Building a RESTful API With Deno, Oak and MongoDB



Hello! My name's Khanh. In this post. We will build a RESTful CRUD API with Deno, MongoDB, Oak Framework.

1. Program structure



common: contains file connect db.
controllers: the controllers handles all the logic behind validating request parameters, query, sending responses with correct codes.
models: contain model definitions.
routes: the API routes maps to the controllers.
service: the services contains the database queries and returning objects or throwing errors.

2. Third party modules.

We will create a server application in Deno using the oak and deno_mongo.

Oak: https://deno.land/x/oak

Deno_mongo: https://deno.land/x/mongo

3. Create file .env


- We define the port number in which the server is listening and database name.

4. Create file connect database

    common/DataConnection.ts



5. Create file server
    
    


6. Create file user model

   models/user.ts



7. Create file contain query data ( folder service )

    service/user.ts

import DB from "../common/DataConnection.ts"; import { User } from "../models/user.ts";

type UserData = Pick<User"username" | "password" | "address" | "isAdmin">;

// Create user
const insertUser = async (data: UserData): Promise<User | undefined> => {
  return DB.collection("users").insertOne({
    username: data.username,
    password: data.password,
    address: data.address,
    isAdmin: data.isAdmin || false,
    createdAt: new Date(),
    updatedAt: new Date(),
  });
};

// Get all users
const findAllUser = async (): Promise<User[]> => {
  return DB.collection("users").find();
};

// Get user
const findUser = async (userId: string): Promise<User | undefined> => {
  return DB.collection("users").findOne({ _id: { $oid: userId } });
};

// Update user
const updateOneUser = async (
  userId: string,
  UserData: UserData,
): Promise<void=> {
  DB.collection("users").updateOne(
    { _id: { $oid: userId } },
    {
      $set: {
        username: UserData.username,
        password: UserData.password,
        address: UserData.address,
        isAdmin: UserData.isAdmin,
        updatedAt: new Date(),
      },
    },
  );
};

// Delete user
const deleteOneUser = async (userId: string): Promise<void=> {
  DB.collection("users").deleteOne({ _id: { $oid: userId } });
};

export {
  insertUser,
  findAllUser,
  findUser,
  updateOneUser,
  deleteOneUser,
};

8. Create file in controllers
 
controllers/user.ts

We have 5 controllers for this project: 
create (POST): adding a user to the database.
getUsers (GET): get all user in database.
getUser (GET): get the user data for the specified id. 
updateUser (PUT): to update info user of a user for the given id. 
deleteUser (DELETE): to delete a user using the id.

import {
  insertUser,
  findAllUser,
  findUser,
  updateOneUser,
  deleteOneUser,
from "../service/user.ts";

// Create a User
const createUser = async (
  { requestresponse }: { request: anyresponse: any },
=> {
  if (!request.hasBody) {
    response.status = 400;
    response.body = { msg: "Invalid user data" };
    return;
  }
  const {
    value: { usernamepasswordaddressisAdmin },
  } = await request.body();

  if (!username || !password) {
    response.status = 422;
    response.body = {
      msg: "Incorrect user data. username and password are required",
    };
    return;
  }
  let user = await insertUser({ usernamepasswordaddressisAdmin });
  response.status = 201;
  response.body = { msg: "User created"user };
};

// Get all user
const getUsers = async ({ response }: { response: any }) => {
  const users = await findAllUser();
  response.status = 200;
  response.body = {success: true, data: users};
};

// Get user
const getUser = async (
  { paramsresponse }: { params: { id: string }; response: any },
=> {
  const id = params.id;
  if (!id) {
    response.status = 400;
    response.body = { success: false, error: "Id params is required" };
  }
  const user = await findUser(id);
  if (!user) {
    response.status = 404;
    response.body = {
      success: false,
      error: `User does not exist`,
    };
    return;
  }
  response.status = 200;
  response.body = {success: true, data: user};
};

// Update user
const updateUser = async (
  {params,request,response}: { params: { id: string }; request: anyresponse: any },
=> {
  if (!request.hasBody) {
    response.status = 400;
    response.body = { msg: "Invalid user data" };
    return;
  }
  const {
    value: { usernamepasswordaddressisAdmin },
  } = await request.body();
  const id = params.id;

  const user = await findUser(id);

  if(!user){
    response.status = 404;
    response.body = {
      success: false,
      error: `User not found`,
    };
    return;
  }
  await updateOneUser(id, { usernamepasswordaddressisAdmin } );
  response.status = 200;
  response.body = {success: true, data: user};

}

// Delete user
const deleteUser = async (
  { paramsresponse }: { params: { id: string }; response: any },
=> {
  const id = params.id;
  if (!id) {
    response.status = 400;
    response.body = { success: false, error: "Invalid user id" };
  }

  const user = await findUser(id);

  if (!user) {
    response.status = 404;
    response.body = {
      success: false,
      error: `User not found`,
    };
    return;
  }
  await deleteOneUser(id);
  response.status = 200;
  response.body = { msg: "Delete User Success!" };
};

export { createUser, getUsers, getUser, updateUser, deleteUser };


9. Add routes
   routes/user.ts


Ok. Now we will run the program.
deno run --allow-net --allow-write --allow-read --allow-plugin --unstable server.ts


10. Testing with Postman

I will test it with some API.






Thank you for reading. What's wrong with my post, everyone can comment. Thanks






Previous Post
Next Post

post written by:

0 Comment: