POST call to SailsJS api showing JSON parse error - node.js

I'm trying to put some data in mysql database using sails js API,
Here is my data which I'm sending via ajax call
{"person":{"name":"Sahasrangshu Guha","address":"Dlf It Park Ii Block 1a, Plot No. Ii-F/1, Action A, Ericsson Kolkata","phoneNumber":"9830612244"}}
Here is the ajax call header
{ 'Content-Type': 'application/json', 'responseType': 'json' }
My sails js controller is as follows
module.exports = {
addPerson: function (req, res) {
if (req.method == 'POST' && req.param('person', null) != null) {
console.log(req.param('person'));
Person.create(req.param('person'), (error, person) => {
if(error) {
res.send('Error:Sorry!Something went Wrong');
} else {
res.send('Successfully Created!');
}
});
// Error handling
// if (err) {
// res.send('Error:Sorry!Something went Wrong');
// } else {}
// res.send('Successfully Created!');
// //res.redirect( ‘person/view/’+model.id);
// }
}
else {
res.send('Error:Sorry!Data Wrong');
}
}
}
And my sails js model looks like below
module.exports = {
tableName: 'person',
primaryKey: 'id',
attributes: {
name: {
type: 'string',
required: true
},
address: {
type: 'string',
required: true
},
phoneNumber: {
type: 'string',
required: true
}
}
};
I'm alaways having the following error whenver I'm making a POST request to my sails js API
{error: SyntaxError: Unexpected token E in JSON at position 0 at JSON.parse ()
Any idea to solve this? I have tried sending object rather than JSON data but the same error pursues.

While returning the response I think an Object is being expected instead of String here
res.send(errObj);
where error obj should be something like
{
success: false,
status: 400,
message : 'Error:Sorry!Something went Wrong'
}
Or send the message with status code
res.status(response.status || 500).send(response)

Related

Mongoose Update Doesn't Run Before My Res.Send()

I currently have a controller which is handling the onboarding of a user. When the user completes their onboarding flow, I update their status in Mongo from New to Active, then send them to a new page. As a method of security, I also have a middleware function on every authenticated route which checks if the user is logged in, as well as their status. If their status is New, I send them to the onboarding flow (because theoretically they haven't seen the onboarding flow).
As I run through my experience, when I submit the onboarding flow, I get redirected back to the beginning of the flow. I check Mongo and my status is no longer New, so I was confused why this was happening. Eventually I realized when I am sending the user to a new page, the authentication route is checking the user's status before my findOneAndUpdate() has had a chance to complete. So the user gets redirected back to the onboarding flow because the last query didn't finish in time.
Any idea how to fix this? I assume it has something to do with async/await but I'm not sure. Here's my code below, I'm working in Node.JS with an express framework. Also, in my post onboarding I am using a mapbox api to get the lat/long of their zip code, which is why I have the request.get() in the code.
Onboarding Controller
exports.postOnboarding = (req, res, next) => {
var data = req.params.data;
var final = data.split(',');
location = final[4].toString();
url = "https://api.mapbox.com/geocoding/v5/mapbox.places/" + location + ".json";
request.get(url)
.query({access_token: "private_key"})
.end(function(err, result) {
User.findOneAndUpdate(
{"credentials.userId": req.session.user.credentials.userId },
{ practiceSettings: {
businessType: final[2],
experienceType: final[0],
fullFee: final[3]
},
credentials: {
userType: "Active",
active: true,
userId: req.session.user.credentials.userId,
provider: "local"
},
paySettings: {
q1: "undeternmined"
},
license: final[1],
zip: final[4],
latLong: result.body.features[0].center
}, (err, result) => {
if (err) {
console.log(err);
} else {
console.log("settings updated");
res.redirect('/dashboard');
}
}
)
}) };
Dashboard Route
router.get('/dashboard', isAuth, adminController.getDashboard);
isAuth Middleware
const User = require('../models/user');
module.exports = (req, res, next) => {
if (!req.session.isLoggedIn) {
return res.redirect('/login');
} else if (req.session.user.credentials.userType == 'Unverified') {
return res.redirect('/login?verified=false');
} else if (req.url == '/onboarding') {
return next();
}
User.findOne({"credentials.userId" : req.session.user.credentials.userId})
.then(result => {
res.locals.user = result;
if (req.session.sidebarStatus == 'closed') {
res.locals.sidebarStatus = 'closed';
}
if (result.credentials.userType == 'New') {
return res.redirect('/onboarding');
}
next();
})
}
And for reference, below is a snippet of my onboarding.ejs file which calls the post route. This isn't the whole thing, I have a lot of nested Sweet Alert modals, but this is the important part.
Swal.fire({
text: "Question",
width: "90%",
input: "text",
inputPlaceholder: "92805",
inputValidator: (value) => {
if (!value) {
return 'You must fill in this field.'
}
if (value.length != 5) {
return 'Please use a 5 digit zip-code as your answer.'
}
},
showCancelButton: false,
confirmButtonText: 'Submit',
backdrop: '#FFFFFF',
allowOutsideClick: false
})
.then((result5) => {
res3 = result3.value.replace(",", "");
final = [result1.value, result2.value, res3, result4.value, result5.value];
$.ajax({
url: "/post-onboarding/" + final,
dataType: 'json',
type: 'post',
success: function (data) {
if ( data.length ) {
Swal.fire({
title: 'Error!',
text: 'Something bad happened',
icon: 'error',
confirmButtonText: 'OK'
});
} else {
//redirect user
}
}
});

MEAN stack how to find _id from database to send a PUT request

I'm having a problem identifying a 'task' in mongoDB from my frontend angular.
This question is the most similar to my question but here it just says req.body.id and doesn't really explain how they got that.
This question involves what I am trying to do: update one document in a collection upon a click. What it does in the frontend isn't important. I just want to change the status text of the Task from "Active" to "Completed" onclick.
First I create a task and stick it in my database collection with this code:
createTask(): void {
const status = "Active";
const taskTree: Task = {
_id: this._id,
author: this.username,
createdBy: this.department,
intendedFor: this.taskFormGroup.value.taskDepartment,
taskName: this.taskFormGroup.value.taskName,
taskDescription: this.taskFormGroup.value.taskDescription,
expectedDuration: this.taskFormGroup.value.expectedDuration,
status: status
};
this.http.post("/api/tasks", taskTree).subscribe(res => {
this.taskData = res;
});
}
When I make this post to the backend, _id is magically filled in!
I'm just not sure how I can pass the id to the put request in nodejs router.put('/:id') when I'm pushing it from the frontend like this:
completeTask(): void {
const status = "Completed";
const taskTree: Task = {
_id: this._id,
author: this.username,
createdBy: this.department,
intendedFor: this.taskFormGroup.value.taskDepartment,
taskName: this.taskFormGroup.value.taskName,
taskDescription: this.taskFormGroup.value.taskDescription,
expectedDuration: this.taskFormGroup.value.expectedDuration,
status: status
};
console.log(taskTree);
this.http.put("/api/tasks/" + taskTree._id, taskTree).subscribe(res => {
this.taskData = res;
console.log(res);
});
}
In the template I have a form that's filled in and the data is immediately outputted to a task 'card' on the same page.
When I send the put request from angular, I get a response in the backend just fine of the response I ask for in task-routes.js:
router.put("/:id", (req, res, next) => {
const taskData = req.body;
console.log(taskData);
const task = new Task({
taskId: taskData._id,
author: taskData.author,
createdBy: taskData.createdBy,
intendedFor: taskData.intendedFor,
taskName: taskData.taskName,
taskDescription: taskData.taskDescription,
expectedDuration: taskData.expectedDuration,
status: taskData.status
})
Task.updateOne(req.params.id, {
$set: task.status
},
{
new: true
},
function(err, updatedTask) {
if (err) throw err;
console.log(updatedTask);
}
)
});
The general response I get for the updated info is:
{
author: 'there's a name here',
createdBy: 'management',
intendedFor: null,
taskName: null,
taskDescription: null,
expectedDuration: null,
status: 'Completed'
}
Now I know _id is created automatically in the database so here when I click create task & it outputs to the 'card', in the console log of task after I save() it on the post request, taskId: undefined comes up. This is all fine and dandy but I have to send a unique identifier from the frontend Task interface so when I send the 'put' request, nodejs gets the same id as was 'post'ed.
I'm quite confused at this point.
So I finally figured this out...In case it helps someone here's what finally worked:
First I moved my update function and (patch instead of put) request to my trigger service:
Trigger Service
tasks: Task[] = [];
updateTask(taskId, data): Observable<Task> {
return this.http.patch<Task>(this.host + "tasks/" + taskId, data);
}
I also created a get request in the trigger service file to find all the documents in a collection:
getTasks() {
return this.http.get<Task[]>(this.host + "tasks");
}
Angular component
Get tasks in ngOnInit to list them when the component loads:
ngOnInit() {
this.triggerService.getTasks().subscribe(
tasks => {
this.tasks = tasks as Task[];
console.log(this.tasks);
},
error => console.error(error)
);
}
Update:
completeTask(taskId, data): any {
this.triggerService.updateTask(taskId, data).subscribe(res => {
console.log(res);
});
}
Angular template (html)
<button mat-button
class="btn btn-lemon"
(click)="completeTask(task._id)"
>Complete Task</button>
// task._id comes from `*ngFor="task of tasks"`, "tasks" being the name of the array
//(or interface array) in your component file. "task" is any name you give it,
//but I think the singular form of your array is the normal practice.
Backend Routes
GET all tasks:
router.get("", (req, res, next) => {
Task.find({})
.then(tasks => {
if (tasks) {
res.status(200).json(tasks);
} else {
res.status(400).json({ message: "all tasks not found" });
}
})
.catch(error => {
response.status(500).json({
message: "Fetching tasks failed",
error: error
});
});
});
Update 1 field in specified document (status from "Active" to "Completed"):
router.patch("/:id", (req, res, next) => {
const status = "Completed";
console.log(req.params.id + " IT'S THE ID ");
Task.updateOne(
{ _id: req.params.id },
{ $set: { status: status } },
{ upsert: true }
)
.then(result => {
if (result.n > 0) {
res.status(200).json({
message: "Update successful!"
});
}
})
.catch(error => {
res.status(500).json({
message: "Failed updating the status.",
error: error
});
});
});
Hope it helps someone!

Catch the Error message text in a rxjs subscribe method in Angular

I have a nodeJS express server application in TypeScript. When an error occurs I want to add some text to it and read it in the client Angular application.
NodeJS Server, express code:
import {
Request,
Response
} from 'express';
if (medewerker) {
verifyPassword(medewerker.id, req.body.wachtwoord).then(isVerifiedPassword => {
if (isVerifiedPassword) {
.......
} else {
throw new Error('Wachtwoord niet juist ingevoerd');
}
}).catch(error => {
console.log(error);
res.status(401).json('I want to show this text: ' + error);
})
}
Client code:
this.httpClient.put(this.url + 'medewerker/login', {
'email': authData.userId,
'wachtwoord': authData.password
}, {
headers: this.headertjes,
withCredentials: true,
observe: 'response',
responseType: 'json'
})
.subscribe((data1: HttpResponse < MedewerkerTypeId > ) => {
if (data1 != null) {
.....
}
}, ((error: HttpErrorResponse) => {
console.log(error.statusText) //here I want to grep and show my text.
}));
But I get an error: undefined message.
I tried all the options but only default properties like error.status and error.message works. But no Custom messages like I want.
Maybe somebody can help me ?
The body of the ErrorResponse can be accessed using the error property.
Change your code like this:
this.httpClient.put(this.url + 'medewerker/login', {
'email': authData.userId,
'wachtwoord': authData.password
}, {
headers: this.headertjes,
withCredentials: true,
observe: 'response',
responseType: 'json'
})
.subscribe((data1: HttpResponse < MedewerkerTypeId > ) => {
if (data1 != null) {
.....
}
}, ((error: HttpErrorResponse) => {
console.log(error.error) //here error contains the text
}));

PUT request from React to mongodb with Axios

I need some little help. PUT request doesn't work when I send it from React app using Axios. But when I test PUT api from Postman - it works as it suppose to. Server side - node+mongoose+mongodb.
modifyCurrentHaspInfo = (e) => {
if (prompt("Enter password:") === "123456") {
axios.put("/hasp/change", {
data: {
_id: "5cd40f6f1e922c236caa82f4",
serial: "11111-22222",
soft: "test-put"
}
})
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
})
} else {
alert("Wrong password!");
}
}
When it finds correct id - data in body must be changed. Here is code from server:
//PUT request
app.put("/hasp/change", function(req, res) {
//console.log(req.body);
HaspInfo.findOneAndUpdate({_id: req.body._id}, {$set:req.body}, {new: true}, function(err, hasps) {
if (err) {
res.status(500).send({error: "Could not modify hasp info..."});
} else {
//console.log(hasps);
res.status(200).send(hasps);
}
});
});
It's because your axios is malformed (not what you're expecting at the backend).
The way you're sending data now from axios can be accessed at the backend as
req.body.data
// which will be an object like
{
_id: "5cd40f6f1e922c236caa82f4",
serial: "11111-22222",
soft: "test-put"
}
So _id can be accessed like req.body.data._id. Change your request to one of the following (note the differences)
axios.put("/hasp/change", {
_id: "5cd40f6f1e922c236caa82f4",
serial: "11111-22222",
soft: "test-put"
})
Or
axios.put({
url: "/hasp/change",
data: {
_id: "5cd40f6f1e922c236caa82f4",
serial: "11111-22222",
soft: "test-put"
}
})

GraphQL with RESTful returning empty response

I am connecting GraphQL with REST endpoints, I confirmed that whenever I am calling http://localhost:3001/graphql it is hitting REST endpoint and it is returning JSON response to GraphQL server, but I am getting an empty response from GraphQL server to GUI as follows:
{
"data": {
"merchant": {
"id": null
}
}
}
Query (decoded manually):
http://localhost:3001/graphql?query={
merchant(id: 1) {
id
}
}
Below is how my GraphQLObjectType looks like:
const MerchantType = new GraphQLObjectType({
name: 'Merchant',
description: 'Merchant details',
fields : () => ({
id : {
type: GraphQLString // ,
// resolve: merchant => merchant.id
},
email: {type: GraphQLString}, // same name as field in REST response, so resolver is not requested
mobile: {type: GraphQLString}
})
});
const QueryType = new GraphQLObjectType({
name: 'Query',
description: 'The root of all... queries',
fields: () => ({
merchant: {
type: merchant.MerchantType,
args: {
id: {type: new GraphQLNonNull(GraphQLID)},
},
resolve: (root, args) => rest.fetchResponseByURL(`merchant/${args.id}/`)
},
}),
});
Response from REST endpoint (I also tried with single object in JSON instead of JSON array):
[
{
"merchant": {
"id": "1",
"email": "a#b.com",
"mobile": "1234567890"
}
}
]
REST call using node-fetch
function fetchResponseByURL(relativeURL) {
return fetch(`${config.BASE_URL}${relativeURL}`, {
method: 'GET',
headers: {
Accept: 'application/json',
}
})
.then(response => {
if (response.ok) {
return response.json();
}
})
.catch(error => { console.log('request failed', error); });
}
const rest = {
fetchResponseByURL
}
export default rest
GitHub: https://github.com/vishrantgupta/graphql
JSON endpoint (dummy): https://api.myjson.com/bins/8lwqk
Edit: Adding node.js tag, may be issue with promise object.
Your fetchResponseByURL function get empty string.
I think the main problem is that you are using wrong function to get the your JSON string, please try to install request-promise and use it to get your JSON string.
https://github.com/request/request-promise#readme
something like
var rp = require('request-promise');
function fetchResponseByURL(relativeURL) {
return rp('https://api.myjson.com/bins/8lwqk')
.then((html) => {
const data = JSON.parse(html)
return data.merchant
})
.catch((err) => console.error(err));
// .catch(error => { console.log('request failed', error); });
}
In this case using data.merchant solved my problem. But the above suggested solution i.e., use of JSON.parse(...) might not be the best practice because if there are no object in JSON, then expected response might be as follows:
{
"data": {
"merchant": null
}
}
Instead of fields to be null.
{
"data": {
"merchant": {
"id": null // even though merchant is null in JSON,
// I am getting a merchant object in response from GraphQL
}
}
}
I have updated my GitHub: https://github.com/vishrantgupta/graphql with working code.

Resources