DEV Community

Cover image for Creating your own ExpressJS from scratch (Part 3) - Handling Request and Response objects
Wesley Miranda
Wesley Miranda

Posted on • Edited on

Creating your own ExpressJS from scratch (Part 3) - Handling Request and Response objects

In part 2, We applied the middleware pattern for our web framework, which make us able to execute how many middlewares that we want for a route.

Today We are going to create Decorators for our Request and Response objects, applying the decorator and middleware pattern together to get parameters and query strings from the URL, also create helper functions to respond to the requests as a JSON transformer, for example.

Let's go!

Request Decorator

src/request.js

const { match } = require('path-to-regexp') const RequestDecorator = (routes, request, response, next) => { // (1) const getParams = () => { const urlParams = request.url.split('/').slice(1) // remove querystrings from the last parameter const [lastParam] = urlParams[urlParams.length - 1].split('?') urlParams.splice(urlParams.length - 1, 1) // joining all params without querystrings const allParams = [...urlParams, lastParam].join('/') // matching url pattern to get the params for (const path of routes) { const urlMatch = match(path, { decode: decodeURIComponent, }); const url = `/${allParams}/${request.method.toUpperCase()}` const found = urlMatch(url) if (found) { Object.keys(found.params).forEach(key => { request.params = { ...request.params, [key]: found.params[key] } }) break } } } // (2) const getQuery = () => { const urlParams = request.url.split('/').slice(1) // Isolating query strings const [lastParam, queryString] = urlParams[urlParams.length - 1].split('?') let params = new URLSearchParams(queryString); let entries = params.entries(); request.query = { ...request.query, ...Object.fromEntries(entries) } } getParams() getQuery() next() } module.exports = RequestDecorator 
Enter fullscreen mode Exit fullscreen mode

From the code sessions above:

1 - Treating the URL to compare with the existent routes and get the parameters and set the request object.

2 - Transforming the query string into an object and setting the request object.


Response Decorator

src/response.js

const ResponseDecorator = (req, res, next) => { // (1) res.status = (status) => { res.statusCode = status return res } // (2) res.json = (data) => { res.setHeader('Content-type', 'application/json') res.end(JSON.stringify(data)) } // (3) res.send = async (data) => { res.end(data) } res.render = async (templatePath, data) => { // We are going to implement it later } next() } module.exports = ResponseDecorator 
Enter fullscreen mode Exit fullscreen mode

From the code sessions above:

1 - Changing the status code and returning the response object, to set the status and response in one line.

2 - Transforming the response into JSON.

3 - Send a text to the client.


Applying Decorators as Middlewares

src/app.js

We need to import our two decorators:

const requestDecorator = require('./request') const responseDecorator = require('./response') 
Enter fullscreen mode Exit fullscreen mode

Now, We have to modify our serverHandler function to apply the decorators as middlewares for all routes.

 const serverHandler = async (request, response) => { const sanitizedUrl = sanitizeUrl(request.url, request.method) const match = matchUrl(sanitizedUrl) if (match) { const middlewaresAndControllers = routes.get(match) await dispatchChain(request, response, [requestDecorator.bind(null, routes.keys()), responseDecorator, ...middlewaresAndControllers]) } else { response.statusCode = 404 response.end('Not found') } } 
Enter fullscreen mode Exit fullscreen mode

Testing

index.js

 // (1) app.get('/params/:id/:name', (req, res) => { res.end(JSON.stringify({ params: req.params, query: req.query }, null, 2)) }) // (2) app.get('/response/:id', (req, res) => { if (req.params.id === '123') { res.status(200).json(req.params) return } res.status(400).json({ message: 'Invalid id' }) }) 
Enter fullscreen mode Exit fullscreen mode

From the code sessions above:

1 - Returning the parameters and query strings from the URL as text.

2 - Here is an example of how you can return JSON and change the status code at the same time.


Conclusion

Using the same that We use for middlewares, we can treat the resquest and response and make them fancier.

You can take a look at the entire code here

I hope you like it.

Top comments (1)

Collapse
 
duongphan profile image
Thanh Dương Phan

Nice bro