Creating our server

Let’s set one up using the snippet below:

const http = require('http'); const server = http.createServer((req, res) => {

res.end(`

<!doctype html>

<html>

<body>

<form action="/" method="post">

<input type="text" name="fname" /><br />

<input type="number" name="age" /><br />

<input type="file" name="photo" /><br />

<button>Save</button>

</form>

</body>

</html>

`);

}); server.listen(3000);

This should spin up a page at http://localhost:3000 with a web form:

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:

const http = require('http'); const server = http.createServer((req, res) => {

if (req.method === 'POST') {

// Handle post info...

}

else {

res.end(`

<!doctype html>

<html>

<body>

<form action="/" method="post">

<input type="text" name="fname" /><br />

<input type="number" name="age" /><br />

<input type="file" name="photo" /><br />

<button>Save</button>

</form>

</body>

</html>

`);

}

}); server.listen(3000);

Given that the request sent to the backend is a Readable stream, 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');

});

}

...

This will log out the result below:

{

fname: 'Jermaine',

age: '29',

photo: 'jermaine-photo.jpg'

}

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! In the meantime, here’s how to handle the POST request body in Dart without using a framework.

I hope this has been an eye-opener, with respect to how the raw data format looks like being sent to the back-end and how we would handle this.

Interestingly, I run a YouTube channel teaching subscribers to build full-stack applications with the Dart language and its ecosystem. Subscribe today and join me on this journey.

As always, your feedback is welcome. Many thanks in advance.

Further Reading