dcsimg
March 3, 2021
Hot Topics:

Creating an API with Deno

  • By Diogo Souza
  • Send Email »
  • More Articles »

Deno has caught the attention of the JavaScript community by offering some disruptive ways to deal with backend application development in JavaScript.

After getting started with the basics, it's time to see Deno in action. In this tutorial, we're going to check Deno's power in practice through the development of a REST API from scratch.

As a prerequisite, you'll need to have Deno installed already. For this, follow the instructions from the previous tutorial.

Project Setup

For this tutorial, we'll be using Visual Studio Code as the IDE to support the coding. To give you a different taste in terms of TypeScript capabilities, that's going to be the language of choice, although you can easily convert it to JavaScript if you want.

The Oak framework is the choice to inject the proper middleware for HTTP server capabilities.

First, let's create the TypeScript file responsible for the controllers, the structures that will receive the requests, process them, and return the responses.

For this, create a new file called controller.ts and add the following content to it:

interface ITask {
  id: string;
  name: string;
  description: string;
}

let taskList: Array = [
  {
    id: "1",
    name: "Walk the dog",
    description: "From 7am - 8am",
  },
  {
    id: "2",
    name: "Finish work",
    description: "Send email to Sandra",
  },
  {
    id: "3",
    name: "Laundry",
    description: "At 9pm with Henry",
  },
];

const getTasks = ({ response }: { response: any }) => {
  response.body = taskList;
};

const getTask = ({
  params,
  response,
}: {
  params: { id: string };
  response: any;
}) => {
  const Task: ITask | undefined = searchTaskByid(params.id);
  if (Task) {
    response.status = 200;
    response.body = Task;
  } else {
    response.status = 404;
    response.body = { message: `Task not found.` };
  }
};

const addTask = async ({
  request,
  response,
}: {
  request: any;
  response: any;
}) => {
  const task: ITask = await request.body().value;
  
  taskList.push(task);
  response.body = { message: "Success" };
  response.status = 200;
};

const updateTask = async ({
  params,
  request,
  response,
}: {
  params: { id: string };
  request: any;
  response: any;
}) => {
  let task: ITask | undefined = searchTaskByid(params.id);
  if (task) {
    const updateInfos: { name?: string; description?: string } = request.body().value;
    task = { ...task, ...updateInfos };
    taskList = [...taskList.filter((Task) => Task.id !== params.id), task];
    response.status = 200;
    response.body = { message: "Success" };
  } else {
    response.status = 404;
    response.body = { message: "Task not found" };
  }
};

const deleteTask = ({
  params,
  response,
}: {
  params: { id: string };
  response: any;
}) => {
  taskList = taskList.filter((Task) => Task.id !== params.id);
  response.body = { message: "Success" };
  response.status = 200;
};

const searchTaskByid = (id: string): ITask | undefined =>
  taskList.filter((Task) => Task.id === id)[0];

export { getTasks, getTask, addTask, updateTask, deleteTask };

If you're not used to TypeScript, this code listing may feel a bit different. That's due to the strongly typed nature of TypeScript.

The first line starts with an interface, which is a great way to establish boundaries for your objects. We're creating an ITask interface to define the attributes common to any other task. Each attribute has also a type that you may obey from thereon.

The taskList object will be our in-memory database for the sake of simplicity.

The rest of the list shows each of the CRUD operations to add, update and delete task items. There's nothing uncommon with them, just regular TypeScript CRUD code.

Next, we need to route each of these CRUD methods to their corresponding REST operations. For this, a new file called router.ts may be created in the same folder.

Add the following content into it:

import { Router } from "https://deno.land/x/oak/mod.ts";
import {
  getTasks,
  getTask,
  addTask,
  updateTask,
  deleteTask,
} from "./controller.ts";

const router = new Router();
router
  .get("/tasks", getTasks)
  .get("/tasks/:id", getTask)
  .post("/tasks", addTask)
  .put("/tasks/:id", updateTask)
  .delete("/tasks/:id", deleteTask);

export default router;

This file is pretty simple. It basically maps each of the methods to its respective endpoints and HTTP methods.

The more controllers you add to your application, the more mappings this (or other routing files) will have to be added as well.

Finally, let's go to the main file of the application, which will be the starting point to run the API. Create a new file index.ts and give it the following content:

import { Application } from "https://deno.land/x/oak/mod.ts";
import router from "./router.ts";

const app = new Application();

app.use(router.routes());
app.use(router.allowedMethods());

const PORT = 8080;
console.log(`Listening on port ${PORT} ...`);
await app.listen(`127.0.0.1:${PORT}`);

You can see at the first line that we're importing Oak's Application object. This is the starting point of any Deno web application using the Oak framework.

The routers come right after. To have it running, simply create a new Application, map the routes to its use method and call the listen method to start it up.

Testing

To test it you'd do as any other REST API. We're going to pick Postman as the testing tool since it's flexible and easy to use.

With Postman open, you may retrieve the list of tasks as shown in the figure below:

Retrieving the list of tasks

To add a new task, change the HTTP method to POST and add the following content to the body:

{
    "name": "Testing Task",
    "description": "Testing description"
}

Use the image below to guide yourself:

Adding a new task

Conclusion

Simple, isn't it? That's the real goal of Deno - to be fast and productive. Go ahead and make sure to test the other flows.

Comment below on what you thought of building APIs with Deno. Let's catch up!

 





This article was originally published on February 13, 2021

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.


Thanks for your registration, follow us on our social networks to keep up-to-date