Node req is a facade to be used by any framework to read the request values. The req object of Node.js HTTP request is very bare bones and it can get cumbersome to consistently read information for a given request.
Table of Contents
- Features
- Getting started
- Working with bodyparser
- Updating request data
- Typescript support
- Extending via Macros
- Difference from other frameworks
- API
Features
-
Handles inconsistencies between different header names like
referer
andreferrer
. -
Proxy headers support from reverse proxies like
nginx
orapache
. -
Content negotiation using
Accept
headers. - Form method spoofing support.
- Helper methods.
- Typings support
- Extendable from outside
- Thoroughly tested.
Getting started
Install the package from npm as follows:
npm i node-req
# yarn
yarn add node-req
and then use it by importing it as follows:
const { Request } = require('node-req')
const http = require('http')
http.createServer(function (req, res) {
const request = new Request(req, res, {})
res.end(`Url without query string is ${request.url()}`)
})
The url
property on Node.js core req
object returns the URL with query string and in order to drop query string, you will have to parse the URL manually.
Whereas, with node-req
, the request.url()
method supports both by passing a parameter to include the query string.
Working with bodyparser
Body parser job is to read the request body (probably from a middleware) and then expose it somehow to the end user. This module offers a handful of methods to consume the bodyparser output and then share it via pre-built methods.
http.createServer(function (req, res) {
const request = new Request(req, res, {})
const body = getRequestBodySomeHow(req)
request.setInitialBody(body)
console.log(request.all())
})
Along with request.all()
, you can use all of the following methods.
request.post()
Get the request body as it is.
request.post()
request.all()
Get merged copy of request body and query string.
request.all()
request.input(key, defaultValue?)
Returns the value for a key from request.all()
. The defaultValue
is used when original value is undefined
or null
.
request.except(keys[])
Returns an object of values except the given keys.
request.except(['submit', 'csrf'])
request.only(keys[])
Returns an object of values only for the given keys.
request.only(['username', 'age'])
Updating request data
Everything inside request is not subject to mutations, apart from the request body
or query string
object.
It is recommended to use inbuilt methods when trying to mutate these values, so that this module can keep a safe copy of original data.
updateBody(body: object)
Mutate the request body
request.updateBody(newBodyObject)
// reflects new body
request.all()
updateQs(data: object)
Mutate query string object
request.updateQs(data)
// reflects new query string
request.all()
request.get()
Why update request body or query string?
Updating request body or query string is the first step you will perform to ensure the user data is consistent and clean before your app can consume it.
Now after the mutation, you do want to keep the copy of original data, so that if their are any errors, you can reflect the original data copy to the end user.
For example:
- The form accepts amount of an item in Euros(€).
- Your server converts it to cents before validating the form values.
- If their are any errors during the validation, you want the form to show the amount back in Euros(€) and not cents.
http.createServer(function (req, res) {
const request = new Request(req, res, {})
/**
* Step 1: Original request body submitted by
* the user.
*/
const body = getRequestBodySomeHow(req)
request.setInitialBody(body)
/**
* Step 2: Sanitize data
*/
const body = request.all()
body.amount = toCents(body.amount)
request.updateBody(body)
/**
* Step 3: Validate data
*/
validate(request.all())
/**
* Step 4: Assuming validation failed and reflect
* original data back in form
*/
res.send({
original: request.original()
})
})
Typescript support
The module is written in Typescript, so expect intellisense to work out of the box. Also an interface is exported, which you can extend if extending the original Request
class.
import { IRequest: BaseIRequest } from 'node-req/build/src/IRequest'
export interface IRequest extends BaseIRequest {
myCustomMethod (): string
}
and then use it as follows
import { IRequest } from './my/interfaces'
http.createServer(function (req, res) {
const request: IRequest = new Request(req, res, {})
request.myCustomMethod() // intellisense works
})
Extending via Macros
The module extends macroable, which allows extending classes from outside in. You can use the following methods to extend the prototype of the Request
class.
import { Request } from 'node-req'
// Added as a method
Request.macro('getTime', function () {
return new Date().getTime()
})
// Added as property
Request.getter('getTime', function () {
return new Date().getTime()
})
// Added as singleton property
Request.getter('getTime', function () {
return new Date().getTime()
}, true)
Later, using the request instance, you can use getters
and macros
.
http.createServer(function (req, res) {
const request = new Request(req, res, {})
request.getTime // getter
request.getTime() // macro
})
Difference from other frameworks
You don't need this module, if you are using Express or Koa, since their req
object is already decorated with handful of convivent getters.
In case you are building a framework or using a framework like micro, then this module can save lots of time.
API
The API docs are generated using Typedoc and can be found here.