-1

I am trying to build a simple restapi for my koa server.

here is my code

const Koa = require('koa');
const app = new Koa();
const json = require('koa-json')
let Router = require('koa-router');
let router = new Router();


let users = [
    { name: 'Kevin', email: 'k@gmail.com' },
    { name: 'Star', email: 'sss@gmail.com' },
    { name: 'Vick', email: 'V@gmail.com' },
]

router
    .get('/user', list)
    .get('/user/:id', detail)
    .post('/user/:id', update)
    .post('/user/create', create)

function list(ctx) {
    ctx.body = users
}

function detail(ctx) {
    ctx.body = users[ctx.params.id]
}

function create(ctx) {
    new_user = ctx.request.body
    users.push(new_user)
    ctx.body = users
}

function update(ctx) {
    ctx.body = Object.assign(users[ctx.params.id], ctx.request.body)
}

When I try to run the post create method, I got this error.

TypeError: Cannot convert undefined or null to object
      at Function.assign (<anonymous>)
      at update (E:\project\javascript\nodejs\KoaAPI\person\server.js:38:20)

I did use the post method and the url entered was user/create, I didn't even run the post update method.

However, when I switch the code order, put the post create before update like this:

router
    .get('/user', list)
    .get('/user/:id', detail)
    .post('/user/create', create)
    .post('/user/:id', update)

It works all fine. Can someone explain me why? Thank you.

ilikechocolate
  • 193
  • 1
  • 12

1 Answers1

1

The reason is that the router invokes the first matching URL (with the same HTTP method) according to the routes declaration. In your case the HTTP handler for .post('/user/:id') will be invoked when the URL is /user/create because the router tries to match the URL in the order of the routes declaration. The first regular expression to be checked is /user/.* ('/user/:id' will be roughly translated to that) and it matches the string /user/create so it will skip checking the rest of the route declarations (it won't check specifically for .post('/user/create') no matter it's a better match logically) and will immediately invoke the first found handler.

The fix as you correctly observed is to declare the more specific routes first - if you declare /user/create before /user/:id, the request to /user/create will invoke the handler you initially expected.

Tsvetan Ganev
  • 8,246
  • 4
  • 26
  • 43