Subscribe Now

* You will receive the latest news and updates on your favorite celebrities!

Trending News

Blog Post

Developing REST API with Deno – Part 1
Deno, Web Development

Developing REST API with Deno – Part 1 

The creator of Node JS, Ryan Dahl, brings up a new technology called Deno, which is an improvement to Node JS. Please note that, Node is not dead – and would still be in existence due to its popularity and ecosystem, but Deno is just a superset of Node and brings in better security and integrates typescript on the fly.

In this post, we’ll be create a simple RESTful API

Benefits of Deno

  • No more node_modules, i.e no more, NPM packages or package.json 🙂
  • Runtime for JavaScript and Typescript (Inbuilt)
  • Global await scope
  • Use cache for storing modules globally on your local PC from https://deno.land/x/
  • Built-in Testing
  • Enhanced Security
  • Unique Standard Library
  • Modern JavaScript ( using ES Modules)

Install Deno

Deno ships as a single executable with no dependencies. You can install it using the installers below;

Shell (Mac, Linux):

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

PowerShell (Windows):

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

Homebrew (Mac):

$ brew install deno 

After installing Deno, just run deno in your command prompt.

Incase you come across this error of command not found, find fix below;

Command not found using zsh on Linuz or Kali

Fix zsh: command not found: deno

If you are using Oh My God Sh, then…

$ export PATH="/home/{your username}/.deno/bin:$PATH"
$ source ~/.zshrc  

If you are using Bash, then…

$ export PATH="/home/{your username}/.deno/bin:$PATH"
$ source ~/.bashrc  

Building a Simple Items API

First, I will be using the VScode text editor with a Deno extension, ensure you have it installed. You can find it here Deno by justjavac

Folder Structure

The Folder structure

Setting up the Server

Let’s make a folder and switch into it

$ mkdir deno_artists_api && cd deno_artists_api 

Now create a server.ts file in the root directory and paste the code below;

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

const port = 6000;

const app = new Application();


console.log(`Server is running on port ${port}`);

app.listen({ port });

This will represent our entry to our app. But Deno does not allow a successful startup until the router middleware is added.

Now let’s create a routes.ts file in our root directory to contain our routes

import { Router } from 'https://deno.land/x/oak/mod.ts';

const router = new Router();

export default router;

this above script must be imported into our server.ts file.

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

// Added
import router from './routes.ts';

const port = 6000;
const app = new Application();

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

console.log(`Server is running on port ${port}`);

app.listen({ port });

Okay! so for the run a test, lets add a welcome route to our API

routes.ts file

import { Router } from 'https://deno.land/x/oak/mod.ts';

const router = new Router();

// Added
router.get('/api/v1/welcome', ({ response }: { response: any }) => {
    response.body = {
        success: true,
        message: "Welcome to Artists API"
    }
});

export default router;
$ deno run --allow-net server.ts

Now lets test our API’s first route. Open Postman if you use it

Server running successfully
Here is a successful test of our new API

Adding Controllers

Now, since we are creating minimal CRUD. I will be using music artists for example,

Let’s build our data, we’ll work with an array of data. Create a data.ts and a types.ts file in the root directory for TypeScript interface of our data.

types.ts file

 
export interface Artist {
    id: string;
    name: string;
    genre: string;
    followers: string;
}

Now the data.ts files

import { Artist } from './types.ts'

export let artists: Artist[] = [
    {
        id: '1',
        name: 'Davido',
        genre: 'Afrobeats',
        followers: '20m'
    },
    {
        id: '2',
        name: 'Chris Brown',
        genre: 'Pop',
        followers: '65m'
    },
    {
        id: '3',
        name: 'Wizkid',
        genre: 'Afrobeats',
        followers: '11m'
    },
    {
        id: '4',
        name: 'Tiwa Savage',
        genre: 'Afrobeats',
        followers: '10.5m'
    },
    {
        id: '5',
        name: 'Yemi Alade',
        genre: 'Afrobeats',
        followers: '11m'
    },
    {
        id: '6',
        name: 'Drake',
        genre: 'Hip Hop',
        followers: '70m'
    },
    {
        id: '7',
        name: '6ix9ine',
        genre: 'Hip Hop',
        followers: '68m'
    },
    {
        id: '8',
        name: 'Lil Baby',
        genre: 'Hip Hop',
        followers: '15m'
    },
    {
        id: '9',
        name: 'Summer Walker',
        genre: 'R & B',
        followers: '5m'
    },
    {
        id: '10',
        name: 'Rihanna',
        genre: 'R & B',
        followers: '150m'
    }
]

