ExpressJS - What happens when .json() is used in with a response? - json

I was making a server using ExpressJS and this thing is really bugging me. What is the use of using .json() instead of .send() with my responses. According to Express, .send() automatically coverts the JavaScript objects into JSON strings and we do not need to use stringify.Then why use .json() with my responses.
app.get('/profile/:id', (req, res) => {
const {id} = req.params;
let found = false;
database.users.forEach(user => {
if(user.id === id) {
found = true;
return res.json(user);
}
})
if (found === false)
{
res.status(400).json('not found');
}
})
Here is the code where res.json() apppears.

well in the end res.json calls res.send, and they both are identical when you pass an object or array.
But res.json method also uses json replacer and json spaces settings. They give you more flexibility and options to format your json file.
also res.json makes sure the response is in utf8 charset.
To better understand the differences I recommend you to check :
Difference between res.send and res.json in Express.js

Related

Angular: Observable with subscribe returns error 200 OK as the response is not JSON

I am developing a front-end web application using Angular 11. This application uses several services which return data in JSON format.
I use the async / await javascript constructs and the Observables to get the answers from these services. This is an example my call:
let myResponse = await this.myService(this.myData);
myResponse.subscribe(
res => {
console.log("Res: ",res)
}, (error) => {
console.log("Error: ",error)
}
);
where this.myService contains the code doing the HTTP call using Angular httpClient.
Unfortunately a specific service (only one!) doesn't return data in JSON format but it returns a byte array (string that identifies a pdf -format application/pdf-).
Unfortunately this invocation causes a very strange error with code 200 OK:
How can I do to prevent res from being interpreted as JSON and therefore this error being reported? How can I read resreporting that it will not be in json format?
This service has no errors (with Postman it works perfectly). The problem is Javascript and Observable which are interpreted as JSON. How can I read the content of res in this case?
If a HTTP API call is not returning a JSON, just provide the proper value in the responseType option:
this.httpClient.get('<URL>', {
responseType: 'arraybuffer'
});
Ref: https://angular.io/api/common/http/HttpClient#description

Make a NestJS route send in response a pretty formatted JSON

I have a NestJS route which sends back in response, a JSON not well formatted (like minified),
I want to make this JSON easier to read, like a JSON prettier or JSON formatted,
Do someone knows how to do it in NestJS ? I accept answers for other NodeJS frameworks like Express, maybe it will work in NestJS too...
Prettifying the JSON response should be the responsibility of the client, not the server. Otherwise you could be sending a lot of white space which will bloat the response size and could lead to a crash due to having a response too large. If you are using something like Postman, it should be easy to prettify it, I think Postman might do it by default. If you are looking at the response in some web browser, you could use JSON.parse() on the response and it should make the response an actual JSON which console.log() would then print in a pretty way.
You should try https://www.postman.com or https://insomnia.rest/. It can save you a lot of time when it comes to testing an API.
While you shouldn't do it in prod as mentioned above, there's number of cases where it makes a lot of sense (e.g. in dev env). You can achieve this in a bit hacky way:
Access express instance inside nest through breaking abstraction. It's not exposed on INest interface, so you'll need to cast it to any type to bypass Typescript check
Set undocumented express property "json spaces", which will set formatting for all JSON responses over the app
const app = await NestFactory.create(AppModule);
if (process.env.NODE_ENV === 'development') {
(app as any).httpAdapter.instance.set('json spaces', 2);
}
await app.listen(3000);
It works for me:
// src/main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
if (process.env.NODE_ENV !== 'production') {
app.getHttpAdapter().getInstance().set('json spaces', 2);
}
await app.listen(process.env.PORT);
}
Define return type string on your controller
Set the Content-Type: application/json response header
Use JSON.stringify to format your object with whitespace
Example controller code:
import { Controller, Get, Header } from '#nestjs/common';
#Controller('diagnostics')
export class DiagnosticsController {
#Get()
#Header('Content-Type', 'application/json')
findAll(): string {
const statusCode = 200;
const statusText = 'OK';
const info = {
self: 'NestJS Diagnostics Report',
status: {
statusCode,
statusText,
},
};
return JSON.stringify(info, null, 2);
}
}

