Developing REST Api using Deno, Oak and MongoDB

Author
April 06, 2022

In this article i will explain you step by step to setup REST Api with deno, oak and mongodb and iam using macOS operating system but procedure is same for Windows and Linux users

Step 1: Install deno

For macOS and Linux user use below command

curl -fsSL https://deno.land/install.sh | sh

For Window user Using Powershell use below command

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

deno

Step 2: Download Visual Studio Code and install extension deno

deno-visual-studio

Step 3: Create app.ts file under root path of your deno project

Advantage of using deno is we don’t need to install packages instead we call standard deno library

Inside your app.ts file copy paste below code this is the main file for your deno rest api

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

import notesRoutes from "./routes/notes.ts";

import { connect } from "./helpers/db.ts";

connect();

const app = new Application();

app.use(async (ctx, next) => {
  console.log("Middleware!");
  await next();
});

app.use(async (ctx, next) => {
  ctx.response.headers.set("Access-Control-Allow-Origin", "*");
  ctx.response.headers.set(
    "Access-Control-Allow-Methods",
    "GET,POST,PUT,DELETE"
  );
  ctx.response.headers.set("Access-Control-Allow-Headers", "Content-Type");
  await next();
});

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

await app.listen({ port: 3000 });

Step 4: Create controllers folder under root path of your project folder and under that folder create notes.ts file

This is the controller file where you will be writing all the logic for GET, POST, PUT , DELETE Rest API methods

Copy paste below code in you controller file

import { ObjectId } from "https://deno.land/x/mongo@v0.29.4/mod.ts";
import { getDb } from "../helpers/db.ts";
import { Notes } from "../interfaces/notes.ts";

export default {
  getAllNotes: async ({ response }: { response: any }) => {
    const notes = await getDb().collection("notes").find({}).toArray();
    response.status = 201;
    response.body = { message: "All Notes!", notes: notes };
  },
  createNotes: async ({
    request,
    response,
  }: {
    request: any;
    response: any;
  }) => {
    const data = await request.body().value;
    const newNotes: Notes = {
      text: data.text,
    };

    await getDb().collection("notes").insertOne(newNotes);
    response.status = 201;
    response.body = { message: "Created notes!", todo: newNotes };
  },
  getById: async ({
    params,
    response,
  }: {
    params: { noteId: string };
    response: any;
  }) => {
    const tid = params.noteId!;
    const notes = await getDb()
      .collection("notes")
      .findOne({ _id: new ObjectId(tid) });
    response.status = 201;
    response.body = { message: "New notes!", notes: notes };
  },
  updateNoteById: async ({
    params,
    request,
    response,
  }: {
    params: { noteId: string };
    request: any;
    response: any;
  }) => {
    const tid = params.noteId!;
    const data = await request.body().value;

    const notes = await getDb()
      .collection("notes")
      .updateOne({ _id: new ObjectId(tid) }, { $set: { text: data.text } });
    response.status = 201;
    response.body = { message: "Updated notes", notes: notes };
  },
  deleteNoteById: async ({
    params,
    response,
  }: {
    params: { noteId: string };
    response: any;
  }) => {
    const tid = params.noteId!;

    const notes = await getDb()
      .collection("notes")
      .deleteOne({ _id: new ObjectId(tid) });

    response.status = 201;
    response.body = { message: "Deleted notes", notes: notes };
  },
};

Step 5: Create interface/types

As we clearly know typescript do check types strictly that is what that advantage we have over using typescript so we need to either create interface or types for defining the types of data we are passing in request and getting in request

Create interfaces folder under root path of your project and inside that folder create notes.ts file and copy paste below code inside notes.ts file

export interface Notes {
  text: string;
}

Step 6: Create routes folder under root path of your project folder and under that folder create notes.ts file

This is the route file for your deno Rest API here you will be defining paths for your UPDATE, DELETE, GET, POST request

Copy paste below code in the file

import { Router } from "https://deno.land/x/oak/mod.ts";
const router = new Router();

import notesController from "../controllers/notes.ts";

router.get("/notes", notesController.getAllNotes);

router.post("/notes", notesController.createNotes);

router.put("/notes/:noteId", notesController.updateNoteById);

router.get("/notes/:noteId", notesController.getById);

router.delete("/notes/:noteId", notesController.deleteNoteById);

export default router;

Step 7: Create MongoDB database configuration file

Create helpers folder under root path of your project inside helpers folder create db.ts file inside db.ts file copy paste below code

import {
  MongoClient,
  Database,
} from "https://deno.land/x/mongo@v0.29.4/mod.ts";

let db: Database;

export async function connect() {
  const client = new MongoClient();
  await client.connect("mongodb://localhost:27017");
  console.log("Database connected");
  db = client.database("notes");
}

export function getDb() {
  return db;
}

Complete folder structure, run the project, test the API

By default deno deosn’t allow permission for anything this is extra feature which deno has introduced so in order to allow permission we need to mention in the command itself

Copy paste below command and run in your terminal by navigating to project folder

deno run --allow-net --allow-read --allow-write app.ts

deno-run

postman-link