node.jsajaxxmlhttprequestkoakoa-router

Koa-Router : Skip the route if the request not in XHR


I have a Rest API made with Koa with some routes, but, at the same time, it will serve my Front (made with a JS framework and its own router).

The fact is, when I access from a browser "localhost/user" I want to display the front but when I reach the same url from fetch / ajax / XMLHttpRequest I want to display a JSON result (the one gave by the Koa-router).

So I would like to enable the /user route from the API only if it's called from XHR.

I did my isXMLHttpRequest middleware like this :

module.exports = async (ctx, next) => {
    if(ctx.request.get('X-Requested-With') === 'XMLHttpRequest') {
        return next()
    }
}

Then, in my koa-router I did something like :

const Router = require('koa-router')

const isXMLHttpRequest = require("@middlewares/isXMLHttpRequest")

const router = new Router()

const user = require("@routes/user")
router.use('/user', isXMLHttpRequest, user.routes(), user.allowedMethods())

And then, it works when I do some XHR request, I have the JSON as planned, but if I try to access the /user from the browser, the API is giving me a Not Found Error and not my front...

I was looking on how to skip the router.use function if the request isn't made in XHR, but I can't find a solution...

I think it's in the middleware else condition, I have to return something, but what can I do to skip the koa-router from giving me 404 ...

Maybe you can help me ?


Solution

  • OK, so if you are using the SAME routes for static and XMLHttpRequests (which is probably not the best strategy), then this could work:

    const Koa = require('koa')
    const Router = require('koa-router')
    
    const app = module.exports = new Koa();
    
    isXmlRequest = (ctx) => {
        // here you could also compare e.g. "accept" header
        return (ctx.request.header && ctx.request.header['x-requested-with'] === 'XMLHttpRequest');
    }
    
    // static routes
    const staticRouter = new Router()
    staticRouter.get('/user', (ctx, next) => {
        ctx.body = 'OK from static route';
        next();
    });
    
    // XMLHttpRequest routes
    const xmlRouter = new Router()
    xmlRouter.get('/user', (ctx, next) => {
        if (isXmlRequest(ctx)) {
            // serve it
            ctx.body = { ok: 'from JSON/XML' }
        } else {
            // downstream to next handler
            next();
        }
    });
    
    app.use(xmlRouter.routes());
    app.use(staticRouter.routes());
    
    const server = app.listen(3000)
    

    This is not using middleware bwcause here you can only allow downstream with next but if there is no next, then this stops. There is no else ;-) Just for reference