Skip to main content

Create REST API using deno

Deno, the creation of Ryan Dahl is a simple, modern, and secure runtime for JavaScript and TypeScript that uses V8 and is built in Rust. As Deno 1.0.0 has released, there is much-awaited curiosity amongst developers around working with this new stack.

When it comes to learning a new language, the first thing that comes to our mind is the creation of a todo app, supporting CRUD functionality. So here we will be creating a very simple Todo application using the Deno.

So before starting I assume you have installed Deno on your system, if not then you can find the link here. For the database, we will be using the JSON file as of now to completely focus on creating web API using Deno. Not more words and now let's start.

The file structure we are going to follow is as below

  // Final directory structure
  deno-todo-api/
    --|controllers/
      |--|todo.ts
      |data/
      |--|todos.ts
      |interfaces/
      |--|Todo.ts
      |routes/
      |--|todo.ts
    --|server.ts
  

At any point in time, if you are stuck somewhere, you can follow this link to get the complete code.

  1. Create a directory named deno-todo-api and move into that directory
  mkdir deno-todo-api && cd deno-todo-api
  1. Create the file server.ts in the root of the directory.
  2. Write the following code into the server.ts file to start a server
import { Application, Router } from "https://deno.land/x/oak/mod.ts";

const app = new Application();
const port: number = 8080;

const router = new Router();
router.get("/", ({ response }: { response: any }) => {
  response.body = {
    message: "Rest API tutorial with Deno",
  };
});
app.use(router.routes());
app.use(router.allowedMethods());

console.log('running on port ', port);
await app.listen({ port });

Unlike NodeJS Deno does not need the package.json file for dependency management. Dependency management is simplified by having a list of modules and their respective URLs.

Here we have used oak, a middleware framework for Deno's HTTP server, including a router middleware.

  1. server.ts is the entry point for our web application. To check it run the following command in the root directory
deno run --allow-net server.ts

Open the browser and hit the URL localhost:8080

You can see the following output in your browser

Browser output

  1. Now following the directory structure, we will create following folders in our project with the help of below command
mkdir controllers data interfaces routes
  1. First of all, we will create dummy data to play with our todo APIs.Go to the data folder and create a file called todos.ts and the following code into it
import { v4 } from "https://deno.land/std/uuid/mod.ts";
// interface
import Todo from '../interfaces/Todo.ts';

let todos: Todo[] = [
  {
    id: v4.generate(),
    task: 'Hello world app with Deno',
    done: true,
  },
  {
    id: v4.generate(),
    task: 'Simple Rest API with Deno',
    done: false,
  },
];

export default todos;

We will be using v4 provided by the uuid module to generate unique IDs.

  1. Now create a file in interface/ folder Todo.ts and paste the following code.
export default interface Todo {
  id: string,
  task: string,
  done: boolean,
}

What are the interfaces??

An interface defines the specifications of an entity.

One of TypeScript’s core principles is that type checking focuses on the shape that values have. In TypeScript, interfaces fill the role of naming these types and are a powerful way of defining contracts within your code as well as contracts with code outside of your project.

  1. Now create a file named todo.ts in controllers/ directory and paste the following code
import { v4 } from "https://deno.land/std/uuid/mod.ts";
// interfaces
import Todo from "../interfaces/Todo.ts";
// stubs
import todos from "../data/todos.ts";

export default {
  getAll: ({ response }: { response: any }) => {
    response.status = 200;
    response.body = {
      data: todos
    };
  },
  create: async (
    { request, response }: { request: any; response: any },
  ) => {
    const body = await request.body();
    if (!request.hasBody) {
      response.status = 400;
      response.body = {
        message: "Please provide the task detail and  status",
      };
      return;
    }
    let newTodo: Todo = {
      id: v4.generate(),
      task: body.value.todo,
      done: false,
    };
    let data = [...todos, newTodo];
    response.body = {
      data
    };
  },
  getById: (
    { params, response }: { params: { id: string }; response: any },
  ) => {
    const todo: Todo | undefined = todos.find((t) => {
      return t.id === params.id;
    });
    if (!todo) {
      response.status = 404;
      response.body = {
        message: "No task found related to given ID",
      };
      return;
    }
    response.status = 200;
    response.body = {
      data: todo
    };
  },
  update: async (
    { params, request, response }: {
      params: { id: string },
      request: any,
      response: any,
    },
  ) => {
    const todo: Todo | undefined = todos.find((t) => t.id === params.id);
    if (!todo) {
      response.status = 404;
      response.body = {
        message: "No todo found",
      };
      return;
    }

    const body = await request.body();
    const updatedData: { task?: string; done?: boolean } = body.value;

    let newTodos = todos.map((t) => {
      return t.id === params.id ? { ...t, ...updatedData } : t;
    });
    response.status = 200;
    response.body = {
      data: newTodos,
    };
  },
  delete: (
    { params, response }: { params: { id: string }; response: any },
  ) => {
    const allTodos = todos.filter((t) => t.id !== params.id);

    response.status = 200;
    response.body = {
      data: allTodos,
    };
  },
};
  1. Now go to routes and create todo.ts file in it and paste the following code
