Forma correcta de devolver JSON usando el nodo o Express

440

Entonces, uno puede intentar obtener el siguiente objeto JSON:

$ curl -i -X GET http://echo.jsontest.com/key/value/anotherKey/anotherValue
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=ISO-8859-1
Date: Wed, 30 Oct 2013 22:19:10 GMT
Server: Google Frontend
Cache-Control: private
Alternate-Protocol: 80:quic,80:quic
Transfer-Encoding: chunked

{
   "anotherKey": "anotherValue",
   "key": "value"
}
$

¿Hay alguna manera de producir exactamente el mismo cuerpo en una respuesta de un servidor usando node o express? Claramente, uno puede configurar los encabezados e indicar que el tipo de contenido de la respuesta será "application / json", pero luego hay diferentes formas de escribir / enviar el objeto. El que he visto que se usa comúnmente es mediante el uso de un comando de la forma:

response.write(JSON.stringify(anObject));

Sin embargo, esto tiene dos puntos donde uno podría argumentar como si fueran "problemas":

  • Estamos enviando una cadena.
  • Además, al final no hay un nuevo carácter de línea.

Otra idea es usar el comando:

response.send(anObject);

Esto parece estar enviando un objeto JSON basado en la salida de curl similar al primer ejemplo anterior. Sin embargo, no hay un nuevo carácter de línea en el extremo del cuerpo cuando el rizo se usa nuevamente en un terminal. Entonces, ¿cómo se puede escribir algo como esto con un nuevo carácter de línea agregado al final usando node o node / express?

MightyMouse
fuente

Respuestas:

620

Esa respuesta también es una cadena, si desea enviar la respuesta embellecida, por alguna razón incómoda, podría usar algo como JSON.stringify(anObject, null, 3)

Es importante que establezca el Content-Typeencabezado application/jsontambién.

var http = require('http');

var app = http.createServer(function(req,res){
    res.setHeader('Content-Type', 'application/json');
    res.end(JSON.stringify({ a: 1 }));
});
app.listen(3000);

// > {"a":1}

Prettified:

var http = require('http');

var app = http.createServer(function(req,res){
    res.setHeader('Content-Type', 'application/json');
    res.end(JSON.stringify({ a: 1 }, null, 3));
});
app.listen(3000);

// >  {
// >     "a": 1
// >  }

No estoy exactamente seguro de por qué desea terminarlo con una nueva línea, pero podría hacerlo JSON.stringify(...) + '\n'para lograrlo.

Rápido

En express puede hacer esto cambiando las opciones en su lugar .

'json replacer' Devolución de llamada JSON reemplazado, nulo por defecto

'json spaces' Espacios de respuesta JSON para formateo, el valor predeterminado es 2 en desarrollo, 0 en producción

En realidad no se recomienda establecer en 40

app.set('json spaces', 40);

Entonces podrías responder con un poco de json.

res.json({ a: 1 });

Utilizará la 'json spaces'configuración para embellecerlo.

bevacqua
fuente
3
Gracias por tu tiempo. Para ser honesto contigo, no tengo ningún problema de mi parte. Es solo que alguien (en una zona horaria diferente) se quejó del formato que estaba usando porque quería hacer un get y por alguna razón no pudo leer mi objeto correctamente. Gracias por señalar la buena versión de stringify. :)
MightyMouse
2
Este alguien realmente debería analizar la cadena JSON en objetos, o usar una extensión del navegador , en lugar de intentar leer a mano.
bevacqua
2
@akshay Aún mejor, res.sendconfigurará automáticamente content-typea JSON, si el elemento enviado es un objeto o matriz.
royhowie
3
Creo que querías usar res.end()en tu httpejemplo (no expreso)
Tobias Fünke, el
2
@ TobiasFünke tiene razón, creo. res.send()no está trabajando. Por favor corríjalo, si es un error. res.end()Funciona correctamente Gracias por cierto.
Kaushal28
410

Desde Express.js 3x, el objeto de respuesta tiene un método json () que establece todos los encabezados correctamente y devuelve la respuesta en formato JSON.

Ejemplo:

res.json({"foo": "bar"});
JamieL
fuente
Gracias por tu tiempo. Sin embargo, mi pregunta no era realmente sobre los encabezados en aquel entonces. Se trataba más del resultado que uno podía ver decir a través del rizo. Gracias de nuevo de todos modos.
MightyMouse
53
OK, pero este método también devuelve JSON formateado correctamente. Es parte de la respuesta. Entonces res.json () establece los encabezados correctos y luego JSON.stringify () es la respuesta para usted automáticamente.
JamieL
19

Si está intentando enviar un archivo json, puede usar transmisiones

var usersFilePath = path.join(__dirname, 'users.min.json');