The script above shows an array of artists with the Type of Artist we created in types.ts

Now let’s create a file in the Controllers folder called artists.ts and add our first function called getArtists().

import { artists } from '../data.ts';
import { Artist } from '../types.ts';

// @desc Get all Artists
// @route GET /api/v1/artists

const getArtists = ( {response }: { response: any }) =>{
    response.body = {
        success: true,
        message: "Artists retrieved successfully",
        data: artists
    }
}

export { getArtists }

 

On routes.ts lets include the route

import { Router } from 'https://deno.land/x/oak/mod.ts';

// Added
import { getArtists } from './controllers/artists.ts'

const router = new Router();

router.get('/api/v1/welcome', ({ response }: { response: any }) => {
    response.body = {
        success: true,
        message: "Welcome to Artists API"
    }
});

//  Added
router.get('/api/v1/artists', getArtists);



export default router;
 

$ deno run --allow-net server.ts
All artists showing on Postman

Getting a Single Artist

Okay, moving on, still on the Controllers/artists.ts file. let get a Single artist

import { artists } from '../data.ts';
import { Artist } from '../types.ts';

// @desc Get all Artists
// @route GET /api/v1/artists
const getArtists = ( {response }: { response: any }) =>{
    response.body = {
        success: true,
        message: "Artists retrieved successfully",
        data: artists
    }
}

// Added

// @desc Get an Artists
// @route GET /api/v1/artists/:id
const getSingleArtist = ({ params, response }: { params: {id: string}, response: any }) =>; {
    const artist: Artist | undefined = artists.find(artist => artist.id === params.id)

    if(artist){
        response.status = 200
        response.body = {
            success: true,
            message: "Artist retrieved successfully",
            data: artist
        }
        }else{
        response.status = 404
        response.body = {
            success: false,
            data: "Artist not found"
        }
        }
}

export { getArtists, getSingleArtist }
 

Lets add the route to our routes.ts

 
import { Router } from 'https://deno.land/x/oak/mod.ts';

// Updated
import { getArtists, getSingleArtist } from './controllers/artists.ts'

const router = new Router();

router.get('/api/v1/welcome', ({ response }: { response: any }) => {
    response.body = {
        success: true,
        message: "Welcome to Artists API"
    }
});

// Updated
router.get('/api/v1/artists', getArtists)
    .get('/api/v1/artists/:id', getSingleArtist);



export default router;

Lets restart our server and test it

$ deno run --allow-net server.ts
Postman result

Adding an Artist

Now, let’s create the function to add an Artist called addArtist() into our artists.ts file in the controller folder.

To generate unique IDs, we’ll use the uuid in the deno Standard Library

 

// Added
import { v4 } from 'https://deno.land/std/uuid/mod.ts'

import { artists } from '../data.ts';
import { Artist } from '../types.ts';

// @desc Get all Artists
// @route GET /api/v1/artists
const getArtists = ( {response }: { response: any }) =>{
    response.body = {
        success: true,
        message: "Artists retrieved successfully",
        data: artists
    }
}

// @desc Get an Artists
// @route GET /api/v1/artists/:id
const getSingleArtist = ({ params, response }: { params: {id: string}, response: any }) => {
    const artist: Artist | undefined = artists.find(artist => artist.id === params.id)

    if(artist){
        response.status = 200
        response.body = {
            success: true,
            message: "Artist retrieved successfully",
            data: artist
        }
        }else{
        response.status = 404
        response.body = {
            success: false,
            data: "Artist not found"
        }
        }
}


