avatarMarcos Henrique da Silva

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

9805

Abstract

plice</span>(objIndex, <span class="hljs-number">1</span>); <span class="hljs-keyword">return</span> <span class="hljs-string"><span class="hljs-subst">${userId}</span> removed</span>; }</pre></div><div id="ec59"><pre>}</pre></div><blockquote id="3a05"><p>Update 2020–06–01: thanks <a href="https://medium.com/@matthew.sherrill.2107?source=post_page-----43583ce3566d----------------------">Matthew</a> for pointing that the splice method was incorrect. Now it’s updated :)</p></blockquote><p id="a550">I will not go further to explain the code above since is just to have something to test our services at the end of this article. <b>Remember</b> that in the end of the series of article we are going to be using a real MongoDB with Docker and all the pieces will be connected to have real API working on your computer.</p><blockquote id="8103"><p>Never use a handmade “in memory” database in a live application, <b>NEVER</b></p></blockquote><p id="b38f">Now we can create our services. As for what me made with a daos folder, let’s create a folder called <b>services </b>inside of the users folder and inside of it, create a file called <b>user.services.ts</b></p><p id="4e1e">What we want to create here is an abstraction between a DAO file and the service itself. For abstracting it we are sure that we want the following methods to be always created:</p><ul><li>list: (limit: number, page: number) => any</li><li>create: (resource: any) => string</li><li>updateById: (resourceId: any) => string</li><li>readById: (resourceId: any) => any</li><li>deleteById: (resourceId: any) => string</li><li>patchById: (resourceId: any) => string</li></ul><p id="75e2">We are basically using this pattern to every resource that we will create and instead of creating it directly to the service, we will be using a concept called <b>interface</b>. That will force us to implement these methods into our service and Typescript allows us do use this feature.</p><p id="bd9b">For now, let the <b>user.services.ts </b>empty and let’s go to the root folder of the project, and inside of the common folder, let’s create a folder called interfaces and the file called <b>crud.interface.ts. </b>Here is the final code:</p><div id="37f0"><pre><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> CRUD { <span class="hljs-attr">list</span>: <span class="hljs-function">(<span class="hljs-params">limit: <span class="hljs-built_in">number</span>, page: <span class="hljs-built_in">number</span></span>) =></span> <span class="hljs-built_in">any</span>, <span class="hljs-attr">create</span>: <span class="hljs-function">(<span class="hljs-params">resource: <span class="hljs-built_in">any</span></span>) =></span> <span class="hljs-built_in">string</span>, <span class="hljs-attr">updateById</span>: <span class="hljs-function">(<span class="hljs-params">resourceId: <span class="hljs-built_in">any</span></span>) =></span> <span class="hljs-built_in">string</span>, <span class="hljs-attr">readById</span>: <span class="hljs-function">(<span class="hljs-params">resourceId: <span class="hljs-built_in">any</span></span>) =></span> <span class="hljs-built_in">any</span>, <span class="hljs-attr">deleteById</span>: <span class="hljs-function">(<span class="hljs-params">resourceId: <span class="hljs-built_in">any</span></span>) =></span> <span class="hljs-built_in">string</span>, <span class="hljs-attr">patchById</span>: <span class="hljs-function">(<span class="hljs-params">resourceId: <span class="hljs-built_in">any</span></span>) =></span> <span class="hljs-built_in">string</span>, }</pre></div><p id="0d00">We are just defining here the <b>interface</b> with the methods (functions) that we want to anyone who use this interface to have, setting the parameters and the abstract response. You can read more about <a href="https://www.typescriptlang.org/docs/handbook/interfaces.html">interfaces here</a>.</p><p id="da66">Now we can open the <b>user.services.ts</b> file and add the following:</p><div id="70cc"><pre><span class="hljs-keyword">import</span> {CRUD} <span class="hljs-keyword">from</span> <span class="hljs-string">'../../common/interfaces/crud.interface'</span>; <span class="hljs-keyword">import</span> {GenericInMemoryDao} <span class="hljs-keyword">from</span> <span class="hljs-string">'../daos/in.memory.dao'</span>;</pre></div><div id="cec1"><pre>export <span class="hljs-title class_"><span class="hljs-keyword">class</span> <span class="hljs-title">UsersService</span> <span class="hljs-keyword"><span class="hljs-keyword">implements</span> <span class="hljs-type">CRUD</span></span> </span>{ <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> instance: <span class="hljs-type">UsersService</span>; dao: <span class="hljs-type">GenericInMemoryDao</span>;</pre></div><div id="abc8"><pre><span class="hljs-function"><span class="hljs-keyword">constructor</span><span class="hljs-params">()</span> <span class="hljs-comment">{ this.dao = GenericInMemoryDao.getInstance(); }</span></span></pre></div><div id="dafd"><pre><span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-title">getInstance</span><span class="hljs-params">()</span>: UsersService {</span> <span class="hljs-keyword">if</span> (!UsersService.instance) { UsersService.instance = <span class="hljs-keyword">new</span> <span class="hljs-built_in">UsersService</span>(); } <span class="hljs-keyword">return</span> UsersService.instance; }</pre></div><div id="cfb3"><pre><span class="hljs-title function_">create</span>(<span class="hljs-params">resource: <span class="hljs-built_in">any</span></span>) { <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">dao</span>.<span class="hljs-title function_">addUser</span>(resource); }</pre></div><div id="e0d6"><pre><span class="hljs-title function_">deleteById</span>(<span class="hljs-params">resourceId: <span class="hljs-built_in">any</span></span>) { <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">dao</span>.<span class="hljs-title function_">removeUserById</span>(resourceId); };</pre></div><div id="7696"><pre><span class="hljs-title function_">list</span>(<span class="hljs-params">limit: <span class="hljs-built_in">number</span>, page: <span class="hljs-built_in">number</span></span>) { <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">dao</span>.<span class="hljs-title function_">getUsers</span>(); };</pre></div><div id="2f4e"><pre><span class="hljs-title function_">patchById</span>(<span class="hljs-params">resource: <span class="hljs-built_in">any</span></span>) { <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">dao</span>.<span class="hljs-title function_">patchUserById</span>(resource) };</pre></div><div id="8882"><pre><span class="hljs-title function_">readById</span>(<span class="hljs-params">resourceId: <span class="hljs-built_in">any</span></span>) { <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">dao</span>.<span class="hljs-title function_">getUserById</span>(resourceId); };</pre></div><div id="ac6d"><pre><span class="hljs-title function_">updateById</span>(<span class="hljs-params">resource: <span class="hljs-built_in">any</span></span>) { <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">dao</span>.<span class="hljs-title function_">putUserById</span>(resource); };</pre></div><div id="51b2"><pre>}</pre></div><p id="b31d">And that’s it. Our service is now communicating with our generic dao and using all the methods that the <b>CRUD</b> interface is asking to. In the late articles we will go back to this service and change the implementation to use a real MongoDB with Mongoose.</p><blockquote id="2c50"><p>Our service will be handling the calls to the current dao and we will change only this file to switch one database implementation to another one.</p></blockquote><p id="a541">The missing cherry of this article is to update the user controller now. Open the <b>user.controllers.ts</b> file and update the code to call our service.</p><div id="3b2c"><pre><span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>; <span class="hljs-keyword">import</span> {UsersService} <span class="hljs-keyword">from</span> <span class="hljs-string">'../services/user.services'</span>;</pre></div><div id="a6de"><pre><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UsersController</span> { <span class="hljs-title function_">constructor</span>(<span class="hljs-params"></span>) { }</pre></div><div id="a5b5"><pre><span class="hljs-title function_">listUsers</span>(<span class="hljs-params">req: express.Request, res: express.Response</span>) { <span class="hljs-keyword">const</span> usersService = <span class="hljs-title class_">UsersService</span>.<span class="hljs-title function_">getInstance</span>(); <span class="hljs-keyword">const</span> users = usersService.<span class="hljs-title function_">list</span>(<span class="hljs-number">100</span>, <span class="hljs-number">0</span>); res.<span class="hljs-title function_">status</span>(<span class="hljs-

Options

number">200</span>).<span class="hljs-title function_">send</span>(users); }</pre></div><div id="40e7"><pre>getUserById(req: express.Request, res: express.Response) { <span class="hljs-keyword">const</span> usersService = UsersService.getInstance(); <span class="hljs-keyword">const</span> <span class="hljs-keyword">user</span> = usersService.readById(req.params.<span class="hljs-keyword">user</span>Id); res.status(<span class="hljs-number">200</span>).send(<span class="hljs-keyword">user</span>); }</pre></div><div id="af4c"><pre><span class="hljs-title function_ invoke__">createUser</span>(<span class="hljs-attr">req</span>: express.Request, <span class="hljs-attr">res</span>: express.Response) { <span class="hljs-keyword">const</span> <span class="hljs-variable constant_">usersService</span> = UsersService.<span class="hljs-title function_ invoke__">getInstance</span>(); <span class="hljs-keyword">const</span> <span class="hljs-variable constant_">userId</span> = usersService.<span class="hljs-title function_ invoke__">create</span>(req.body); res.<span class="hljs-title function_ invoke__">status</span>(<span class="hljs-number">201</span>).<span class="hljs-title function_ invoke__">send</span>({<span class="hljs-attr">id</span>: userId}); }</pre></div><div id="5e24"><pre><span class="hljs-title function_">patch</span>(<span class="hljs-params">req: express.Request, res: express.Response</span>) { <span class="hljs-keyword">const</span> usersService = <span class="hljs-title class_">UsersService</span>.<span class="hljs-title function_">getInstance</span>(); usersService.<span class="hljs-title function_">patchById</span>(req.<span class="hljs-property">body</span>); res.<span class="hljs-title function_">status</span>(<span class="hljs-number">204</span>).<span class="hljs-title function_">send</span>(<span class="hljs-string"></span>); }</pre></div><div id="d953"><pre><span class="hljs-title function_">put</span>(<span class="hljs-params">req: express.Request, res: express.Response</span>) { <span class="hljs-keyword">const</span> usersService = <span class="hljs-title class_">UsersService</span>.<span class="hljs-title function_">getInstance</span>(); usersService.<span class="hljs-title function_">updateById</span>(req.<span class="hljs-property">body</span>); res.<span class="hljs-title function_">status</span>(<span class="hljs-number">204</span>).<span class="hljs-title function_">send</span>(<span class="hljs-string"></span>); }</pre></div><div id="0557"><pre><span class="hljs-title function_">removeUser</span>(<span class="hljs-params">req: express.Request, res: express.Response</span>) { <span class="hljs-keyword">const</span> usersService = <span class="hljs-title class_">UsersService</span>.<span class="hljs-title function_">getInstance</span>(); usersService.<span class="hljs-title function_">deleteById</span>(req.<span class="hljs-property">params</span>.<span class="hljs-property">userId</span>); res.<span class="hljs-title function_">status</span>(<span class="hljs-number">204</span>).<span class="hljs-title function_">send</span>(<span class="hljs-string">``</span>); }</pre></div><div id="3455"><pre>}</pre></div><p id="bb8c">Look that now we can talk a bit more about our structure:</p><ul><li>A routes file that is responsible only to define endpoints and who controls it (controllers)</li><li>A controller file which is responsible to call a service which will do what the route is defined to do and to send a response to the client</li><li>A service file that is responsible to “talk” to whatever database you might be wanting to use</li><li>A specific DAO file that could be any database implementation, ORM, ODM, that you might need</li><li>All of our functions are short and well defined and <b>easy to read</b></li></ul><p id="8de7">That might be a bit of too much abstraction but once you start to have a huge project with hundreds of resources, services, then all of this breakdown strategy starts to easy it up your and your co-workers life. Again, its not a final strategy but one of several that I found useful in my working career so far.</p><p id="574a">If you will run <code>npm start</code> now you will be able to call your API requests with Postman or Insomnia and play with it. Remember that we are not controlling any type of request and every time you will restart the API all the data will be gone. But we have enough to test the routes, controllers and services with more useful data now.</p><p id="6a68">Here are some requests CURL samples:</p><p id="9932">Create a new user:</p><div id="05b2"><pre>curl --<span class="hljs-keyword">location</span> <span class="hljs-title">--request</span> POST 'localhost:<span class="hljs-number">3000</span>/users'
--header 'Content-<span class="hljs-keyword">Type</span>: application/json'
--data-raw '{ <span class="hljs-string">"username"</span>:<span class="hljs-string">"mytestingUser"</span>, <span class="hljs-string">"password"</span>:<span class="hljs-string">"amazingMediumArticle"</span> }'</pre></div><p id="56c7">List users:</p><div id="6756"><pre><span class="hljs-string">curl</span> <span class="hljs-built_in">--location</span> <span class="hljs-built_in">--request</span> <span class="hljs-string">GET</span> <span class="hljs-string">'localhost:3000/users'</span>
<span class="hljs-built_in">--header</span> <span class="hljs-string">'Content-Type: application/json'</span> </pre></div><p id="6c8f">Patch an user:</p><div id="af68"><pre>curl --<span class="hljs-keyword">location</span> <span class="hljs-title">--request</span> PATCH 'localhost:<span class="hljs-number">3000</span>/users/<span class="hljs-number">3</span>'
--header 'Content-<span class="hljs-keyword">Type</span>: application/json'
--data-raw '{ <span class="hljs-string">"username"</span>:<span class="hljs-string">"mytestingUser2"</span>, <span class="hljs-string">"password"</span>:<span class="hljs-string">"amazingMediumArticle"</span>, <span class="hljs-string">"id"</span>:<span class="hljs-number">3</span> }'</pre></div><p id="a32d">Put an user:</p><div id="7d7d"><pre>curl --<span class="hljs-keyword">location</span> <span class="hljs-title">--request</span> PUT 'localhost:<span class="hljs-number">3000</span>/users/<span class="hljs-number">3</span>'
--header 'Content-<span class="hljs-keyword">Type</span>: application/json'
--data-raw '{ <span class="hljs-string">"username"</span>:<span class="hljs-string">"mytestingUser2"</span>, <span class="hljs-string">"password"</span>:<span class="hljs-string">"amazingMediumArticle4"</span>, <span class="hljs-string">"id"</span>:<span class="hljs-number">3</span> }'</pre></div><p id="f4e2">Delete an user:</p><div id="8cce"><pre><span class="hljs-string">curl</span> <span class="hljs-built_in">--location</span> <span class="hljs-built_in">--request</span> <span class="hljs-string">DELETE</span> <span class="hljs-string">'localhost:3000/users/3'</span>
<span class="hljs-built_in">--header</span> <span class="hljs-string">'Content-Type: application/json'</span>
<span class="hljs-built_in">--data-raw</span> <span class="hljs-string">''</span></pre></div><blockquote id="4e1a"><p>Once again, we are not controlling id, body requests and others. The main purpose of this article is connect a controller, services and database into the routes and not to implement Business Rules.</p></blockquote><p id="48d5">That’s all for this article. The final version of this article as a code can be found <a href="https://github.com/makinhs/expressjs-api-tutorial/tree/005-configurando-service">here</a>.</p><p id="7bde">At our next article we are going to introduce the <b>Middlewares </b>concept to the users routes and implement some basic business rules and usages of things that should happen before the controller is used. Have fun coding ;)</p><p id="d70b">Thanks for reading and see you at the <a href="https://readmedium.com/another-expressjs-api-tutorial-for-2020-part-06-middlewares-5b7102e58179">next article</a>!</p><div id="26f6" class="link-block"> <a href="https://readmedium.com/another-expressjs-api-tutorial-for-2020-part-06-middlewares-5b7102e58179"> <div> <div> <h2>Another ExpressJS API tutorial for 2020, part 06 — Middlewares</h2> <div><h3>We are finally reaching the half of the series of articles about how to develop an API using ExpressJS and Typescript…</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*eWYm3Dm7s0t8lLWYRW4pow.jpeg)"></div> </div> </div> </a> </div><p id="5a00">tips:</p><ul><li>the full code of this article is <a href="https://github.com/makinhs/expressjs-api-tutorial/tree/005-configurando-service">HERE</a></li><li>don’t forget to use a nice app to test your API such as <a href="https://www.postman.com/">Postman</a> or <a href="https://insomnia.rest/">Insomnia</a></li><li>I know you still didn’t… Read the ExpressJS <a href="https://expressjs.com/en/4x/api.html">documentation</a>!</li><li>Book suggestion: <a href="https://amzn.to/3dgcWwI">Clean Code</a> and again <a href="https://amzn.to/2WGb1f5">Design Patterns</a></li><li>Brazilian? PT-BR Book suggestion: <a href="https://amzn.to/2wnMel1">Clean Code</a> and <a href="https://amzn.to/2U6uXWI">Design Patterns</a></li><li>Complete project is <a href="https://github.com/makinhs/expressjs-api-tutorial">here</a>! (Includes even the non existing articles yet)</li></ul></article></body>

