koajs / koa-body

koa body parser middleware
MIT License
950 stars 130 forks source link

Status 404 when use koa-body #124

Closed dstuff closed 5 years ago

dstuff commented 5 years ago

Promblem/Feature Request Summary

404 status Not found when use koa-body

Environment Information

Current Behavior

When use koa-body as middleware with koa-router API responds with 404 status.

Steps to Reproduce

  1. Add koa-body as a koa-rourter middleware
  2. Try to upload file using Postman (method POST with form-data mode and image field)
  3. Get 404 status

My code for app.js (api/app.js):

const Koa = require('koa');
const koaBody = require('koa-body');
...
const api = router();
const events = require('./routes/events');
...
app
  .use(logger())
  .use(errorHandler())
  .use(koaBody({ multipart: true }))
  .use(serve(__dirname + '/uploads', serveOptions));

api.use('/events', events.routes());

app.listen(config.port);

My events route code (api/routes/event.js):

const router = require('koa-router')();
const koaBody = require('koa-body');
...
 router.post('/:_id/upload',
    auth(secret),
    koaBody(),
    async (ctx) => {
      const file = ctx.request.files.file;
      console.log('File:', file)
      return events.uploadImage(ctx);
  })

module.exports = router;

Console log in events route doesn't appear in console. So, I assumed that the issue may be before it on koa-body initialization or so. By the way, I see my POST request log with the event id:

<-- POST /events/5c03ade8abef04112f3b269c/upload --> POST /events/5c03ade8abef04112f3b269c/upload 404 17ms -

Expected Behavior

Koa-body should upload files to local directory

Possible Solution

Nope. Any help will be appreciated.

MarkHerhold commented 5 years ago

I think this sounds like an issue with your router config. Could you try debugging by setting DEBUG=koa-router and seeing if that provides any clues?

Also, per the koa-router docs, they add routes to koa like so:

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

I'm not exactly sure why you are doing api.use('/events', events.routes());.

I haven't run any of your code yet so my guess may be off.

dstuff commented 5 years ago

Thanks for the answer!

I wrote api.use('/events', events.routes()); because all my routes in separate files and api is just name for router instance. Actually, I take this code form koa-router issues and it works fine.

I just skip lines with

app.use(api.routes());
app.use(api.allowedMethods());

Debug logs:

<-- POST /events/5c03ade8abef04112f3b269c/upload
  koa-router POST /events/5c03ade8abef04112f3b269c/upload +0ms
  koa-router test // /^\/(?:\/(?=$))?$/i +1ms
  koa-router test /auth/register /^\/auth\/register(?:\/(?=$))?$/i +0ms
  koa-router test /auth/login /^\/auth\/login(?:\/(?=$))?$/i +0ms
  koa-router test /users/ /^\/users(?:\/(?=$))?$/i +1ms
  koa-router test /users/ /^\/users(?:\/(?=$))?$/i +0ms
  koa-router test /events/ /^\/events(?:\/(?=$))?$/i +0ms
  koa-router test /events/:_id /^\/events\/((?:[^\/]+?))(?:\/(?=$))?$/i +0ms
  koa-router test /events/ /^\/events(?:\/(?=$))?$/i +0ms
  koa-router test /events/:_id/upload /^\/events\/((?:[^\/]+?))\/upload(?:\/(?=$))?$/i +0ms
  koa-router test /events/:_id /^\/events\/((?:[^\/]+?))(?:\/(?=$))?$/i +0ms
  koa-router test /events/ /^\/events(?:\/(?=$))?$/i +0ms
 --> POST /events/5c03ade8abef04112f3b269c/upload 404 30ms -

And I'm not sure what does it mean.

dstuff commented 5 years ago

Hey! I figured it out. I require koa-body 2 times in app.js and event.js (router) and used it in my router as middleware again. Also, I missed formidable properties for saving files locally. I'm quite new to Node.js so it wasn't clear for me bout formidable properties. So, the correct code is: app.js

const Koa = require('koa');
const koaBody = require('koa-body');
const serve = require('koa-static');
const router = require('koa-router');
const cors = require('@koa/cors');
const logger = require('koa-logger');

// databse init
require('./database/db');

const errorHandler = require('./middleware/errorHandler');

const config = require('./config');

const api = router();

// import routes
const index = require('./routes/index');
const auth = require('./routes/auth');
const users = require('./routes/users');
const events = require('./routes/events');

const serveOptions = {
  maxage: 60 * 60 * 24,
};

const app = new Koa();

app
  .use(logger())
  .use(errorHandler())
  // .use(helmet())
  .use(koaBody({
    multipart: true,
    formidable: {
      uploadDir: `${__dirname}/uploads`,
      keepExtensions: true,
    },
  }))
  .use(cors({
    origin: '*',
    allowMethods: ['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH', 'OPTIONS'],
    exposeHeaders: ['X-Request-Id']
  }))
  .use(serve(__dirname + '/uploads', serveOptions));

// app routes
api.use('/', index.routes());
api.use('/auth', auth.routes());
api.use('/users', users.routes());
api.use('/events', events.routes());

app.use(api.routes());
app.use(api.allowedMethods());

app.listen(config.port);

routes/event.js

const router = require('koa-router')();

const events = require('../controllers/events.controller');
const auth = require('../middleware/jwtAuth');

// app config data
const config = require('../config');
const secret = {
  secretKey: config.jwtToken,
};

// routes for the Events endpoint
router
  .get('/', async (ctx) => {
    return events.get(ctx);
  })
  .get('/:_id', async (ctx) => {
    return events.getOne(ctx);
  })
  .post('/',
    auth(secret),
    async (ctx) => {
      return events.create(ctx);
  })
  .post('/:_id/upload',
    auth(secret),
    async (ctx) => {
      const { files, body } = ctx.request;
      console.log('files:', files, 'fields:', body.fields);
      return events.uploadImage(ctx);
  })
  .put('/:_id', auth(secret), async (ctx) => {
    return events.update(ctx);
  })
  .all('/', async (ctx) => {
    return ctx.body = {
      status: 200,
      message: '/events/',
    };
  });

module.exports = router;

Anyway, thanks for the reply and for your awesome work!

MarkHerhold commented 5 years ago

Glad to hear you got it working. Best of luck!