// Added

// @desc Add an Artists
// @route POST /api/v1/artists/
const addArtist = async ({ request, response }: {request: any, response: any }) => {
    const body = await request.body()
    if(!request.hasBody){
        response.status = 400;
        response.body = {
            success: false,
            message: "Ensure to enter data"
        }
    }else {
        const artist: Artist = body.value
        artist.id = v4.generate();
        artists.push(artist)
        response.status = 201;
        response.body = {
            success: true,
            message: "Artist added successfully",
            data: artist
        }
    }
}

// Updated
export { getArtists, getSingleArtist, addArtist }

Lets update the route in the routes.ts

 
import { Router } from 'https://deno.land/x/oak/mod.ts';

// Updated
import { getArtists, getSingleArtist, addArtist } from './controllers/artists.ts'

const router = new Router();

router.get('/api/v1/welcome', ({ response }: { response: any }) => {
    response.body = {
        success: true,
        message: "Welcome to Artists API"
    }
});

// Updated
router.get('/api/v1/artists', getArtists)
    .get('/api/v1/artists/:id', getSingleArtist)
    .post('/api/v1/artists', addArtist);



export default router;

Lets restart our server and test it

$ deno run --allow-net server.ts
Result from Postman

Updating an Artist

Let us now add an update function, we’ll call it updateArtist() into our artists.ts file in the controller folder.

import { v4 } from 'https://deno.land/std/uuid/mod.ts'
import { artists } from '../data.ts';
import { Artist } from '../types.ts';

// @desc Get all Artists
// @route GET /api/v1/artists
const getArtists = ( {response }: { response: any }) =>{
    response.body = {
        success: true,
        message: "Artists retrieved successfully",
        data: artists
    }
}

// @desc Get an Artists
// @route GET /api/v1/artists/:id
const getSingleArtist = ({ params, response }: { params: {id: string}, response: any }) => {
    const artist: Artist | undefined = artists.find(artist => artist.id === params.id)

    if(artist){
        response.status = 200
        response.body = {
            success: true,
            message: "Artist retrieved successfully",
            data: artist
        }
        }else{
        response.status = 404
        response.body = {
            success: false,
            data: "Artist not found"
        }
        }
}

// @desc Add an Artists
// @route POST /api/v1/artists/
const addArtist = async ({ request, response }: {request: any, response: any }) => {
    const body = await request.body()
    if(!request.hasBody){
        response.status = 400;
        response.body = {
            success: false,
            message: "Ensure to enter data"
        }
    }else {
        const artist: Artist = body.value
        artist.id = v4.generate();
        artists.push(artist)
        response.status = 201;
        response.body = {
            success: true,
            message: "Artist added successfully",
            data: artist
        }
    }
}

// Added
// @desc update an Artist
// @route PUT /api/v1/artists/:id
const updateArtist = async ({ params, request, response }: { params:{id: string}, request:any, response: any }) => {
    const artist: Artist | undefined = artists.find(artist => artist.id === params.id)

    if (artist) {
        const body = await request.body()
        const updateArtist: {name?: string; genre?: string; followers?:string} = body.value

        const updatedArtists = artists.map(artist => artist.id === params.id ? {...artist, ...updateArtist} : artist)

        response.status = 200;
        response.body = {
            success: true,
            message: "Artist updated successfully",
            data: updatedArtists
        }
    } else {
        response.status = 404
        response.body = {
            success: false,
            message: "Artist not found"
        }
    }
}

// Updated
export { getArtists, getSingleArtist, addArtist, updateArtis }

Lets update the route to our export routes.ts

 
import { Router } from 'https://deno.land/x/oak/mod.ts';

// Updated
import { getArtists, getSingleArtist, addArtist, updateArtist } from './controllers/artists.ts'

const router = new Router();

router.get('/api/v1/welcome', ({ response }: { response: any }) => {
    response.body = {
        success: true,
        message: "Welcome to Artists API"
    }
});

// Updated
router.get('/api/v1/artists', getArtists)
    .get('/api/v1/artists/:id', getSingleArtist)
    .post('/api/v1/artists', addArtist)
    .put('/api/v1/artists/:id', updateArtist);