apiRouter.get('/users', function(req, res){
    var readable = fs.createReadStream(usersFilePath);
    readable.pipe(res);
});
Connor Leech
fuente
10
¿Qué es fs, qué es pipe, qué es legible? Su respuesta es más un misterio
Aakash Dave
11

La res.json()función debería ser suficiente para la mayoría de los casos.

app.get('/', (req, res) => res.json({ answer: 42 }));

La res.json()función convierte el parámetro que pasa a JSON usando JSON.stringify()y establece el Content-Typeencabezado para application/json; charset=utf-8que los clientes HTTP sepan analizar automáticamente la respuesta.

vkarpov15
fuente
6

si usa Express, puede usar esto:

res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({key:"value"}));

o solo esto

res.json({key:"value"});
IXOVER
fuente
5

Puede prettificarlo usando pipe y uno de los muchos procesadores. Su aplicación siempre debe responder con la menor carga posible.

$ curl -i -X GET http://echo.jsontest.com/key/value/anotherKey/anotherValue | underscore print

https://github.com/ddopson/underscore-cli

pawelzny
fuente
4

Puede hacer una ayuda para eso: haga una función de ayuda para que pueda usarla en todas partes en su aplicación

function getStandardResponse(status,message,data){
    return {
        status: status,
        message : message,
        data : data
     }
}

Aquí está mi ruta de temas donde estoy tratando de obtener todos los temas

router.get('/', async (req, res) => {
    const topics = await Topic.find().sort('name');
    return res.json(getStandardResponse(true, "", topics));
});

Respuesta que obtenemos

{
"status": true,
"message": "",
"data": [
    {
        "description": "sqswqswqs",
        "timestamp": "2019-11-29T12:46:21.633Z",
        "_id": "5de1131d8f7be5395080f7b9",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575031579309.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    },
    {
        "description": "sqswqswqs",
        "timestamp": "2019-11-29T12:50:35.627Z",
        "_id": "5de1141bc902041b58377218",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575031835605.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    },
    {
        "description": " ",
        "timestamp": "2019-11-30T06:51:18.936Z",
        "_id": "5de211665c3f2c26c00fe64f",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575096678917.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    },
    {
        "description": "null",
        "timestamp": "2019-11-30T06:51:41.060Z",
        "_id": "5de2117d5c3f2c26c00fe650",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575096701051.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    },
    {
        "description": "swqdwqd wwwwdwq",
        "timestamp": "2019-11-30T07:05:22.398Z",
        "_id": "5de214b2964be62d78358f87",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575097522372.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    },
    {
        "description": "swqdwqd wwwwdwq",
        "timestamp": "2019-11-30T07:36:48.894Z",
        "_id": "5de21c1006f2b81790276f6a",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575099408870.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    }
      ]
}
Nishant
fuente
3

Puede usar un middleware para establecer el Tipo de contenido predeterminado y establecer el Tipo de contenido de manera diferente para API particulares. Aquí hay un ejemplo:

const express = require('express');
const app = express();

const port = process.env.PORT || 3000;

const server = app.listen(port);

server.timeout = 1000 * 60 * 10; // 10 minutes

// Use middleware to set the default Content-Type
app.use(function (req, res, next) {
    res.header('Content-Type', 'application/json');
    next();
});

app.get('/api/endpoint1', (req, res) => {
    res.send(JSON.stringify({value: 1}));
})

app.get('/api/endpoint2', (req, res) => {
    // Set Content-Type differently for this particular API
    res.set({'Content-Type': 'application/xml'});
    res.send(`<note>
        <to>Tove</to>
        <from>Jani</from>
        <heading>Reminder</heading>
        <body>Don't forget me this weekend!</body>
        </note>`);
})
Yuci
fuente
2

Para el encabezado de la mitad de la pregunta, voy a dar un saludo res.typeaquí:

res.type('json')

es equivalente a

res.setHeader('Content-Type', 'application/json')

Fuente: documentos express :

Establece el encabezado HTTP Content-Type en el tipo MIME según lo determinado por mime.lookup () para el tipo especificado. Si el tipo contiene el carácter "/", establece el Tipo de contenido para escribir.

MalcolmOcean
fuente
1

Versión anterior del uso Express app.use(express.json())o bodyParser.json() lea más sobre el middleware bodyParser

En la última versión de express podríamos simplemente usar res.json()

const express = require('express'),
    port = process.env.port || 3000,
    app = express()

app.get('/', (req, res) => res.json({key: "value"}))

app.listen(port, () => console.log(`Server start at ${port}`))
Aung Zan Baw
fuente
Querida, estás confundiendo la respuesta con la solicitud. El middleware BodyParser es para analizar la solicitud de modo que req.bodysea ​​el objeto enviado como cuerpo de la solicitud.
Matthias Hryniszak