21-Nodejs Course 2023: Advanced Request Data Handling

hassanzohdy

Hasan Zohdy

Posted on November 1, 2022

21-Nodejs Course 2023: Advanced Request Data Handling

We've successfully created our own Request class, now let's add some methods to allow us getting data from the request.

Request Input

Our first method we'll use here is input which will grab us a value from the request body, query string, or URL parameters.

// src/core/http/request.ts

  /**
   * Get the value of the given key from the request body, query or params
   */
  public input(key: string, defaultValue?: any) {
    return (
      this.request.params[key] ||
      this.request.body[key]?.value ||
      this.request.query[key] ||
      defaultValue
    );
  }
Enter fullscreen mode Exit fullscreen mode

In this method, we checked for the key in the params list, body, and query string. If the key is not found, we return the default value.

Now we can use this method in our controller to get the value of the name key from the request body.

// src/app/users/controllers/create-user.ts

  /**
   * Create a new user
   */
  export default function async createUser(request: Request) {
    const name = request.input('name');

    return {
      name
    };
  }
Enter fullscreen mode Exit fullscreen mode

Request All

The all method will return all the data from the request body, query string, and URL parameters.

// src/core/http/request.ts

  /**
   * Get all the data from the request body, query or params
   */

  /**
   * Get all inputs from the request body, query or params
   */
  public all() {
    const body: any = {};

    for (const key in this.request.body) {
      body[key] = this.request.body[key].value;
    }

    return {
      ...this.request.params,
      ...body,
      ...this.request.query,
    };
  }
Enter fullscreen mode Exit fullscreen mode

We can also expose the params, body, and query properties to get the data from each of them.

// src/core/http/request.ts

  /**
   * Get the request params
   */
  public get params() {
    return this.request.params;
  }

  /**
   * Get the request body
   */
  public get body() {
    const body: any = {};

    for (const key in this.request.body) {
      body[key] = this.request.body[key].value;
    }

    return body;
  }

  /**
   * Get the request query
   */
  public get query() {
    return this.request.query;
  }
Enter fullscreen mode Exit fullscreen mode

Now we can update or all and input methods again to use the body property.

  /**
   * Get all inputs from the request body, query or params
   */
  public all() {
    return {
      ...this.request.params,
      ...this.body,
      ...this.request.query,
    };
  }

  /**
   * Get the value of the given key from the request body, query or params
   */
  public input(key: string, defaultValue?: any) {
    return (
      this.request.params[key] ||
      this.body[key] ||
      this.request.query[key] ||
      defaultValue
    );
  }
Enter fullscreen mode Exit fullscreen mode

Request Boolean Input

Let's add a new method that we can call bool to make sure that we can receive a boolean value from the request.

For example if the url is something like this: google.com?is_admin=true we want to make sure that the value of is_admin is a boolean.


  /**
   * Get the boolean value of the given key from the request body, query or params
   */
  public bool(key: string, defaultValue?: boolean = false) {
    const value = this.input(key, defaultValue);

    if (value === 'true') {
      return true;
    }

    if (value === 'false') {
      return false;
    }

    return Boolean(value);
  }
Enter fullscreen mode Exit fullscreen mode

Request Integer Input

We can also add a method to get an integer value from the request.

  /**
   * Get the integer value of the given key from the request body, query or params
   */
  public int(key: string, defaultValue = 0) {
    const value = this.input(key, defaultValue);

    return parseInt(value);
  }
Enter fullscreen mode Exit fullscreen mode

Request Float Input

We can also add a method to get a float value from the request.

  /**
   * Get the float value of the given key from the request body, query or params
   */
  public float(key: string, defaultValue = 0) {
    const value = this.input(key, defaultValue);

    return parseFloat(value);
  }
Enter fullscreen mode Exit fullscreen mode

Request Number Input

We can also add a method to get a number value from the request.

  /**
   * Get the number value of the given key from the request body, query or params
   */
  public number(key: string, defaultValue = 0) {
    const value = this.input(key, defaultValue);

    return Number(value);
  }
Enter fullscreen mode Exit fullscreen mode

Request File Input

Now let's head to the big boss input, the file input, this one will have a special treatment as we'll create a new class handler for that file, we'll call it UploadedFile but let's first create the file method

  /**
   * Get the file value of the given key from the request body, query or params
   */
  public file(key: string) {
    return this.request.body[key];
  }
Enter fullscreen mode Exit fullscreen mode

Here we'll have a little problem, the file itself is stored in another key than the value that we used in the body which is called file, so we need to make a small modification about that first in our body property.

  /**
   * Get the request body
   */
  public get body() {
    const body: any = {};

    for (const key in this.request.body) {
      const data = this.request.body[key];

      if (data.file) {
        body[key] = {
          file: data.file,
          filename: data.filename,
          mimetype: data.mimetype,
        };
      } else {
        body[key] = data.value;
      }
    }

    return body;
  }
Enter fullscreen mode Exit fullscreen mode

As we can see the multipart plugin provides us with some extra data about the file like the file name and its mimetype so we can catch these too.

Watchout for the array of inputs

Let's hold the files for a moment, imagine with me that you're receiving an array of values of the same key, for example tags which is an array of strings, so the request will look like this:

tags[]: tag1
tags[]: tag2
tags[]: tag3
Enter fullscreen mode Exit fullscreen mode

Please keep in mind that we're still managing the multipart form data, there will be also a json handling next.

Now these values will be sent in one key called tags[] and it will sent as an array instead.

Now we have to check if the data from the body is an array or not, if so then handle it as an array, otherwise handle it as a single value.

  /**
   * Get the request body
   */
  public get body() {
    const body: any = {};

    for (const key in this.request.body) {
      const data = this.request.body[key];

      if (Array.isArray(data)) {
        body[key] = data.map(this.parseBodyValue.bind(this));
      } else {
        body[key] = this.parseBodyValue(data);
      }

    return body;
  }
Enter fullscreen mode Exit fullscreen mode

Wait! parseBodyValue, what? this method will just use now to handle the given data properly, so we don't have to repeat our code again, as we can see we'll use it in the map to convert the request body data into proper data, and it is not an array then we'll call it directly.

  /**
   * Parse the body value
   */
  private parseBodyValue(data: any) {
    if (data.file) {
      return {
        file: data.file,
        filename: data.filename,
        mimetype: data.mimetype,
      };
    }

    return data.value;
  }
Enter fullscreen mode Exit fullscreen mode

If the request body content is json, then the data will be returned directly, so we can just return it as it is.

  /**
   * Parse the body value
   */
  private parseBodyValue(data: any) {
    if (data.file) {
      return {
        file: data.file,
        filename: data.filename,
        mimetype: data.mimetype,
      };
    }

    return data.value || data;
  }
Enter fullscreen mode Exit fullscreen mode

Uploaded File

This is where we'll stop for this article, we'll continue in the next article to handle the UploadedFile class.

🎨 Project Repository

You can find the latest updates of this project on Github

😍 Join our community

Join our community on Discord to get help and support (Node Js 2023 Channel).

🎞️ Video Course (Arabic Voice)

If you want to learn this course in video format, you can find it on Youtube, the course is in Arabic language.

💰 Bonus Content 💰

You may have a look at these articles, it will definitely boost your knowledge and productivity.

General Topics

Packages & Libraries

React Js Packages

Courses (Articles)

💖 💪 🙅 🚩
hassanzohdy
Hasan Zohdy

Posted on November 1, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related