Working with routers
In Foxx routers are used to definethe URLs of your API. The easiest way to use a router is to mount itdirectly in the service using the context:
const createRouter = require("@arangodb/foxx/router");
const router = createRouter();
module.context.use(router);
Nested routers
Instead of mounting routers where they are defined, routers can also beexported from one module and imported in another. This allows you tostructure your routes by splitting them across multiple files:
// in your main file
const usersRouter = require("./api/users");
module.context.use("/users", usersRouter);
// in api/users/index.js
const createRouter = require("@arangodb/foxx/router");
const usersRouter = createRouter();
module.exports = usersRouter;
usersRouter.get("/me", (req, res) => {
// this will be exposed as /users/me
});
You can also mount routers inside of each other:
// in api/users/friends.js
const createRouter = require("@arangodb/foxx/router");
const friendsRouter = createRouter();
module.exports = friendsRouter;
// in api/users/index.js
const friendsRouter = require("./friends");
usersRouter.use("/friends", friendsRouter);
Note that you can also mount several routers with the same prefixor even without a prefix:
adminRouter.use(usersAdminRouter);
adminRouter.use(groupsAdminRouter);
Local middleware
Router-level middleware only applies to the router it is applied to andis not shared between multiple routers mounted at the same prefix(or without a prefix).
This can be especially useful when restricting access tosome routes but not others:
const createRouter = require("@arangodb/foxx/router");
const publicRoutes = createRouter();
const authedRoutes = createRouter();
authedRoutes.use((req, res, next) => {
if (req.session.uid) {
next();
} else {
res.throw("unauthorized");
}
});
module.context.use(publicRoutes);
module.context.use(authedRoutes);
Router factories
Sometimes you may have routers you want to use in multiple projects oruse at multiple points of your API but with slightly different implementationsor using different collections.
In these cases it can be useful to return the router from a function thattakes these differences as arguments instead of exporting the router directly:
// in your main file
const createUsersRouter = require("../util/users-router");
const usersRouter = createUsersRouter(
module.context.collection("users"),
"username"
);
module.context.use(usersRouter);
// in util/users-router.js
const createRouter = require("@arangodb/foxx/router");
const { query } = require("@arangodb");
module.export = (usersCollection, keyField) => {
const router = createRouter();
router.use((req, res) => {
if (!req.session || !req.session.uid) {
res.throw("unauthorized");
}
});
router.get("/me", (req, res) => {
const user = query`
FOR user IN ${usersCollection}
FILTER user[${keyField}] == ${req.session.uid}
LIMIT 1
RETURN user
`.next();
res.json(user);
});
return router;
};