Building ES6 CRUD API with Nodejs, Expressjs and babel-register

It is very hard to find written tutorials on how to make an api with es6 nodejs and express with js data structures.And that is why i have decided to put this together with the hope that it will help someone in the future, as i have myself struggled before when i wanted to specifically use es6 data structures to build an api but couldn’t find a medium post about it :).
CRUD stands for Create, Read, Update, and Delete, In this tutorial, you’ll learn how to build a simple CRUD blog API with Nodejs using ES6. What is Nodejs ?,Node.js is an open-source, cross-platform JavaScript run-time environment that executes JavaScript code outside the browser. It is a javascript runtime built on Chrome V8 Javascript Engine. Simply put Nodejs give us the ability to write backend code in Javascript.

What we are going to build?

You are going to learn how to build a simple blog API — A blog api will give users the ability to add posts with title and body, view all posts, edit a single post and delete a post.

Setting Up

If you don’t have Node installed on your system, see here
Create a new directory,runnpm init, and follow along with the prompts, giving your app the name of your preference.
npm init
After that is done, now your package.json should look more like this
{  "name": "blog",  "version": "1.0.0",  "description": "a simple blog api",  "main": "server.js",  "scripts": {  },  "author": "Igwaneza Bruce",  "license": "MIT",}
Next, let’s install all the package dependencies that we’ll need to build the project
. expressjs : Expressjs is a nodejs web application framework that gives us the ability to create quick and easy APIs.
. babeljs : Since we’ll be writing all our JavaScript code using ES6, babeljs will help in transpiling our ES6 codes to ES2015, and we will be using babel-register a hook system to compile files on the fly when they are loaded.
. momentjs : This gives us the ability to add time on our posts.
nodemon : This monitors for any changes in your node.js application and automatically restart the server
Run the following command to install all the above packages:
$ npm install --save express moment$npm install --save-dev babel-cli babel-preset-env nodemon
If all went well, you should see something similar to this in your package.json file:
"author": "Igwaneza Bruce","license": "MIT","devDependencies": {  "babel-cli": "^6.26.0",  "babel-preset-env": "^1.7.0",  "nodemon": "^1.18.5"},"dependencies": {  "express": "^4.16.4",  "moment": "^2.22.2"}
You’ll notice that express and moment is under dependencies, that is because those are needed by the time we deploy our code to production. babel-cli, babel-preset-env and nodemonare only needed during development.
You should also see a new folder called node_modules in the project root directory - This folder contains the source code of the package we downloaded.
Our Server
Let’s start by importing all dependencies, create a folder call it src and inside create a file and call it server.js.
import express from "express";const app = express();app.use(express.json());app.listen(process.env.PORT || 5000);export default app;
From the code above, we imported express and set up a new express instance const app = express(). We set up a new express.json() middleware - this is needed to get access to request body.
Note: express.json() is only available in express version 4.16.0 and above
If you run the server using node server.js command, you'll get an error and that is ok,because nodejs runtime cannot understand some of the ES6 features we used — e.g import. In the next section we will set up babel - babel will help us compile the code to ES5 that nodejs runtime can understand.

Configure babel

In the project root directory, create a new file and name it .babelrc and add
{
  "presets":["babel-preset-env"]
}
Inside the root directory create a folder and call it db (stands for database), inside db folder create a file and call it posts.js

Set up database

now add the following code inside posts.js
const posts = [];
export default posts;
From the above code, we are defining our posts data structure(Array of data) and simply exporting it,as we are going to need it in our post controller.

Set up controller

Inside root directory now create a controllers folder and create postController.js file inside controllers folder.now add the following code inside postController.js
import Posts from "../db/posts";
import moment from "moment";class postsController {
  static getPosts(req, res) {
    return res.json({
      message: "List of all posts",
      posts: Posts
    });
  }static createPost(req, res) {
    const newId = parseInt(Posts.length) + 1;
    const { title, body } = req.body;
    const newPost = {
      id: newId,
      title,
      body,
      created_at: moment.utc().format()
    };
    Posts.push(newPost);
    return res.status(200).json({
      message: "created a new post"
    });
  }static getOnePost(req, res) {
    const { id } = req.params;
    const post = Posts.find(onePost => onePost.id == id);
    if (post) {
      return res.status(200).json({
        message: "one post found",
        onePost: post
      });
    } else {
      res.status(400).json({
        error: "no post found with that id"
      });
    }
  }
  static updatePost(req, res) {
    const { id } = req.params;
    const post = Posts.find(updatePost => updatePost.id == id);
    if (post) {
      (post.title = req.body.title), (post.body = req.body.body);
      return res.status(201).json({
        message: "successfully updated",
        updatePost: post
      });
    } else {
      res.status(400).json({
        error: "post cannot be updated"
      });
    }
  }
  static deletePost(req, res) {
    let { id } = req.params;
    const findPost = Posts.find(post => {
      return post.id == id;
    });
    if (findPost) {
      const newPosts = Posts.filter(post => {
        return post !== findPost;
      });
      res.status(200).json({
        message: "post successfully deleted",
        Posts: newPosts
      });
    } else {
      res.status(400).json({
        error: "could not delete a post"
      });
    }
  }
}export default postsController;
In above code we have imported our posts db and created Post class that contains getPosts - to list all posts, createPost - create a new post, getOnePost - get one post, updatePost - update a post and deletePost - delete a post.Also we have used our moment npm package to give created_at property to our newly created posts.
Next up, we are going to set up our endpoints, inside our root directory , create routes folder, and inside routes folder create a router file routes.js

Defining Endpoints

The following endpoints will be defined:
  • Create a Post— POST /api/v1/posts
Finally, let’s define our endpoints, open routes.js and add the following code
import express from "express";
import postController from "../controllers/postController";const router = express.Router();router.get("/api/v1/posts", postController.getPosts);
router.post("/api/v1/posts", postController.createPost);
router.get("/api/v1/posts/:id", postController.getOnePost);
router.put("/api/v1/posts/:id", postController.updatePost);
router.delete("/api/v1/posts/:id", postController.deletePost);export default router;
The above code defines all our five endpoints, each connecting to it’s respective controller method.Now to get it working we need to update our server.js file, so that our server knows about the routes we have defined.
import express from "express";
import router from "../routes/routes";const app = express();
app.use(express.json());app.use(router);app.listen(process.env.PORT || 5000);export default app;
Finally our api is complete, but to make it run, we need to define a command that starts up the server inside our package json file
"scripts":{   "start":"nodemon transpiled/index.js"
},
Yeah , simple right?, that is the only command you need , but wait we don’t have an index.js file in our directory, and where is transpiled comming from?
To end all confusions,remember what i said about babel-register, well you are about to see its magic,and how it transpiles es6 on the fly :)
Now inside our root directory create a folder and call it transpiled,then inside our newly created folder add a new file and call it index.js
Add the following code inside our index.js
require("babel-register");
require("../src/server");
require("..routes/routes");

End Project folder structure

YAY!

That’s it! You have a working ES6 Node API with each of the four major CRUD operations.

Test endpoints with POSTMAN

Use the following command to run the server
$ npm run start

Conclusion

The goal of this tutorial was to give you a degree of familiarity with Express,nodejs and Es6, in another post we will be deploying this on heroku, also you can grab working code on github repo here
Drop your questions and comments. Don’t forget to like this post if you learned one or two things.
PS:This tutorial was inspired by the Andela Developer Challenge which i am currently participating in.

Comments