Retrieve both string and json of body using koa js - node.js

I use koa js with bodyparser, suppose client send body like this:
{ "first": "1" , "second": "2"}
what I want is the original body as string with no changes (JSON.stringify changes the order of fields and remove spaces then I can't use it). I try to use raw-body that gives me the string of body, so I have to parse it to JSON.
is there any middleware that give me body as both json and original string?

If you want both the raw string and the JSON, get the string, keep a copy, then parse it to JSON.
var getRawBody = require('raw-body')
app.use(function* (next) {
var string = yield getRawBody(this.req, {
length: this.length,
limit: '1mb',
encoding: this.charset
})
var json = JSON.parse(string)
// do something with "string"
// do something with "json"
})
Note: You have to run getRawBody() against this.req, since that's node's raw http request object. this.request is koa-specific and won't work.

Related

Get a `ReadableStream` from Node's `IncomingMessage` type (request)

I am using plain Node (v14 rn) and node-fetch. I need to pass on the incoming body on to a downstream fetch.
The body option on node-fetch's RequestInit accepts:
| "Request body. can be null, a string, a Buffer, a Blob, or a Node.js Readable stream"
To minimize memory consumption I would prefer to hand over the readable stream to fetch vs read the contents of the body into a string first.
How can I generate a ReadableStream from IncomingMessage so I could write code something like this (pseudo-code)
async function(req:IncomingMessage, res:ServerResponse) {
// need the magic inside toReadableStream
const readableStream = toReadableStream(req);
const result = await fetch('http://example.com', {
method: "POST",
body: readableStream,
});
// handle the result and send response to client
}

JSON via NodeJS Express Websocket has lots extra characters

I have a nodeJS server configured with Express and BodyParser
const express = require('express')
const expressWs = require('express-ws')
const bodyParser = require('body-parser')
app.ws('/ws', websocket)
When the websocket gets a message I pass it on
ws.onmessage = e => {
const {action, payload} = JSON.parse(e.data)
channel.send(action,payload)
}
However when it comes to the app via the channel it's got lots of extra characters in it
"{\"action\":\"guide_data_retreived\",\"payload\":[{\"id\":544,\"json\":\"{\\\"code\\\":\\\"lPvwP4rz\\\",\\\"coverDesign\\\":null,\\\"created\\\":1535018423000,\\\"description\\\":\\\"{\\\\\\\"blocks\\\\\\\":[{\\\\\\\"key\\\\\\\":\\\\\\\"dpcth\\\\\\\",\\\\\\\"text\\\\\\\":\\\\\\\"This is an example of a medical emergency. \\\\\\\",\\\\\\\"type\\\\\\\":\\\\\\\"unstyled\\\\\\\",\\\\\\\"depth\\\\\\\":0,\\\\\\\"inlineStyleRanges\\\\\\\":[],\\\\\\\"entityRanges\\\\\\\":[],\\\\\\\"data\\\\\\\":{}},
Which makes it unparseable.
Any idea where this is coming from and how to fix it?
The problem is that you have several levels of string-encoded JSON nested within your objects.
The \'s are escape characters. They are there to indicate that the quote following them is not a terminating quote, but rather is a character in the string. So for instance, let's say I want to have a javascript object which looks like this:
// myFile.javascript
{ "x" : "abc" }
const s = JSON.stringify(foo) // s is a string
Then s will include these escape characters, so that the quotes around "x" and "abc" will be interpreted as inside the string rather than as string terminators:
s == "{\"x\":\"abc\"}" // -> true
So since s is a string, you can also put it inside another object, like this:
const bar = { "nested" : s }
And if you stringify that, you will end up with another level of escapes to signify that s is a string and not a nested JSON object within the object:
JSON.stringify(bar) == "{\"nested\":\"{\\"x\\":\\"abc\\"}\"}
So it's clear that within your application, you're passing around strings instead of objects. For instance, inside your payload, json is a nested string-encoaded JSON, and inside json, description is string-encoaded-JSON.
If you have control over the message being sent on this websocket, then you should parse those strings before you put them in the payload.
So for instance, if you are building the payload like this:
func sendMessage(ws, action, id, json) {
ws.send(action, {id: id, json: json})
}
then you should change it to this:
func sendMessage(ws, action, id, json) {
ws.send(action, {id: id, json: JSON.parse(json)})
}
And so on, for each level of nested object.

How to parse body params on AWS lambda?

On my AWS lambda function i have access to an event json which holds a parameter called: body. the issue is this is a raw body string (not parsed into individual parameters).
{
input: {
body: "------WebKitFormBoundarys3wLu6HlaCBrIExe\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n------WebKitFormBoundarys3wLu6HlaCBrIExe\r\nContent-Disposition: form-data; name=\"media[]\"\r\n\r\nhthtth\r\n------WebKitFormBoundarys3wLu6HlaCBrIExe\r\nContent-Disposition: form-data; name=\"media[]\"\r\n\r\nlololol\r\n------WebKitFormBoundarys3wLu6HlaCBrIExe--\r\n"
}
}
I'd like to take that and turn into:
{
foo: 'bar',
media: [
"grgkoerpkge",
"twepgbopcib"
]
}
I'd prefer not to use some bloated express server just to parse a body string.
P.S. I've tried to use body-parser but it seems like it only works with express as a middleware
const {URLSearchParams} = require('url')
const sp = new URLSearchParams(event.body)
Encountered similar issue recently, as content-type in request was plain text format, I used querystring, built in module in node js to parse body string,
more about querystring
const querystring = require('querystring');
& in lambda handler,
var jsonData = querystring.parse(event.body);
Send it to your lambda as JSON.
Then, in your lambda (if you use lambda-proxy integration), parse it by using JSON.parse(event.body).
You'r passing the params by form or with the "Content-Type" in the header "application/x-www-form-urlencoded".
You shoukd pass it with "application/json"

Breeze Json uriBuilder

I'm trying to use breeze.js with sails.js.
Therefore I'm using the breeze json uriBuilder.
I logged the req.query and got the following:
{ '{"where":{"name":"foo"},"orderBy":': { '"name"': '' } }
To query waterline objects I need to bring it into a format like this:
{ where: { name: 'foo' }, sort: 'name' }
First thing I tried:
var queryString = JSON.parse(Object.keys(req.query)[0]);
That works as long as I only put a where clause in. But with more parameters i get this strangely formatted json object.
How can I parse it to get the correct object?
Solution:
Don't parse he req.query. Parse the url and parse it. This way u will get a json uery that sails accepts. Now strip of unsupported parameters as select and you're done.
var parsedUrl = urlUtils.parse(req.url, true);
var jsonQueryString = Object.keys(parsedUrl.query)[0];
var jsonQuery = JSON.parse(jsonQueryString);
Good question! We haven't yet documented this adequately, but the basic idea is that there is a breeze-client npm package (https://www.npmjs.com/package/breeze-client) that you can use to parse the incoming json query into a breeze EntityQuery instance, from there you can interrogate the EntityQuery and turn it into whatever server side syntax you want, i.e. in your case Sails.)
// req = the HTTP request object.
var resourceName = req.params.slug; // the HTTP endpoint
var entityQuery = breeze.EntityQuery.fromUrl(req.url, resourceName);
// you would write the transform to sails below.
var sailsQuery = tranformToSails(entityQuery);
This is exactly what we do in the breeze-sequelize npm package where we take the incoming req.query and go thru the process above to create a 'Sequelize' query.
See http://www.getbreezenow.com/sequelize-mysqlpostgressql-lite

Node.js: Make a HTTP POST with params

call = "https://aaa#api.twilio.com/2010-04-01/Accounts/sasa/Calls.xml"
fields = { To : "+12321434", From : req.body.from }
request.post
url: call, body: fields (err,response,body) ->
console.log response.body
How can I pass fields to the HTTP POST request?
It works if I pass a string like "To=+12321434" but not "To=+12321434,From = req.body.from"
You need to stringify your data, look at the example:
http://nodejs.org/docs/latest/api/querystring.html#querystring.stringify

Resources