React.js: setState method setting variable to a string instead of object... is there a workaround?

I am trying to fetch a simple JSON element from express.js. I am trying have React assign it to a state variable on the front end. I am using this code to do so:
componentDidMount() {
fetch("/user")
.then(response => response.json())
.then(result => this.setState({myUser:result}))
}
But when I run typeof myUser after this setState command, it says string instead of object. I've tried using JSON.parse(), etc. But either I get an error or it continues to assign the data as a string rather than JSON. What sort of syntax do I need to use in this fetch-then context to coerce the data assignment to be JSON?
I have read this link:
With this code:
componentDidMount(){
fetch('https://abx.com/data/tool.json').then(response =>{
if (!response.ok) throw Error('Response not ok')
return response.json(); // This is built in JSON.parse wrapped as a Promise
}).then(json => {
this.setState({"sections" : json});
}).catch(err =>{
console.log(err);
});
}
But it doesn't solve the problem. I ran this code directly in my application verbatim. When I run typeof on the variable, it says string instead of object. I looked at other posts on Stack Overflow, but I did not see a solution to this.
I figured out what was going wrong (after many hours of experimenting):
On the server side, I was creating a "homegrown" JSON object using string and variable concatenation. I also tried creating the JSON object by doing this:
var str = "name:" + name + ", department:" + department
var user = {str};
Both of these were not working in subtle ways... despite trying different types of gadgetry on the client side, I couldn't get React to interpret the data as a JSON object. But then I had an idea to construct the JSON on the server side (in Express.js) like this:
var user = {};
user["name"] = name;
user["department"] = department;
That immediately cleared things up on the server side and the client side. When using setState() in React, it now sets the value as an object (which was the goal all along).
I think this can be useful to others... if React doesn't seem to understand the JSON, perhaps it is being sent from the server in a subtly incorrect format.

Unable to access data inside a string (i.e. [ object Object ]) that was originally sent as a JSON object

I'm using axios to send a JSON object as a parameter to my api. Before it post request is fired, my data starts of as a JSON object. On the server side, when I console.log(req.params) the data is returned as such
[object Object]
When I used typeof, it returned a string. So then I went to use JSON.parse(). However, when I used that, it returned an error as such
SyntaxError: Unexpected token o in JSON at position 1
I looked for solutions, but nothing I tried seemed to work. Now I'm thinking I'm sending the data to the server incorrectly.
Here's my post request using axios:
createMedia: async function(mediaData) {
console.log("SAVING MEDIA OBJECT");
console.log(typeof mediaData)
let json = await axios.post(`http://localhost:3001/api/media/new/${mediaData}`)
return json;
}
Any thoughts on how I can solve this?
You need to update your code using axios to provide the mediaData in the body of the request instead of the URL:
createMedia: async function(mediaData) {
console.log("SAVING MEDIA OBJECT");
console.log(typeof mediaData)
let json = await axios.post(`http://localhost:3001/api/media/new/`, mediaData)
return json;
}
In the backend (assuming you're using express here), you need to configure your application to use bodyParser:
var express = require('express')
, app = express.createServer();
app.use(express.bodyParser());
And then in your controller update your console.log(req.params) to console.log(req.body); then restart your node server

Customize Loopback response after save

I have a loopback 2.x app, in which I have a model Conversation and a model Message, with a relationship "Conversation has many messages". I want to customize the response for POST conversations/:id/messages with a json response different than the default, say {status: 'success'}. I tried to use remote hook for the method __create__messages, but it did not work:
Conversation.afterRemote('__create__messages', function(ctx, next) {
ctx.result.data = {
success: 'yes'
};
next();
});
This still returns the default response. How can I return a custom json for a remote method? I have seen examples only for all models, or for all methods: multiple models, multiple methods
Maybe you can try a version of following code below. Also, I think you are meaning to to manipulate data before the method finishes, not after. If you wait, the response will already be created, preventing your intended goal. Let me know if this works (replace with methods that will work for your use case).
Conversation.observe('before save', function(context, next) {
var instance = context.instance || context.data;
if (!instance) return next();
// Your code here
next();
});