This post highlights an attempt to take a peek at the raw format of data sent in a POST request body and how one could parse it. There are packages like body-parser for Express that do this for us so this post is merely for learning purposes. I won’t suggest the use of this solution in production.
When making post requests to the server via HTML form submission, the data sent to the backend is typically configured with one of these media types: application/x-www-form-urlencoded, multipart/form-data or text/plain. I’m looking at application/x-www-form-urlencoded in this example.
Populating the fields and hitting ‘Save’ will submit the results to the root path containing the data fields as expected. This will use the default media type application/x-www-form-urlencoded. That means that it will create a query string using the field names as keys and its data as the values.
Capturing the POSTed data
To set the scene to capture this data, we must first check that its a POST request:
Given that the request sent to the backend is a Readablestream, the EventEmitter API is used as a means of reading data off this stream (we do not need to import the ‘events’ module here since the request object extends EventEmitter):
... if (req.method === 'POST') { let body = ''; req.on('data', chunk => { body += chunk.toString(); // convert Buffer to string }); req.on('end', () => { console.log(body); res.end('ok'); }); } ...
Populating the form and hitting ‘Save’ will log out this information to the console:
fname=Jermaine&age=29&photo=jermaine-photo.png
Each field in the form is delimited by the ampersand(&) character and the key and values are separated by the equal character.
Parsing the data
For ease of accessing each key/value pair we will use Node’s inbuilt querystring module to convert the data to an object:
// At the top of the file const { parse } = require('querystring'); ... ... if (req.method === 'POST') { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', () => { console.log( parse(body) ); res.end('ok'); }); } ...
To tidy this up a bit more, lets create a utility function to simplify the above:
function collectRequestData(request, callback) { const FORM_URLENCODED = 'application/x-www-form-urlencoded';
if(request.headers['content-type'] === FORM_URLENCODED) { let body = ''; request.on('data', chunk => { body += chunk.toString(); }); request.on('end', () => { callback(parse(body)); }); } else { callback(null); } }
We will use our function like so:
... if(req.method === 'POST') { collectRequestData(req, result => { console.log(result); res.end(`Parsed data belonging to ${result.fname}`); }); } ...
Fill in the form and submitting should display the message below:
Below is the full solution:
Limitations
You would have noticed that uploading a file sends only the file name to the backend and not the file itself. This is a limitation of the application/x-www-form-urlencoded media type. Using multipart/form-data will send the raw file along with its metadata. Perhaps in a future post, we will look at how this could be done!
I hope this has been an eye-opener, with respect to how the raw data format looks like being sent to the backend and how we would handle this. As always, please let me know if this helps and what you would like to see in future. Many thanks in advance.