REST API with Deno

Hasitha Chandula
Analytics Vidhya
Published in
7 min readMar 17, 2020

--

What is Deno, and what are its main features?

Deno is a runtime for JavaScript and TypeScript that is based on the V8 JavaScript engine and the Rust programming language. It was created by Ryan Dahl, the original creator of Node. js, and is focused on security and productivity.

It was built with:

  • Rust (Deno’s core was written in Rust, Node’s in C++)
  • Tokio (the event loop written in Rust)
  • TypeScript (Deno supports both JavaScript and TypeScript out of the box)
  • V8 (Google’s JavaScript runtime used in Chrome and Node, among others)

Still, Deno is under development and it has lots of bugs. But we can build simple REST API Using Deno. And also there are no node_modules in the Deno project.

Here I’m going to show you how to build a simple REST API with CRUD operations with Deno. I'm Not going to use any database and all data store in JSON file.

First of all, we need to install Deno on our computer. you can do that by referring https://deno.land/ according to your operating system.

In windows open the power shell and copy and paste this

iwr https://deno.land/x/install/install.ps1 -useb | iex

command and press enter (it will take some time )

Folder and files Structure

Since there is no node_modules in Deno we need to import Libraries and dependencies from the internet.

Let's build our REST API (Ignore red underlines in screenshots, I did not install Deno extensions in vs code)

First, we create our main file (index.ts)

// oak is pretty much similar to express in nodejs
import { Application } from “https://deno.land/x/oak/mod.ts";
// Import App host and Port from config file
import { APP_HOST, APP_PORT } from “./config/config.ts”;
// Import router from routes file
import router from ‘./routes/routes.ts’;
// Create Application Like Express
const app = new Application()
// Add Routes
app.use(router.routes())
app.use(router.allowedMethods())
// Display App running
console.log(`App Started at Port ${APP_PORT}`)
await app.listen(`${APP_HOST}:${APP_PORT}`)

config/config.ts file

const env = Deno.env();export const APP_HOST = env.APP_HOST || "127.0.0.1";export const APP_PORT = env.APP_PORT || 5000;export const DB_PATH = env.DB_PATH || "./db/todos.json";

models/todos.ts file

export default interface ToDos {   id: string;   title: string;   description: string;}

routes/routes.ts file

import { Router } from "https://deno.land/x/oak/mod.ts";import getTodos from './todos/getTodos.ts';import getTodo from './todos/getTodo.ts';import addTodo from './todos/addTodos.ts';import deleteTodo from './todos/deleteTodo.ts';import editTodo from './todos/editTodo.ts';
const router = new Router()router.get('/todos', getTodos)
router.get('/todo/:id', getTodo)router.post('/addTodo', addTodo)router.put('/editTodo/:id', editTodo)router.delete('/deleteTodo/:id', deleteTodo)export default router;

db/todos.json file

[{"id":"010fbf79-048e-4508-ac65-5c8b326aa026","title":"Learn TypeScript","description":"TypeScript is typed version of JavaScript"},{"id":"38bd9aad-4047-47e1-b879-7a9ab77761c5","title":"Learn React","description":"React is a Front-End web Library"},{"id":"81ded252-661c-4fb1-a1e0-aad717b84891","title":"Learn Deno","description":"Deno is the next version of nodejs"}]

db/db.ts (Where we add and get data from todos.json file) file

