Is there any good resource to help me learn koa.js 2

I read the documentation. Made a simple CRUD API. But I do not get it.

I have research sync/await. I understand it but when it comes to using Koa I feel I’m missing something

For example when I made my API i didn’t make use of any of this

const Koa = require('koa');
const app = new Koa();

// x-response-time

app.use(async function (ctx, next) {
  const start = new Date();
  await next();
  const ms = new Date() - start;
  ctx.set('X-Response-Time', `${ms}ms`);
});

// logger

app.use(async function (ctx, next) {
  const start = new Date();
  await next();
  const ms = new Date() - start;
  console.log(`${ctx.method} ${ctx.url} - ${ms}`);
});

// response

app.use(ctx => {
  ctx.body = 'Hello World';
});

Though the above might be a pointless example. I do not understand why you would do anything like that.

Thank

Hey relio,

The example you posted is demonstrating how to use middleware in Koa. Middleware is functionality that wraps your application and can modify the request as it comes in (before it reaches your application code) or the response as it’s returned.

As I understand it, the middleware functions are executed in the order they are attached. In the example, when a request comes in, the response time function is called first. This creates a new Date object in order to capture the time at the start of the request.

It then calls await next(); which pauses the execution of the current function (using the await keyword) and passes control to the next middleware (the logger). The logger then performs some logic (in this case, creating its own Date object) and then pauses and passes control to the next function.

As there is no additional middleware to pass through, the request ends up at the function which generates the response (returning the string 'Hello World'). This function doesn’t call next(), so when it terminates the control passes back to the previous function in the chain (the logger) which resumes where it left off.

The logger middleware calculates the ms taken for the request, and logs out the method, URL and ms before returning control to the response time function. That function then recalculates the response time in ms and appends it to the outgoing request as a header and returns.

As there is no further middleware in the stack, the response is now returned to the user.

The benefit of the async/await syntax here is that it makes asynchronous code easier to follow. Rather than having a bunch of nested callback functions (or chained Promises) you can read the code as if it was synchronous.

I hope that helps, but let me know if anything was unclear. :slight_smile:

Thanks, From what you said maybe diving in how middleware work might help me.

About these two snippets.

I got this code from a github sample project, and I have seen it in other github threads

router.get('/', async (ctx, next) => {
  ctx.body = {
    page: 'Index'
  };
  await next();
});

router.get('/data', async (ctx, next) => {
  ctx.body = dummyjson.parse(data);
  await next();
});

I understand how they work. I used similar code when I created my little API but the await next() I do not get. In the first example, we used next not to hold up other middleware but in this case, we are just rendering there is no other middleware. I removed the await next() and the code still worked!

Anyway, I might need to learn more about middleware.

One last thing, this might be off topic. I have this code which I actually understand

import Koa from 'koa';
import router from './router';

const app = new Koa();

app.use(async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    ctx.body = { message: err.message };
    ctx.status = err.status || 500;
  }
});
app.use(router.routes());
app.listen(3000);

How can I similate an error so that I can see how I think the above code works

Thanks again, I understand what I just wrote are a bit all over the place, so thanks for anything you might add

It seems that the router methods can accept multiple functions (which are basically another form of middleware). The docs have this example:

router.get(
  '/users/:id',
  function (ctx, next) {
    return User.findOne(ctx.params.id).then(function(user) {
      ctx.user = user;
      return next();
    });
  },
  function (ctx) {
    console.log(ctx.user);
    // => { id: 17, name: "Alex" }
  }
);

See that the first function declares next as the second argument and calls it to pass control to the second function, while the second function doesn’t bother declaring next as it’s not used. So in your example, as you’re only declaring a single function per route, you don’t need to worry about calling next().

You can add a second middleware function beneath the first to throw an error:

// ...

app.use(async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    ctx.body = { message: err.message };
    ctx.status = err.status || 500;
  }
});

app.use(ctx => {
  throw new Error('Oh noes!');
});

// ...
1 Like

You’ve been very helpful.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.