Another ExpressJS API tutorial for 2021, part 05 — Configuring services

At the part five of this articles we are going to configure services which will communicate between controllers and the database

Hey all, if you are completely lost and arrived here, we are creating a series of small articles to build an API with ExpressJS and this is the part number 5. You can check the first article here.

Just as a quick overview, here is the series of articles that we are writing:

Let’s get started! Last article we’ve created a controllers file that will handle what each configured route should do for an user resource. Now we aim to build services which will communicate with our databases and will be called at our controllers. That way, it will be easier to do code maintenance and, even if we will change the current database to another we will have no hard time on changing the code.

Services can abstract the usage of databases as well as to share common functions that other files might need.

It is also worth to say that all of the architecture of this project is a suggestion but it is not the only way you could do it and you shouldn’t be using it as the ‘master piece of truth’ since every case is a different case and we are dealing with a generic scenario that might work with tons of real life scenarios.

That all said, our Github branch is currently this. To focus only at the services at this point, we are going to add a very simple and temporary database that will be switched to a real one with MongoDB in the late articles.

Let’s create a folder called daos at our users folder and create a file called in.memory.dao.ts. The code will work like the following:

export class GenericInMemoryDao {
    private static instance: GenericInMemoryDao;
    users: any = [];
constructor() {
        console.log('Created new instance of GenericInMemoryDao');
    }
static getInstance(): GenericInMemoryDao {
        if (!GenericInMemoryDao.instance) {
            GenericInMemoryDao.instance = new GenericInMemoryDao();
        }
        return GenericInMemoryDao.instance;
    }
addUser(user: any) {
        return this.users.push(user);
    }
getUsers() {
        return this.users;
    }
getUserById(userId: string) {
        return this.users.find((user: { id: string; }) => user.id === userId);
    }
putUserById(user: any) {
        const objIndex = this.users.findIndex((obj: { id: any; }) => obj.id === user.id);
        const updatedUsers = [
            ...this.users.slice(0, objIndex),
            user,
            ...this.users.slice(objIndex + 1),
        ];
        this.users = updatedUsers;
        return `${user.id} updated via put`;
    }
patchUserById(user: any) {
        const objIndex = this.users.findIndex((obj: { id: any; }) => obj.id === user.id);
        let currentUser = this.users[objIndex];
        for (let i in user) {
            if (i !== 'id') {
                currentUser[i] = user[i];
            }
        }
        this.users = [
            ...this.users.slice(0, objIndex),
            currentUser,
            ...this.users.slice(objIndex + 1),
        ];
        return `${user.id} patched`;
    }
removeUserById(userId: string) {
        const objIndex = this.users.findIndex((obj: { id: any; }) => obj.id === userId);
        this.users = this.users.splice(objIndex, 1);
        return `${userId} removed`;
    }
}

