koa.js

SeanUdayantha
6 min readMay 15, 2022

--

Introduction

The team behind Express has created Koa, a new web framework that aspires to offer a smaller, more expressive, and more robust base for online applications and APIs. Koa eliminates callbacks and dramatically improves error handling by using async functions. Koa’s core does not provide any middleware, but it does include an elegant set of mechanisms for constructing servers quickly and easily.

The Koa framework has the following features

· Node.js framework designed to be lightweight and adaptable.

· By default, ECMAScript 6 (/ES2015) is supported.

· Generators can be used as functions by developers to pause and resume code execution.

· Error management is made easier by utilizing middleware more efficiently.

· All HTTP methods are identified and understood.

Koa has async/await functionality even before Express.

Installation

Koa requires node v7.6.0 or higher for ES2015 and async function support.

You can quickly install a supported version of node with your favorite version manager:

$ nvm install 7
$ npm i koa
$ node my-koa-app.js

Get start Koa

A Koa application is a stack-like object that contains an array of middleware functions that are constructed and performed on demand. Many other middleware systems, such as Ruby’s Rack, Connect, and others, are comparable to Koa; nevertheless, a fundamental design decision was taken to give high-level “sugar” at the normally low-level middleware layer. This increases interoperability and robustness while also making middleware development more pleasurable.

This covers, among other things, mechanisms for content negotiation, cache freshness, proxy support, and redirection. Despite having a huge number of useful methods, Koa has a tiny footprint since no middleware is included.

The required hello world application:

What is ctx? : The asynchronous middleware function takes ctx as an argument. In Koa, it’s known as Context, and it combines request and response objects into a single object. In contrast to ExpressJS, this needs request and response to be supplied as distinct objects as parameters. Every request to the server in Koa generates a context, which is always referred to as middleware.

Cascading

comparable technologies. We can accomplish “true” middleware with async functions. Koa invokes “downstream,” then control flows back “upstream,” in contrast to Connect’s approach, which simply sends control through a sequence of functions until one returns.

The following example responds with “Hello World,” but first passes through the x-response-time and logging middleware to determine when the request began, before passing control to the response middleware. When a middleware calls next(), the function suspends execution and transmits control to the next declared middleware. The stack will unwind whenever there is no more middleware to run downstream, and each middleware will resume its upstream behavior.

app.listen(…)

A Koa application is not an exact replica of an HTTP server. With a single HTTP server, one or more Koa applications may be mounted together to construct bigger applications.

Pass the specified parameters to Server#listen to create and return an HTTP server (). On nodejs.org, these parameters are documented. A worthless Koa application linked to port 5000 is as follows:

const Koa = require('koa');
const app = new Koa();
app.listen(5000);

Building the REST API

Now we need to install some dependencies for the API to work.

· koa-router is a routing middleware that uses HTTP verbs to enable ExpressJS-style routing. It has methods that may be used directly in the application. For example, app.get() and app.post().

· koa-bodyparser is a middleware for body-parsing. It accepts request bodies that are urlencoded, multi-part, and json. It basically aids in the creation and response to HTTP POST requests, which may be used as a form field, a file upload, and so on. It informs the server that the client’s inbound request has a body of data.

· koa-json is a middleware for pretty-printing JSON responses. Also transforms binary node object streams.

npm i koa-router koa-bodyparser koa-json

let’s create this API in Koa

Now that we have our application up and running, we can focus on developing the API. Set up the movies.js file first. We don’t save the movies in a database; instead, we keep them in memory, so the movies we’ve uploaded will vanish when the server restarts. A database or a file may readily be used to replicate this (using node fs module).

Import koa-router, create a Router and export it using module.exports.

var Router = require('koa-router');
var router = Router({
prefix: '/movies'
}); //Prefixed all routes with /movies

var movies = [
{id: 101, name: "Fight Club", year: 1999, rating: 8.1},
{id: 102, name: "Inception", year: 2010, rating: 8.7},
{id: 103, name: "The Dark Knight", year: 2008, rating: 9},
{id: 104, name: "12 Angry Men", year: 1957, rating: 8.9}
];

//Routes will go here

module.exports = router;

GET Routes

Get All Movies

router.get('/', sendMovies);
function *sendMovies(next){
this.body = movies;
yield next;
}

That’s it. To see if everything is functioning, start your program, then open your terminal and type.

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET localhost:3000/movies

Get the response as

