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?

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.


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"});

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);
});

10
¿Qué es fs, qué es pipe, qué es legible? Su respuesta es más un misterio
Aakash Dave


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"});

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


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
    }
      ]
}

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>`);
})

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.


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}`))

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.