Update 2020–06–01: thanks Matthew for pointing that the splice method was incorrect. Now it’s updated :)

I will not go further to explain the code above since is just to have something to test our services at the end of this article. Remember that in the end of the series of article we are going to be using a real MongoDB with Docker and all the pieces will be connected to have real API working on your computer.

Never use a handmade “in memory” database in a live application, NEVER

Now we can create our services. As for what me made with a daos folder, let’s create a folder called services inside of the users folder and inside of it, create a file called user.services.ts

What we want to create here is an abstraction between a DAO file and the service itself. For abstracting it we are sure that we want the following methods to be always created:

  • list: (limit: number, page: number) => any
  • create: (resource: any) => string
  • updateById: (resourceId: any) => string
  • readById: (resourceId: any) => any
  • deleteById: (resourceId: any) => string
  • patchById: (resourceId: any) => string

We are basically using this pattern to every resource that we will create and instead of creating it directly to the service, we will be using a concept called interface. That will force us to implement these methods into our service and Typescript allows us do use this feature.

For now, let the user.services.ts empty and let’s go to the root folder of the project, and inside of the common folder, let’s create a folder called interfaces and the file called crud.interface.ts. Here is the final code:

export interface CRUD {
    list: (limit: number, page: number) => any,
    create: (resource: any) => string,
    updateById: (resourceId: any) => string,
    readById: (resourceId: any) => any,
    deleteById: (resourceId: any) => string,
    patchById: (resourceId: any) => string,
}