[{"id":101,"name":"Fight 
Club","year":1999,"rating":8.1},{"id":102,"name":"Inception","year":2010,"rating":8.7},
{"id":103,"name":"The Dark Knight","year":2008,"rating":9},{"id":104,"name":"12 Angry
Men","year":1957,"rating":8.9}]

We have a route to get all the movies. Now let’s create a route to get a specific movie by its id.

router.get('/:id([0-9]{3,})', sendMovieWithId);

function *sendMovieWithId(next){
var ctx = this;
var currMovie = movies.filter(function(movie){
if(movie.id == ctx.params.id){
return true;
}
});
if(currMovie.length == 1){
this.body = currMovie[0];
} else {
this.response.status = 404;//Set status to 404 as movie was not found
this.body = {message: "Not Found"};
}
yield next;
}

This will retrieve the movies based on the id we supply. Use the following command in your terminal to verify this.

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET localhost:3000/movies/101

Get the response as

{"id":101,"name":"Fight Club","year":1999,"rating":8.1}

POST Route

router.post('/', addNewMovie);

function *addNewMovie(next){
//Check if all fields are provided and are valid:
if(!this.request.body.name ||
!this.request.body.year.toString().match(/^[0-9]{4}$/g) ||
!this.request.body.rating.toString().match(/^[0-9]\.[0-9]$/g)){

this.response.status = 400;
this.body = {message: "Bad Request"};
} else {
var newId = movies[movies.length-1].id+1;

movies.push({
id: newId,
name: this.request.body.name,
year: this.request.body.year,
rating: this.request.body.rating
});
this.body = {message: "New movie created.", location: "/movies/" + newId};
}
yield next;
}

This creates a new movie and saves it to the movies variable. Enter the following into your terminal to test this route

curl -X POST --data "name = Toy%20story&year = 1995&rating = 8.5" 
https://localhost:3000/movies

Get the following response

{"message":"New movie created.","location":"/movies/105"}

PUT Route

The PUT route is nearly identical to the POST route. The id of the item to be updated/created will be specified. Create the route by following these steps:

router.put('/:id', updateMovieWithId);

function *updateMovieWithId(next){
//Check if all fields are provided and are valid:
if(!this.request.body.name ||
!this.request.body.year.toString().match(/^[0-9]{4}$/g) ||
!this.request.body.rating.toString().match(/^[0-9]\.[0-9]$/g) ||
!this.params.id.toString().match(/^[0-9]{3,}$/g)){

this.response.status = 400;
this.body = {message: "Bad Request"};
} else {
//Gets us the index of movie with given id.
var updateIndex = movies.map(function(movie){
return movie.id;
}).indexOf(parseInt(this.params.id));

if(updateIndex === -1){
//Movie not found, create new movies.push({
id: this.params.id,
name: this.request.body.name,
year: this.request.body.year,
rating: this.request.body.rating
});
this.body = {message: "New movie created.", location: "/movies/" + this.params.id};
} else {
//Update existing movie
movies[updateIndex] = {
id: this.params.id,
name: this.request.body.name,
year: this.request.body.year,
rating: this.request.body.rating
};
this.body = {message: "Movie id " + this.params.id + " updated.", location: "/movies/" + this.params.id};
}
}
}

This route will do the task listed in the table above. If the item exists, it will be updated with new information. It will generate a new object if it does not exist. To test this route, use the curl command below. This will bring an existing movie up to date. Simply update the id to a non-existing id to make a new Movie.

curl -X PUT --data "name = Toy%20story&year = 1995&rating = 8.5" 
https://localhost:3000/movies/101

Get the following response

{"message":"Movie id 101 updated.","location":"/movies/101"}

DELETE Route

Use the following code to create a delete route.

router.delete('/:id', deleteMovieWithId);

function *deleteMovieWithId(next){
var removeIndex = movies.map(function(movie){
return movie.id;
}).indexOf(this.params.id); //Gets us the index of movie with given id.

if(removeIndex === -1){
this.body = {message: "Not found"};
} else {
movies.splice(removeIndex, 1);
this.body = {message: "Movie id " + this.params.id + " removed."};
}
}

Test the route in the same way we did for the others. On successful deletion (for example id 101), you will get

{message: "Movie id 101 removed."}

Finally, our movies.js

Our REST API is now complete. Using this fundamental architectural style and Koa, you can now construct far more complicated apps.

--

--

No responses yet