ctx request body is undefined with nodejs - node.js

I have a problem, when I post my form, i can't get what is in my post in my API.
this is my post with axios in react :
onSubmit = () => {
let data = {
nickname: this.state.nickname,
password: this.state.password
}
axios.post("/api/user/login", { data })
.then(res => {
console.log("res from api is => ", res.data);
})
}
and this is in my API :
import koaBody from "koa-body";
const app = new koa();
const router = new Router();
app.use(router.routes());
app.use(koaBody());
router.post("/api/user/login", async(ctx) => {
console.log("body is => ", ctx.request.body);
ctx.body = "ok";
});
the problem is ctx.request.body is always undefined...
Can you tell me why ?
I tried with router.get and I have no problem, it works fine.

You need to load the body parser before the router, otherwise the router will get to handle the requests before the body contents are parsed:
app.use(koaBody());
app.use(router.routes());

Related

data does not arrive properly in req.body (axios post method)

data not arriving in req.body when using axios in post methord, when i testing Api using postman is Working properly,
in console payload also showing,
Pay load :-
Api Call:
axios.post('offices/office',{name,email},config)
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
});
axios instance:
import axios from 'axios'
import { BaseUrl } from './Api';
const instance = axios.create({
baseURL:BaseUrl,
});
export default instance
Server :
code : officeRouter:
const express =require('express')
const { createOffice } = require('../Controller/Office_Controller')
const router=express.Router()
router.post('/office',createOffice)
module.exports=router
controller.js
createOffice:async(req,res) => {
console.log(req.body)
},

How do I debug server-side errors on MERN?