We are just defining here the interface with the methods (functions) that we want to anyone who use this interface to have, setting the parameters and the abstract response. You can read more about interfaces here.

Now we can open the user.services.ts file and add the following:

import {CRUD} from '../../common/interfaces/crud.interface';
import {GenericInMemoryDao} from '../daos/in.memory.dao';
export class UsersService implements CRUD {
    private static instance: UsersService;
    dao: GenericInMemoryDao;
constructor() {
        this.dao = GenericInMemoryDao.getInstance();
    }
static getInstance(): UsersService {
        if (!UsersService.instance) {
            UsersService.instance = new UsersService();
        }
        return UsersService.instance;
    }
create(resource: any) {
        return this.dao.addUser(resource);
    }
deleteById(resourceId: any) {
        return this.dao.removeUserById(resourceId);
    };
list(limit: number, page: number) {
        return this.dao.getUsers();
    };
patchById(resource: any) {
        return this.dao.patchUserById(resource)
    };
readById(resourceId: any) {
        return this.dao.getUserById(resourceId);
    };
updateById(resource: any) {
        return this.dao.putUserById(resource);
    };
}

And that’s it. Our service is now communicating with our generic dao and using all the methods that the CRUD interface is asking to. In the late articles we will go back to this service and change the implementation to use a real MongoDB with Mongoose.

