Express provides a default Express.Request
type that can be used in building powerful servers.
Request is an interface that includes the following :
- ReqBody
- ReqQuery
- ReqParams
But when you are developing a complex application, you need to add different properties to your Request Objects. This is where the age old practice of extending Data Types come in.
For example, I want to Authorize
requests using JWT in Lynkit. For that I added a SessionToken
for the requests that need authentication.
And then to check : if the client making the request is Authorized or not
I added a middleware that verifies the Tokens.
When the token is verified, you will need to decode the token before every request, and put in the decoded data somewhere.
In Javascript, it would have been a simple effort to add an additional property to the request object, as it does not need to strictly follow a certain interface.
- Register User and then allow them to login
- Successful Login generates a Session Token using JWT that hashes and stores the following details :
{ "email": "tthevinitguptaaawa@gmail.com", "name": "Vinit Gupta", "_id": "64ef2d863c4b2c55efb90590", "__v": 0 }
- The token is stored in the User's
cookies🍪
- A Middleware to verify the user's token and extract the details.
The next thing, I had to do was to pass the above extracted details to the Request Handler
function.
The natural way to to this is to attach the user data to the Request Object. But Request object does not have a User property by default.
After a lot of headaches, I was able to find 3 ways to accept the user details and let's discuss about it from the worst to the most elegant and typescript suggested
way.
The simplest way to add a custom data in any argument is to use the & any
syntax. This appends a user
field in the Request object with the any
data type :
Important
Use of the above method not recommended
Another way to solve the problem of custom request type is to extend the Request locally as a type.
This ways since it can be defined in the same file we need to extend the Request Object
in.
This works, but is a tedious approach as you have to do this for every file that you need the extension to be.
The Express types provides us the functionality to extend the Globally declared Express
namespace that contains the Request interface
.
This is really a powerful feature and can be used to extend the Express namespace globally (called Augmentation).
The steps are really simple :
- Create a file with the following extension
*.d.ts
, which are calledDeclaration files
and are used to define types. (For best approach, create a folder calledsrc/types/
and define all the separate types inside this - We will add the
user
data to the interface, so we name it :user.d.ts
- Then we create a user interface :
interface IUser {
name: string;
_id: ObjectId;
email: string;
}
- Declare a global namespace with the same name as the one you want to extend. This adds on to the already defined one(Augmenting) and add the above defined interface.
declare global {
namespace Express {
interface Request {
user: IUser;
}
}
}
And now you can use this in multiple places inside your apps.
You can also add other types as per you usage and also declare generic types to extend the capabilities further.