Denorest

Lightweight, Minimalist Framework For REST API ๐Ÿฆ• ๐Ÿš€

View the Project on GitHub slectgit/denorest

Getting Started

Hello! Thank you for checking out Denorest!

Your First Server

To create a very basic โ€œhello, Deno!โ€ server, you would want to create a server.ts file with the following content:

import { WebApp, Router, Req, Res } from "https://deno.land/x/denorest@v3.1/mod.ts";

const app = new WebApp();
const router = new Router();

router.get("/", (_req: Req, res: Res) => {
  res.reply = "Hello, Deno!";
});

app.set(router);
app.listen(8080);

And then you would run the following command:

$ deno run --allow-net server.ts

If you arenโ€™t overly familiar with Deno, by default it does not trust the code you are running, and need you to let it have access to your machines network, so --allow-net provides that.

When navigating on your local machine to http://localhost:8080/ you should see the Hello world! message in your browser.

Router

Use the Router class to create modular, mountable route handlers.

The following example creates a router as a module, defines some routes, and assign router using WebApp.set() function.

import { Req, Res, Router, WebApp } from "https://deno.land/x/denorest@v3.1/mod.ts";

const app = new WebApp();

// create router
const router = new Router();

// define the home page route
router.get("/", (_req: Req, res: Res) => {
  res.reply = {
    page: "Home",
  };
});

// define the about page route
router.get("/about", (_req: Req, res: Res) => {
  res.reply = {
    page: "About",
  };
});

// assign router
app.set(router);

app.listen(8080);

Route Methods

A route method is derived from one of the HTTP methods, and is attached to an instance of the Router class.

The following code is an example of routes that are defined for the GET and the POST methods to the router module.

// GET method route
router.get("/", (req: Req, res: Res) => {
  res.reply = {
    page: "Home",
    method: "GET",
  };
});

// POST method route
router.post("/", (req: Req, res: Res) => {
  res.reply = {
    page: "Home",
    method: "POST",
  };
});

There is a special routing method Router.all(), used to load route functions at a path for all HTTP request methods. For example, the following handler is executed for requests to the route /about whether using GET, POST, PUT, DELETE, or any other HTTP request method supported in the http module.

router.all("/about", (_req: Req, res: Res) => {
  res.reply = {
    page: "About",
  };
});

Router Prefixing

Create a router file named birds.ts in the app directory, with the following content:

import { Router, Req, Res } from "https://deno.land/x/denorest@v3.1/mod.ts";

// create router
const router = new Router();

// define the home page route
router.all("/", (req: Req, res: Res) => {
  res.reply = {
    page: "Birds Home",
  };
});

// define the about page route
router.all("/about", (req: Req, res: Res) => {
  res.reply = {
    page: "Birds About",
  };
});

export default router;

Then, load the router module in the app using Router.pre() function:

// ...

import birdRouter from "./birds.ts";

// ...

router.pre("/birds", birdRouter);

// assign router
app.set(router);

// ...

The app will now be able to handle requests to /birds and /birds/about

Middleware

Middleware functions are functions that have access to the request object (Req) and response object (Res),

Bind middleware using Router.use() function.

// ...

// create router
const router = new Router();

// define middleware
router.use((req: Req, res: Res) => {
  // ...
  if (auth) {
    req.state.auth = true;
  } else {
    res.reply = {
      massage: "Please login",
    };
  }
})

// define the home page route
router.all("/", (req: Req, res: Res) => {
  // ...
  res.reply = {
    page: "Birds Home",
  };
});

// ...

Use middleware in specific route using route handler third parameter.

// ...

// middleware
const auth = (req: Req, res: Res) => {
  // ...
  if (auth) {
    req.state.auth = true;
  } else {
    res.reply = {
      massage: "Please login",
    };
  }
}

// define the home page route
router.all("/", (req: Req, res: Res) => {
  // ...
});

// define the about page route
router.all("/about", (req: Req, res: Res) => {
  res.reply = {
    page: "Birds About",
  };
}, [auth, ...]); // assign middleware in third parameter
        
// ...

Req - Request

The first parameter of the handler function is Req.

Req is a containing the following fields:

Res - Response

The second parameter of the handler function is Res.

Res is a containing the following fields:

Set Default Headers

Set default headers for all routes using WebApp.headers() function.

// ...

const app = new WebApp();
app.headers({
  "Content-Type": "text/html"
})

// ...

Get Query And Parameter

Route parameters are named URL segments that are used to capture the values specified at their position in the URL.

import { Req, Res, Router, WebApp, pathParse } from "https://deno.land/x/denorest@v3.1/mod.ts";

// ...

router.all("/:username/post/:postId", (req: Req, res: Res) => {
  // using pathParse() function
  const path = pathParse(req);
  console.log(path);
  res.reply = {
    username: path.params.username,
    post_id: path.params.postId
  };
});

// ...
Route path: /:username/post/:postId
Request URL: http://localhost:8080/deno/post/12?page=2
pathParse(Req): { params: { username: "deno", postId: "12" }, query: { page: "2" } }

Parse Request Payload

Support Content-Type:

import { Req, Res, Router, WebApp, bodyParse } from "https://deno.land/x/denorest@v3.1/mod.ts";

// ...

router.post("/", async (req: Req, res: Res) => {
  // using bodyParse() function
  const body = await bodyParse(req);
  console.log(body);
  res.reply = {
    page: "Home"
  };
});

// ...

404 Not Found & 500 Internal Server Error

You can handle 404 and 500 response using WebApp.set404() and WebApp.set500() function.

// ...

// set 404 route
app.set404(async (req: any, res: any) => {
  res.status = 404;
  res.headers = {
    "Content-Type": "text/html",
  };
  res.reply = "Not Found";
});

// set 500 route
app.set500(async (req: any, res: any) => {
  res.status = 500;
  res.headers = {
    "Content-Type": "text/html",
  };
  res.reply = "Internal Server Error";
});

// ...

HTTPS

HTTPS is supported in all modern browsers.

import { WebApp, Router, Req, Res } from "https://deno.land/x/denorest@v3.1/mod.ts";

const app = new WebApp();
const router = new Router();

router.get("/", (_req: Req, res: Res) => {
  res.reply = "Hello, Deno!";
});

app.set(router);

app.listenTls(443, "./cert.pem", "./key.pem");

Contribute

If you'd like to contribute, start by searching through the issues and pull requests to see whether someone else has raised a similar idea or question.

If you don't see your idea listed, and you think it fits into the goals of this guide, do one of the following: