Simon Trichereau
Simon Trichereau

Reputation: 809

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 ?

Upvotes: 0

Views: 897

Answers (2)

Sebastian Hildebrandt
Sebastian Hildebrandt

Reputation: 2791

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

Upvotes: 0

Sebastian Hildebrandt
Sebastian Hildebrandt

Reputation: 2791

Not sure If I got your question right. So you have a backend that acts like a static web server AND a REST API, right?.

I would try to do it the other way round. Using e.g koa-static (https://www.npmjs.com/package/koa-static) would FIRST try to serve your files and if no matching files are found in your defines public directory, all other routes (so your REST API) are handled. Then you only have to make sure, that endpoint names do not overlap with files you are serving.

Upvotes: 0

Related Questions