4

I implemented a simple server in NodeJS using TypeScript and ExpressJS. At present, in each endpoint, I check if the incoming request body matches the expected parameters in the following way: -

express.Router().post('/add', (req: Request, res: Response) => {
     if (!req.body.operand1 || typeof req.body.operand1 !== 'number' ||
         !req.body.operand2 || typeof req.body.operand2 !== 'number') {
          res.send('Request body is invalid');
          return;
     }

     const parameters = req.body;

     res.send(parameters.operand1 + parameters.operand2);
}

But this would get tedious if there are many expected parameters in a given endpoint. What is the best way to achieve this?

EDIT

I edited this question because, before I had included some interfaces and the question looked similar to Detect whether object implement interface in TypeScript dynamically, which (understandably) confused people, while the scenario was different from that. There, the asker wanted to know if an object implements an interface. Here, I want to see if the body in a post request is the expected one.

Jayaraj P
  • 179
  • 7
  • 2
    There are a lot of validation libraries that can do that for you. Otherwise, why not write a simple function that uses the body and a rules object (like your interface) and crosschecks each property in the body with your rules. – svenbravo7 Aug 07 '20 at 12:39
  • @svenbravo7 Thanks for the reply. I would like to avoid using an external package if possible. I could write a method to cross-check whether a request body matches a particular interface (like the one in my example), but is there a way to make it generic? That is, given any object and interface, can I loop through the properties within the object and see if it matches with the interface. Since I have some experience in C#, reflection is what comes to my mind to do this, but not sure if typescript has anything similar. – Jayaraj P Aug 07 '20 at 12:51
  • I do not have any experience with Typescript I am afraid. But since that is converted to JS anyway, my gut feeling is telling me that there is no way of doing that out-of-the-box. If you want I can write an example of what I had in mind (without the interfaces)? – svenbravo7 Aug 07 '20 at 12:57
  • @svenbravo7 Sure!.That may impart some insights to me. – Jayaraj P Aug 07 '20 at 13:02
  • Done, see my example answer below. – svenbravo7 Aug 07 '20 at 13:16
  • I recently stumbled upon 'Joi' - https://joi.dev/api/?v=17.4.0 This was exactly what I was looking for. Don't know how I missed it. Anyway, wanted to share in case anyone would find it helpful [Note: Putting it as comment since this question was closed a while ago] – Jayaraj P Jun 29 '21 at 07:51

2 Answers2

2

So here is my example and what I had in mind. Its a very basic example and goes under the assumption that everything you define in your rules MUST be present in the body:

const AddEndpointRules = {
    operand1: 'number',
    operand2: 'number'
};

express.Router().post('/add', (req: Request, res: Response) => {
    // --- Changed
    if (!matches(req.body, AddEndpointRules)) {
        res.send('Request body is invalid');
        return;
    }
    // ---

    const parameters: AddEndpointParameters = req.body;

    res.send(parameters.operand1 + parameters.operand2);
}

function matches(body, rules) {
    // All keys of rules must be present, so we use that to check our body
    for (let attribute in rules) {
        // The type of value must be same as our rule
        // Not present would mean 'undefined'
        if (typeof body[attribute] !== rules[attribute]) {
            // We invalidate body as soon as we find our first invalid attribute
            return false;
        }
    }

    // All checked out, request body is OK
    return true;
}

You can also place the matches function in a class of its own and require/import it above your request and use it like for example: Validator.validate() (rename it to validate). That way you can also extend the logic some more and check for length and/or check deeper in the object.

svenbravo7
  • 317
  • 1
  • 6
  • Thanks. Although not exactly what I wanted since separate JSON (AddEndpointRules) has to be created instead of using the interface (AddEndpointParameters) directly, this would work and can come in handy; and you did mention in the question's comment that you are not experienced with typescript and interfaces. Appreciate the effort. Not marking this as answer, but giving an up-vote since someone might find it useful. – Jayaraj P Aug 07 '20 at 14:00
1

What you are looking for is called a schema. It's a way to define what a json object should look like or be formatted as and then use that to compare against the body that is being sent to the API. I would look into this.

https://www.npmjs.com/package/jsonschema

Jeymz
  • 89
  • 3