import { Router } from "https://deno.land/x/oak/mod.ts";

const router = new Router();
// controller
import todoController from "../controllers/todo.ts";

router
  .get("/todos", todoController.getAll)
  .post("/todos", todoController.create)
  .get("/todos/:id", todoController.getById)
  .put("/todos/:id", todoController.update)
  .delete("/todos/:id", todoController.delete);

export default router;
  1. Now since we have created the complete MVC project for our todo APIs, we will be going to update our main server.ts file with following code
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
import todoRouter from "./routes/todo.ts"; // added the router call

const app = new Application();
const port: number = 8080;

app.use(todoRouter.routes()); // Intitialize the router with our application. 
app.use(todoRouter.allowedMethods());

app.addEventListener("listen", ({ secure, hostname, port }) => {
  const protocol = secure ? "https://" : "http://";
  const url = `${protocol}${hostname ?? "localhost"}:${port}`;
  console.log(`Listening on: ${port}`);
});

await app.listen({ port });
  1. Now run again the server with the following command
deno run --allow-net server.ts

Now open the postman and hit the get URL http://localhost:8080/todos/

Browser output

To check the getByID router, copy the ID of any task and hit the URL like

http://localhost:8080/todos/:id

You will be getting output like below

{
    "data": {
        "id": "eeacacdc-e55b-4299-aab7-5f631a2e3975",
        "task": "Hello world app with Deno",
        "done": true
    }
}

Similarly, we can verify the complete crud API created. Below is the reference of all APIs created in the blog post

APIMethodDescription
http://localhost:8080/todos/GETFetch All todos
http://localhost:8080/todos/{id}GETFetch todo by ID
http://localhost:8080/todos/POSTCreate New todo
http://localhost:8080/todos/{id}PUTUpdate todo by ID
http://localhost:8080/todos/{id}DELETEDelete todo by ID

Comments

Popular posts from this blog

How to use Ngx-Charts in Angular ?

Charts helps us to visualize large amount of data in an easy to understand and interactive way. This helps businesses to grow more by taking important decisions from the data. For example, e-commerce can have charts or reports for product sales, with various categories like product type, year, etc. In angular, we have various charting libraries to create charts.  Ngx-charts  is one of them. Check out the list of  best angular chart libraries .  In this article, we will see data visualization with ngx-charts and how to use ngx-charts in angular application ? We will see, How to install ngx-charts in angular ? Create a vertical bar chart Create a pie chart, advanced pie chart and pie chart grid Introduction ngx-charts  is an open-source and declarative charting framework for angular2+. It is maintained by  Swimlane . It is using Angular to render and animate the SVG elements with all of its binding and speed goodness and uses d3 for the excellent math functio...

Understand Angular’s forRoot and forChild

  forRoot   /   forChild   is a pattern for singleton services that most of us know from routing. Routing is actually the main use case for it and as it is not commonly used outside of it, I wouldn’t be surprised if most Angular developers haven’t given it a second thought. However, as the official Angular documentation puts it: “Understanding how  forRoot()  works to make sure a service is a singleton will inform your development at a deeper level.” So let’s go. Providers & Injectors Angular comes with a dependency injection (DI) mechanism. When a component depends on a service, you don’t manually create an instance of the service. You  inject  the service and the dependency injection system takes care of providing an instance. import { Component, OnInit } from '@angular/core'; import { TestService } from 'src/app/services/test.service'; @Component({ selector: 'app-test', templateUrl: './test.component.html', styleUrls: ['./test.compon...

How to solve Puppeteer TimeoutError: Navigation timeout of 30000 ms exceeded

During the automation of multiple tasks on my job and personal projects, i decided to move on  Puppeteer  instead of the old school PhantomJS. One of the most usual problems with pages that contain a lot of content, because of the ads, images etc. is the load time, an exception is thrown (specifically the TimeoutError) after a page takes more than 30000ms (30 seconds) to load totally. To solve this problem, you will have 2 options, either to increase this timeout in the configuration or remove it at all. Personally, i prefer to remove the limit as i know that the pages that i work with will end up loading someday. In this article, i'll explain you briefly 2 ways to bypass this limitation. A. Globally on the tab The option that i prefer, as i browse multiple pages in the same tab, is to remove the timeout limit on the tab that i use to browse. For example, to remove the limit you should add: await page . setDefaultNavigationTimeout ( 0 ) ;  COPY SNIPPET The setDefaultNav...