I have this front-end code:
export const CreatePage = () => {
const auth = useContext(AuthContext)
const {request} = useHttp()
const [content, setContent] = useState('')
const [title, setTitle] = useState('')
const [lead, setLead] = useState('')
useEffect(() => {
window.M.updateTextFields()
},[])
const postHandler = async () => {
try {
const data = await request('/api/post/generate', 'POST', {title: title, lead: lead, content: content}, {
Authorization: `Bearer ${auth.token}`
})
console.log(data)
} catch (e) {}
}
And this back-end code:
router.post('/generate', auth, async (req, res) => {
try {
const baseURL = config.get('baseURL')
const {title, lead, content} = req.body
// if (!title || !lead || !content) {
// return res.status(422).json({error: 'Please, input ALL fields'})
// }
const Post = new Post({
title, lead, content, owner: req.body.user.userId // req.user.userId
})
await Post.save()
res.status(201).json({Post})
} catch (e) {
res.status(500).json({message: 'Something went wrong'})
}})
I've tried a lot of things, but I still get this error. I know this is a server-side error, but that's all I have been able to figure out.
P.S. If there are any questions about the code, I will add it later.
UPD: By the way, could it be a problem's reason? Console log:
[1] Proxy error: Could not proxy request /api/post/generate from localhost:3000 to http://localhost:5000.
Probably, it's because of cors, you just can't send request from different url's. Try to install cors and configure it:
const cors = require("cors");
app.use("/", require('./src/routes'));
app.use(cors({
origin: '*'
}))

Ionic/Angular change Data in Node Server

I have create a Node application that uses the Twit(twitter api) to allow my ionic/Angular Application to post a tweet on twitter, however this problem that I have is that i get a 404 error message when I set the REST method to Post, it seems to work with a GET method.
However I do not know how I can dynamically change the Data in my node application from my Ionic Application.
I want to change the User's information and the Message that is being sent, but I do not know where to start. if anyone can guide me that will be appriecated.
this is my Node server.js file
const express = require('express');
const Twitter = require('twit');
const app = express();
const client = new Twitter({
consumer_key: '...',
consumer_secret: '...',
access_token: '...',
access_token_secret: '...',
});
app.use(require('cors')());
app.use(require('body-parser').json());
app.post('/post_tweet', (req, res) => {
tweet = {status:"Random"};
client
.post(`statuses/update`, tweet)
.then(timeline => {
console.log(timeline);
res.send(timeline);
})
.catch(error => {
res.send(error);
});
});
app.listen(3000, () => console.log('Server running'));
this is my twitter service in my Ionic application
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class TwitterserviceService {
api_url = 'http://localhost:3000';
constructor(private http: HttpClient) { }
tweet(tweetdata: string) {
return this.http.get<any>(`${this.api_url}/post_tweet`)
.pipe(map(tweet => {
alert("tweet posted")
return tweet;
}));
}
}
and this is the method that I use to send a Post, however the message "this works" doesent post instead the default message in the Node application is sent "random"
sendTweet() {
this.api.tweet('this works')
.pipe(first())
.subscribe(
data => {
console.log('yes')
},
error => {
'failed'
});
}
Your service should do a POST, not a GET. And a POST must have a body.
tweet(tweetdata: string) {
return this.http.post<any>(`${this.api_url}/post_tweet`, { tweetdata })
}
note that you will have to handle this body in the express route and probably do something with this tweetdata attribute.
Alright I have found the answer and it was actually quite simple
here it the link to the resource that i am using => https://code.tutsplus.com/tutorials/connect-to-the-twitter-api-in-an-angular-6-app--cms-32315
this is my node js code
const express = require('express');
const Twitter = require('twit');
const app = express();
const client = new Twitter({
consumer_key: '...',
consumer_secret: '...',
access_token: '...',
access_token_secret: '...',
});
app.use(require('cors')());
app.use(require('body-parser').json());
app.post('/post_tweet', (req, res) => {
tweet = req.body;
client
.post(`statuses/update`, tweet)
.then(tweeting => {
console.log(tweeting);
res.send(tweeting);
})
.catch(error => {
res.send(error);
});
});
app.listen(3000, () => console.log('Server running'));
and here it the code that I have in my Ionic/Angular Project
api_url = 'http://localhost:3000';
tweet(tweetdata: string) {
return this.http.post<any>(`${this.api_url}/post_tweet/`, {status: tweetdata})
.pipe(map(tweet => {
alert("tweet posted")
return tweet;
}));
}
sendTweet() {
this.tweet('This is app code')
.pipe(first())
.subscribe(
data => {
console.log('yes')
},
error => {
'failed'
});
}
hope this helps someone.

Splitting Goole-Play-Scraper Results

I have a React front-end with a Node back-end, and all I'm trying to do is scrape some data from the Google Play Store using Facundo Olano's Google-Play-Scraper.
This is my React front-end...
import React, {Component} from 'react';
import './App.css';
export default class App extends Component {
state = {
title: '',
review: ''
};
componentDidMount() {
this.callApi()
.then(res => this.setState({
title: res.title,
review: res.review
}))
.catch(err => console.log('Error: ', err));
}
callApi = async () => {
const response = await fetch('/gPlay');
const body = await response.json();
if (response.status !== 200) {
throw Error(body.message);
}
return body;
};
render() {
console.log("==================== app log ====================");
console.log("State: ", this.state);
return (
<div className="App">
<p>Title: {this.state.title}.</p>
<p>Review: {this.state.review}.</p>
</div>
);
}
}
This is my Node back-end...
[const express = require('express');
const app = express();
const port = process.env.PORT||5000;
const gPlay = require('google-play-scraper');
const appToScrape = 'com.mojang.minecraftpe';
app.get('/gPlay', (req, res) => {
const gPlayResults = gPlay.app({appId: appToScrape});
console.log('==================== server log ====================');
gPlayResults.then(console.log);
res.send({
title: 'title',
review: 'review',
});
});
app.listen(port, () => console.log(`Listening on port: ${port}`));
This is a small snippet of the results i'm getting...
{
price: 6.99,
free: false,
currency: 'USD',
priceText: '$6.99',
offersIAP: true,
size: 'Varies with device'
}
I'm getting the full results as per the doc's, but I need to be able to split the returned object up to be able to send bits of it back to the front-end, but I can't for the life of me get it to work.
I thought I could just simply do something like gPlayResults.price and have 6.99 returned, but all that comes back is undefined.
Please can someone help, I must be missing something as it surely can't be that hard!?
Thanks xxx
Ok, I worked it out! :)
For anyone who's interested, gPlayResults is being assigned a Promise and not the object I was expecting.
I made a callback using .then and was able to use the result I needed to send a usable object back to the front end.
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
const googlePlayApp = require('google-play-scraper');
const appToScrape = 'com.mojang.minecraftpe';
app.get('/gPlay', (req, res) => {
console.log('==================== /gPlay ====================');
const gPlayResults = googlePlayApp.app({appId: appToScrape});
gPlayResults.then(function(result) {
res.send({
appObject: result
})
});
});
app.listen(port, () => console.log(`Listening on port: ${port}`));
On to the next problem...

Send response from server side axios request to React/Redux app

I'm a little new to creating a backend in Node/Express, but I am trying use axios to make HTTP requests. I've set up express routes that will make the necessary request and I know from using Postman that GET request I'm testing does return a response. Where I'm stuck is how to return that data and send it to my React/Redux app to use.
-Server Side-
//Express Route
app.get('/api/recipes', recipeController.getRecipes)
//Controller Function that makes axios request
const axios = require('axios')
const Promise = require('bluebird')
module.exports = {
getRecipes(req, res) {
const url = "https://gw.hellofresh.com/api/recipes/search?country=us&limit=9"
const token = "IUzI1NiIsInR5c"
axios
.get(url, {
"headers": {"Authorization": "Bearer " + token}
})
.then((response) => {
console.log(response)
})
.catch((err) => {
console.log(err)
})
}
}
-Client Side-
I dispatch the following action and make a call using the endpoint I created. However, at this point, I'd get an error status even though on the server side I was able to get a response. I tried playing around using Promises as I read that axios GET requests returns promises, but couldn't wrap my head around on how to implement it.
export const getRecipes = () => {
return (dispatch) => {
axios
.get('/api/recipes')
.then((resp) => {
console.log(resp)
})
.catch((err) => {
console.log(err)
})
}
}
You need to call res.send in the route, to send the data to the client:
module.exports = {
getRecipes(req, res) {
const url = "https://gw.hellofresh.com/api/recipes/search?country=us&limit=9"
const token = "IUzI1NiIsInR5c"
axios
.get(url, {
"headers": {"Authorization": "Bearer " + token}
})
.then(response => {
console.log(response)
res.send(response) // <= send data to the client
})
.catch(err => {
console.log(err)
res.send({ err }) // <= send error
})
}
}

Resources