DEV Community

Cover image for 90-Nodejs Course 2023: Restful Routes: Restful Resource
Hasan Zohdy
Hasan Zohdy

Posted on

 

90-Nodejs Course 2023: Restful Routes: Restful Resource

So, we got to know what is meant by Restful Api concept, now let's start implementing it in our project.

Workflow

Before we start implementing the Restful Api concept, we need to know the workflow of the project, so we can understand how to implement it.

Our first step is to create a route.resource method, this method will be used to generate all the routes for a specific resource, so we need to pass the resource name to it.

This method is supposed to generate the following routes:

  1. GET /resource - Get all resources
  2. GET /resource/:id - Get a specific resource
  3. POST /resource - Create a new resource
  4. PUT /resource/:id - Update a specific resource
  5. DELETE /resource/:id - Delete a specific resource
  6. PATCH /resource/:id - Update a specific resource

The second argument is resource object, that object should have certain methods, each method represents a handler for a specific route, so we need to pass the handler for each route to the resource object.

For example:


const resource = {
  list: listUsers,
  get: getSingleUser,
  create: createUser,
  update: updateUser,
  delete: deleteUser,
  patch: patchUser,
};
Enter fullscreen mode Exit fullscreen mode

So based on what the resource contains, we'll add the routes accordingly.

The other good feature is that we can also pass route options to be used with these routes, as we do with single route call.

We'll also use route name feature to name the routes, so we can use them in the future.

Enough talking now let's move to the code.

Implementation

First off, let's define our Resource Type.

// src/core/router/types.ts

/** Route resource */
export type RouteResource = {
  /**
   * list route
   */
  list?: RouteHandler;
  /**
   * Single resource route
   */
  get?: RouteHandler;
  /**
   * Create resource route
   */
  create?: RouteHandler;
  /**
   * Update resource route
   */
  update?: RouteHandler;
  /**
   * Patch resource route
   */
  patch?: RouteHandler;
  /**
   * Delete resource route
   */
  delete?: RouteHandler;
};
Enter fullscreen mode Exit fullscreen mode

So we just defined a type that is used to define the resource object, it contains all the methods that will be used to handle the routes, the handler is the same as the single route handler, so nothing new here.

Resource Method

Now let's define our resource method, this method will receive three arguments, the first one is the resource path, the second one is the resource object, and the third one is the route options.

We need also to set the resource name if it is not passed in the options, let's see in action.

// src/core/router/index.ts
import { ltrim, merge, toCamelCase } from "@mongez/reinforcements";
// ...
  /**
   * Add full restful resource routes
   * This method will generate the following routes:
   * 1. GET /path: list all resources
   * 2. GET /path/:id: get a single resource
   * 3. POST /path: create a new resource
   * 4. PUT /path/:id: update a resource
   * 5. DELETE /path/:id: delete a resource
   * 6. PATCH /path/:id: update a resource partially
   */
  public resource(
    path: string,
    resource: RouteResource,
    options: RouteOptions = {},
  ) {
    // get base resource name
    const baseResourceName = options.name || toCamelCase(ltrim(path, "/"));

    if (resource.list) {
      const resourceName = baseResourceName + ".list";
      this.get(path, resource.list, { ...options, name: resourceName });
    }

    if (resource.get) {
      const resourceName = baseResourceName + ".get";

      this.get(path + "/:id", resource.get, { ...options, name: resourceName });
    }

    if (resource.create) {
      const resourceName = baseResourceName + ".create";

      this.post(path, resource.create, { ...options, name: resourceName });
    }

    if (resource.update) {
      const resourceName = baseResourceName + ".update";

      this.put(path + "/:id", resource.update, {
        ...options,
        name: resourceName,
      });
    }

    if (resource.patch) {
      const resourceName = baseResourceName + ".patch";

      this.patch(path + "/:id", resource.patch, {
        ...options,
        name: resourceName,
      });
    }

    if (resource.delete) {
      const resourceName = baseResourceName + ".delete";

      this.delete(path + "/:id", resource.delete, {
        ...options,
        name: resourceName,
      });
    }

    return this;
  }
Enter fullscreen mode Exit fullscreen mode

Nothing hard here, firstly i got the baseResourceName, you can pass it in the options list, otherwise it will be taken from the path.

const baseResourceName = options.name || toCamelCase(ltrim(path, "/"));
Enter fullscreen mode Exit fullscreen mode

toCamelCase is used to transform the path to camel case, for example users-groups will be transformed to usersGroups.

And i used ltrim to remove the / from the path, so if the path is /users it will be users.

Then we checked for each route type, we started with list, if it exists we'll add the route, we used the baseResourceName and added .list to it, so the route name will be users.list for example, then we added it as a route to our router system.

And the same applies for the rest of the routes.

Usage

Now let's see how we can use it.

// src/app/users/routes.ts
import router from "core/router";
import login from "./controllers/auth/login";
import listUsers from './controllers/users/list';
import getUser from './controllers/users/get';
import createUser from './controllers/users/create';
import updateUser from './controllers/users/update';
import patchUser from './controllers/users/patch';

const restfulUser = {
    list: listUsers,
    get: getUser,
    create: createUser,
    update: updateUser,
    patch: patchUser,
};

router.resource("/users", restfulUser);

router.post("/login", login);
Enter fullscreen mode Exit fullscreen mode

And that's it!, now you can use the resource routes in your application.

๐ŸŽจ Conclusion

In this article, we learned how to create a resource route, and how to use it in our application.

In our next article, we'll see how to create our first Restful Class, that manages everything within a one place!, stay tuned.

โ˜•โ™จ๏ธ Buy me a Coffee โ™จ๏ธโ˜•

If you enjoy my articles and see it useful to you, you may buy me a coffee, it will help me to keep going and keep creating more content.

๐Ÿš€ 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)

Oldest comments (0)

11 Tips That Make You a Better Typescript Programmer

typescript

1 Think in {Set}

Type is an everyday concept to programmers, but itโ€™s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields

...

Read the whole post now!