aws cloudwatch logs request.body as "[object Object]" - javascript

I am trying to log the body of an api request on Webiny api (they use fastify) but so far cloudwatch is outputting only "[object Object]".
I've tried:
console.log(request.body);
console.log(JSON.stringify(request.body));
console.log(JSON.stringify(request.body, null, 2));
Could this be how I am making the request?
function logData(payload: any) {
return navigator.sendBeacon('https://example.com/test', payload);
}

sendBeacon converts the payload to string.
An ArrayBuffer, a TypedArray, a DataView, a Blob, a string literal or object, a FormData or a URLSearchParams object containing the data to send.
navigator.sendBeacon('https://example.com/test', payload)
Just need to convert the payload to a string before sending it.
JSON.stringify(payload)

Related

axios converts x-www-form-urlencoded to multipart/form-data

I am sending a post request with axios. However, when I check the browser console, I see that the request header is actually content-type: multipart/form-data. How can I enforce application/x-www-form-urlencoded? Or does it even matter?
let data = new FormData();
data.append('grant_type', 'authorization_code');
// ... removed for conciseness
return axios.post(`${AUTH_URL}/token`,
data,
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
FormData objects always serialise to multipart/form-data. They have to because they support file uploading and application/x-www-form-urlencoded and application/json do not.
If you want to send application/x-www-form-urlencoded data you should pass a URLSearchParams object instead.
This is described in the axios documentation.
In either case, you shouldn't specify the Content-Type in the headers since the underlying browser APIs will infer it correctly from the object type passed as the body data.

Is there a way to tell if a POST (body) request is formatted as a URL encoded query string or JSON data?

I am writing the server side code to handle incoming post requests (using NodeJS and Express).
If the request coming into the server is formatted as JSON data, then I want to use JSON.parse, but if the data coming in is formatted as a URL encoded query string, then using JSON.parse on that data gives me the error below. Any suggestions? Code at the bottom.
app.post("/", (req, res) => {
let parsedData;
// if request.body is received as JSON data, I want to put it inside the loop below and parse it and then set parsedData equal to that parsed data.
// if the request.body is received as url encoded data, I just want to set parsedData = req.body
for (var key in req.body) {
parsedData = JSON.parse(key);
}
})
Actually I was able to figure it out! Basically I created a separate function to see if I could JSON PARSE the req.body
function isJSONObject(value) {
try {
JSON.parse(value)
} catch {
return false;
}
return true;
}

Sending JSON from backend to frontend

I need some clarification on JSON objects. Inside my node backend, I receive a JSON object and after I'm done going through which key/value pairs I need, I send it off to the frontend. This is where I'm getting confused- I still need to turn that response object into json via response.json(). Why? If the backend is passing JSON, then why would I need to turn the response obj into JSON?
// test.js (node)
const testObj = {
"test1": {
"1": "Hello there"
}
}
app.get('some-route', async(req,res) =>{
res.send(testObj)
}
// front.js (React)
async someFunc(){
const response = await fetch('/some-route');
const data = await response.json(); //why?
}
Because on your front-end, the fetch API receives a buffer -- an array of bytes, which could contain any payload. It could be an image, plain text, a file, or a JSON payload.
Knowing what your back-end is going to send down, you need to receive the buffer of the data and then perform the .json() API on it, essentially asking that the buffer be interpreted as a serialized string representing a JSON object, and then having the Javascript engine evaluate (deserialize) that string into an object.
Fetch is a multi-purpose API that doesn't have any prior knowledge about the payload that the server is going to send. You are instructing it to treat the payload as JSON by using the .json() function.
Besides .json(), there are other helper methods to read and parse a variety of other possible response types; for example, .text() for plain text, .formData() for form encoded data (similar to querystring values), .blob(), and .arrayBuffer() for byte-level access to the returned data. You will use the appropriate method based on the response type that you're expecting from the API.
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
The response object isn't whatever you sent from the backend, it will be a Response object. That's how the Fetch API works. That Response object will have lots of metadata on it, and some methods, including .json which Takes a Response stream and reads it to completion. It returns a promise that resolves with the result of parsing the body text as JSON.
If you don't want to have to go through these two steps, just write this function.
const fetchJson = async url => {
const response = await fetch(url)
return response.json()
}
and use it like this:
async someFunc(){
const data = await fetchJson('/some-route')
}
A response object is more than just its JSON part. It contains all HTTP protocol elements, like headers, the state of the response and so on.
When you use res.json() you are telling your code to separate only the JSON part from all these other things.
To understand a bit more about an HTTP response, I suggest you to read this.
Good question!
When you send data to the front-end from the back-end, you're not just sending the data payload you created in your testObj. What's actually being returned is a response object, which will look something like:
{
type: "cors",
url: "http://some-url.com/some-api",
redirected: false,
status: 200,
ok: true,
body: ReadableStream,
...
headers: Headers,
json: json(),
...
}
where the value of response.json is the body deserializer method in the response object. You can see for yourself; try to console.log(data) from your example after removing the .json() bit, and you'll get a look at the response object in its entirety.
As you can see, the response's body - or the payload you sent from the server - is received by the client as a ReadableStream object, which then needs to be deserialized once the entire object has reached the client. The response.json() method simply deserializes the response.body ReadableStream object from serialized byte data into JSON, which you can then parse in your application.

get form data from '[object Object]'

I am passing uploaded file and dataObject in FormData:
let data = new FormData();
data.append("file", this.state.files);
data.append("data", formData);
formData is just a Json Object eg: formData = { "a":123 }
Passing data to the node server using put request with axios ,I am able to get the file object and data in req, but in data field it's giving '[object Object]'
Don't know how to access this. I tried JSON.parse(req.body.data), but getting error
SyntaxError: Unexpected token o in JSON at position 1
Looks like formData is an object that's cast to string [object Object] prior to being sent on the wire. Try data.append("data", JSON.stringify(formData)).
Send the object with JSON.stringify and then use JSON.parse once you receive data, to make the string object an object again.

AngularJS: PUT binary data from ArrayBuffer to the server

Ok, so I try to read a PDF file like this:
reader.readAsArrayBuffer(file);
and then try to send it to the server using $http like this:
$http.put(url, data, {headers: {'Content-Type': 'application/pdf'}});
So, just read & send the binary to the server in raw form. According to some resources I found, passing an ArrayBuffer to XHR should work, but passing it as data to $http just results in a request body like this: {} and Content-Length=2
Reading the file readAsBinaryString() results in a corrupted file (and is apparently deprecated for that very reason)
The use case seems so trivial to me, am I missing something?
Chrome 36, Angular 1.2.20
You have to use reader.readAsArrayBuffer(file); then in the onload callback create an ArrayBufferView from the result:
new Uint8Array(reader.result)
pass that data to $http and overwrite the transformRequest property so angularjs doesn't encode your array into json:
reader.onload = function() {
$http({
method: 'PUT',
headers: {'Content-Type': 'application/pdf'},
data: new Uint8Array(reader.result),
transformRequest: []
})
};
reader.readAsArrayBuffer(file);
Is it because you are just handing the $http method the array buffer instead of writing that buffer into a byte array? If so what you are posting to the server is probably just the arraybuffer object.
Check this post on how to write ArrayBuffer to byte array:
How do I read binary data to a byte array in Javascript?
There are two problems in your request.
You need to supply a data view to $http function.
So, data should be new DataView(data) or new Uint8Array(data) etc
$http always attempt to send the data as json. You can prevent this if you override the transform function. The transform function is the agent that is responsible for transforming your binary into json.
So, you should add transformRequest: [] property to your request.
Example:
var request = $http({
method: 'PUT',
url: 'example.com',
data: new Uint8Array(data),
headers: {'Content-Type': 'application/octet-stream'},
transformRequest: [],
responseType: 'arraybuffer'
});

Categories

Resources