Our service will be handling the calls to the current dao and we will change only this file to switch one database implementation to another one.

The missing cherry of this article is to update the user controller now. Open the user.controllers.ts file and update the code to call our service.

import express from 'express';
import {UsersService} from '../services/user.services';
export class UsersController {
    constructor() {
    }
listUsers(req: express.Request, res: express.Response) {
        const usersService = UsersService.getInstance();
        const users = usersService.list(100, 0);
        res.status(200).send(users);
    }
getUserById(req: express.Request, res: express.Response) {
        const usersService = UsersService.getInstance();
        const user = usersService.readById(req.params.userId);
        res.status(200).send(user);
    }
createUser(req: express.Request, res: express.Response) {
        const usersService = UsersService.getInstance();
        const userId = usersService.create(req.body);
        res.status(201).send({id: userId});
    }
patch(req: express.Request, res: express.Response) {
        const usersService = UsersService.getInstance();
        usersService.patchById(req.body);
        res.status(204).send(``);
    }
put(req: express.Request, res: express.Response) {
        const usersService = UsersService.getInstance();
        usersService.updateById(req.body);
        res.status(204).send(``);
    }
removeUser(req: express.Request, res: express.Response) {
        const usersService = UsersService.getInstance();
        usersService.deleteById(req.params.userId);
        res.status(204).send(``);
    }
}