import { DB_PATH } from '../config/config.ts';import ToDos from '../models/todos.ts';export const getTodosFromJson: () => Promise<ToDos[]> = async () =>{try {// Read Files In Deno
const data: any = await Deno.readFile(DB_PATH);
// Decode Data From File
const decode = new TextDecoder()
const decodedData = decode.decode(data)return JSON.parse(decodedData)} catch (err) {console.error(err.message);}}export const writeDataToJson: (todos: ToDos[]) => Promise<void> = async (todos: ToDos[]): Promise<void> => {try {// encode Jsonconst encode = new TextEncoder();// Write Files in Denoawait Deno.writeFile(DB_PATH, encode.encode(JSON.stringify(todos)))} catch (err) {console.error(err.message);}}

routes/todos/getTodos.ts file

import { Response } from "https://deno.land/x/oak/mod.ts";import ToDos from '../../models/todos.ts';import id from '../../services/createIds.ts'import { getTodosFromJson } from '../../db/db.ts';const getTodos = async ({ response }: { response: Response }) => {try {const todos: ToDos[] = await getTodosFromJson()response.body = todos;} catch (err) {console.error(err.message);}}export default getTodos

routes/todos/getTodo.ts file

import { Response } from "https://deno.land/x/oak/mod.ts";import { getTodosFromJson } from '../../db/db.ts';const getTodo = async ({ params, response }: { params: any, response: Response }) => {const id = params?.idif (!id) {response.status = 400;response.body = { msg: 'Invalid Id' }}const todos = await getTodosFromJson()const todo = todos.find(todo => todo.id === id)if (!todo) {response.status = 404;response.body = { msg: `No Todo Found on ${id}` }return;}response.status = 200;response.body = todo;}export default getTodo

routes/todos/addTodos.ts file

import { Request, Response } from "https://deno.land/x/oak/mod.ts";import { v4 as uuid } from "https://deno.land/std/uuid/mod.ts";import ToDos from '../../models/todos.ts';import { writeDataToJson, getTodosFromJson } from '../../db/db.ts';const addTodo = async ({ request, response }: { request: Request, response: Response }) => {// Check Request Has a body or notif (!request.hasBody) {response.status = 400;response.body = { msg: "Invalid data, Please Add Title and Description" };return;}// Get Title and description from Requestconst {value: { title, description }} = await request.body();// Check title and description is validif (!title || !description) {response.status = 422;response.body = { msg: "Title and Description is required" };return;}// Create New Todoconst newTodo: ToDos = { id: uuid.generate(), title, description }// Get All Todoslet allTodos: ToDos[] = await getTodosFromJson()// Add New Todo to allTodos ArrayallTodos = [newTodo, ...allTodos]// Save Data In ToDos.json Fileawait writeDataToJson(allTodos)// Response To the Clientresponse.body = { msg: "New Todo Created", newTodo };};export default addTodo

routes/todos/editTodo.ts file

import { Response, Request } from "https://deno.land/x/oak/mod.ts";import { getTodosFromJson, writeDataToJson } from '../../db/db.ts';import ToDos from '../../models/todos.ts';const editTodo = async ({ params, request, response }: { params: any, request: Request, response: Response }): Promise<void> => {try {// Save todo id to a variableconst id = params.id;// Check Request Has a body or notif (!request.hasBody) {response.status = 400;response.body = { msg: "Invalid data, Please Add Title and Description" };return;}// Get Title and description from Requestconst {value: { title, description }} = await request.body();// Check title and description is validif (!title || !description) {response.status = 422;response.body = { msg: "Title and Description is required" };return;}// Get All Todos From Json File And Save it in to a Variablelet allTodos: ToDos[] = await getTodosFromJson();// Check if todo is here in that Id sent by clientconst todo: ToDos | undefined = allTodos.find((todo: ToDos) => todo.id === id)// check todo is undefined, if so then response 404if (!todo) {response.status = 404;response.body = { msg: `No Todo Found on this ${id} id` }return;}//    Add New Title And Description to Old Onetodo.title = title;todo.description = description;await writeDataToJson(allTodos)response.status = 200;response.body = { msg: "Todo has been Edited", todo }} catch (err) {console.error(err.message);}}export default editTodo;

routes/todos/deleteTodo.ts file

import { Response } from "https://deno.land/x/oak/mod.ts";import { getTodosFromJson, writeDataToJson } from '../../db/db.ts';import ToDos from '../../models/todos.ts';const deleteTodo = async ({ params, response }: { params: any, response: Response }): Promise<void> => {try {// Save todo id to a variableconst id = params.id;// Get All Todos From Json File And Save it in to a Variablelet allTodos = await getTodosFromJson();// Check if todo is here in that Id sent by clientconst index = allTodos.findIndex((todo: ToDos) => todo.id === id)// if todo is here index > 0// if todo is not here index = -1// check index < 0, if so then response 404if (index < 0) {response.status = 404;response.body = { msg: `No Todo Found on this ${id} id` }return;}// if index > 0 then filter the array and delete todo and saveallTodos = allTodos.filter((todo: ToDos) => todo.id !== id)await writeDataToJson(allTodos)response.status = 200;response.body = { msg: "Todo has been Deleted" }} catch (err) {console.error(err.message);}}export default deleteTodo;

Now Our Simple REST API if finished. to run server all we need to do is open the cmd or terminal in that project folder and run

deno run --allow-all index.ts

yot will get a message like this. now You can test your REST API using a tool like postman.

Github repo:- https://github.com/Hasi6/REST-API-Using-Deno

That’s it Happy Coding. Thank You.

--

--

Hasitha Chandula
Analytics Vidhya

Senior Full Stack Engineer specializing in TypeScript & Go. I create scalable web apps, love learning new tech, and thrive on teamwork.