export default router;

Lets restart our server and test it

$ deno run --allow-net server.ts
We updated Davido’s followers successfully

Deleting an Artist

Let us now add our delete function called deleteArtist() into our artists.ts file in the controller folder.

import { v4 } from 'https://deno.land/std/uuid/mod.ts'
import { artists } from '../data.ts';
import { Artist } from '../types.ts';

// @desc Get all Artists
// @route GET /api/v1/artists
const getArtists = ( {response }: { response: any }) =>{
    response.body = {
        success: true,
        message: "Artists retrieved successfully",
        data: artists
    }
}

// @desc Get an Artists
// @route GET /api/v1/artists/:id
const getSingleArtist = ({ params, response }: { params: {id: string}, response: any }) => {
    const artist: Artist | undefined = artists.find(artist => artist.id === params.id)

    if(artist){
        response.status = 200
        response.body = {
            success: true,
            message: "Artist retrieved successfully",
            data: artist
        }
        }else{
        response.status = 404
        response.body = {
            success: false,
            data: "Artist not found"
        }
        }
}

// @desc Add an Artists
// @route POST /api/v1/artists/
const addArtist = async ({ request, response }: {request: any, response: any }) => {
    const body = await request.body()
    if(!request.hasBody){
        response.status = 400;
        response.body = {
            success: false,
            message: "Ensure to enter data"
        }
    }else {
        const artist: Artist = body.value
        artist.id = v4.generate();
        artists.push(artist)
        response.status = 201;
        response.body = {
            success: true,
            message: "Artist added successfully",
            data: artist
        }
    }
}


// @desc update an Artist
// @route PUT /api/v1/artists/:id
const updateArtist = async ({ params, request, response }: { params:{id: string}, request:any, response: any }) => {
    const artist: Artist | undefined = artists.find(artist => artist.id === params.id)

    if (artist) {
        const body = await request.body()
        const updateArtist: {name?: string; genre?: string; followers?:string} = body.value

        const updatedArtists = artists.map(artist => artist.id === params.id ? {...artist, ...updateArtist} : artist)

        response.status = 200;
        response.body = {
            success: true,
            message: "Artist updated successfully",
            data: updatedArtists
        }
    } else {
        response.status = 404
        response.body = {
            success: false,
            message: "Artist not found"
        }
    }
}

// Added

// @desc Remove an Artist
// @route DELETE /api/v1/artists/:id
const deleteArtist = ({ params, response }: { params: {id:string}, response: any }) => {
    const artist = artists.filter(artist => artist.id !== params.id)
    if (artist) {
        response.status = 200
        response.body = {
            success: true,
            message: "Artist removed successfully",
            data: artist
        }
    } else {
        response.status = 404
        response.body = {
            success: false,
            message: "Artist not found"
        }
    }
}

// Updated
export { getArtists, getSingleArtist, addArtist, updateArtist, deleteArtist }

Lets update the route to our export routes.ts

 
import { Router } from 'https://deno.land/x/oak/mod.ts';

// Updated
import { getArtists, getSingleArtist, addArtist, updateArtist } from './controllers/artists.ts'

const router = new Router();

router.get('/api/v1/welcome', ({ response }: { response: any }) => {
    response.body = {
        success: true,
        message: "Welcome to Artists API"
    }
});

// Updated
router.get('/api/v1/artists', getArtists)
    .get('/api/v1/artists/:id', getSingleArtist)
    .post('/api/v1/artists', addArtist)
    .put('/api/v1/artists/:id', updateArtist)
    .delete('/api/v1/artists/:id', deleteArtist);



export default router;

Lets restart our server and test it

$ deno run --allow-net server.ts
Postman Result

Find the code in this GitHub Repo

Summary

We have successfully built our first Deno API using Artists records as an Example. In the future, we would be integrating a Database to store our data.

Do not hesitate to point out any corrections you notice. thank you!

Continue to Part 2

Related posts

Leave a Reply

Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.