Look that now we can talk a bit more about our structure:

  • A routes file that is responsible only to define endpoints and who controls it (controllers)
  • A controller file which is responsible to call a service which will do what the route is defined to do and to send a response to the client
  • A service file that is responsible to “talk” to whatever database you might be wanting to use
  • A specific DAO file that could be any database implementation, ORM, ODM, that you might need
  • All of our functions are short and well defined and easy to read

That might be a bit of too much abstraction but once you start to have a huge project with hundreds of resources, services, then all of this breakdown strategy starts to easy it up your and your co-workers life. Again, its not a final strategy but one of several that I found useful in my working career so far.

If you will run npm start now you will be able to call your API requests with Postman or Insomnia and play with it. Remember that we are not controlling any type of request and every time you will restart the API all the data will be gone. But we have enough to test the routes, controllers and services with more useful data now.

Here are some requests CURL samples:

Create a new user:

curl --location --request POST 'localhost:3000/users' \
--header 'Content-Type: application/json' \
--data-raw '{
 "username":"mytestingUser",
 "password":"amazingMediumArticle"
}'

List users:

curl --location --request GET 'localhost:3000/users' \
--header 'Content-Type: application/json' \

Patch an user:

curl --location --request PATCH 'localhost:3000/users/3' \
--header 'Content-Type: application/json' \
--data-raw '{
 "username":"mytestingUser2",
 "password":"amazingMediumArticle",
 "id":3
}'

Put an user:

curl --location --request PUT 'localhost:3000/users/3' \
--header 'Content-Type: application/json' \
--data-raw '{
 "username":"mytestingUser2",
 "password":"amazingMediumArticle4",
 "id":3
}'

Delete an user:

curl --location --request DELETE 'localhost:3000/users/3' \
--header 'Content-Type: application/json' \
--data-raw ''

Once again, we are not controlling id, body requests and others. The main purpose of this article is connect a controller, services and database into the routes and not to implement Business Rules.

That’s all for this article. The final version of this article as a code can be found here.

At our next article we are going to introduce the Middlewares concept to the users routes and implement some basic business rules and usages of things that should happen before the controller is used. Have fun coding ;)

Thanks for reading and see you at the next article!

tips:

Expressjs
Nodejs
Api Development
Software Engineering
Tutorial
Recommended from ReadMedium