I was playing around with this, here is another way that worked for me.
GitHub Link Example
1 Override existing route to use slug vs id
src/api/post/routes/post.js
"use strict";
/**
* post router.
*/
const { createCoreRouter } = require("@strapi/strapi").factories;
const defaultRouter = createCoreRouter("api::post.post");
// function to add to or override default router methods
const customRouter = (innerRouter, routeOveride = [], extraRoutes = []) => {
let routes;
return {
get prefix() {
return innerRouter.prefix;
},
get routes() {
if (!routes) routes = innerRouter.routes;
const newRoutes = routes.map((route) => {
let found = false;
routeOveride.forEach((overide) => {
if (
route.handler === overide.handler &&
route.method === overide.method
) {
found = overide;
}
});
return found || route;
});
return newRoutes.concat(extraRoutes);
},
};
};
// Overide the default router with the custom router to use slug.
const myOverideRoutes = [
{
method: "GET",
path: "/posts/:slug",
handler: "api::post.post.findOne",
},
];
const myExtraRoutes = [];
module.exports = customRouter(defaultRouter, myOverideRoutes, myExtraRoutes);
2 Override existing controller to use slug instead of id
src/api/post/controllers/post.js
"use strict";
/**
* post controller
*/
const { createCoreController } = require("@strapi/strapi").factories;
module.exports = createCoreController("api::post.post", ({ strapi }) => ({
async findOne(ctx) {
const { slug } = ctx.params;
const query = {
filters: { slug },
...ctx.query,
};
const post = await strapi.entityService.findMany("api::post.post", query);
const sanitizedEntity = await this.sanitizeOutput(post);
return this.transformResponse(sanitizedEntity[0]);
},
}));
query
http://localhost:1337/api/posts/how-to-use-a-slug-vs-an-id-field
response
{
"data": {
"id": 1,
"attributes": {
"title": "How to use a slug vs an id field",
"content": "## My content",
"slug": "how-to-use-a-slug-vs-an-id-field",
"createdAt": "2022-06-16T21:20:05.209Z",
"updatedAt": "2022-06-16T23:32:45.288Z",
"publishedAt": "2022-06-16T21:20:08.070Z"
}
},
"meta": {}
}
query
http://localhost:1337/api/posts/how-to-use-a-slug-vs-an-id-field?populate=*
response
{
"data": {
"id": 1,
"attributes": {
"title": "How to use a slug vs an id field",
"content": "## My content",
"slug": "how-to-use-a-slug-vs-an-id-field",
"createdAt": "2022-06-16T21:20:05.209Z",
"updatedAt": "2022-06-16T23:32:45.288Z",
"publishedAt": "2022-06-16T21:20:08.070Z",
"image": {
"data": {
"id": 1,
"attributes": {
"name": "cat2.jpg",
"alternativeText": "cat2.jpg",
"caption": "cat2.jpg",
"width": 2392,
"height": 2500,
"formats": {
"thumbnail": {
"name": "thumbnail_cat2.jpg",
"hash": "thumbnail_cat2_bf2dde0b7d",
"ext": ".jpg",
"mime": "image/jpeg",
"path": null,
"width": 150,
"height": 156,
"size": 4.66,
"url": "/uploads/thumbnail_cat2_bf2dde0b7d.jpg"
},
"large": {
"name": "large_cat2.jpg",
"hash": "large_cat2_bf2dde0b7d",
"ext": ".jpg",
"mime": "image/jpeg",
"path": null,
"width": 957,
"height": 1000,
"size": 120.28,
"url": "/uploads/large_cat2_bf2dde0b7d.jpg"
},
"medium": {
"name": "medium_cat2.jpg",
"hash": "medium_cat2_bf2dde0b7d",
"ext": ".jpg",
"mime": "image/jpeg",
"path": null,
"width": 718,
"height": 750,
"size": 70.24,
"url": "/uploads/medium_cat2_bf2dde0b7d.jpg"
},
"small": {
"name": "small_cat2.jpg",
"hash": "small_cat2_bf2dde0b7d",
"ext": ".jpg",
"mime": "image/jpeg",
"path": null,
"width": 478,
"height": 500,
"size": 32.39,
"url": "/uploads/small_cat2_bf2dde0b7d.jpg"
}
},
"hash": "cat2_bf2dde0b7d",
"ext": ".jpg",
"mime": "image/jpeg",
"size": 544.61,
"url": "/uploads/cat2_bf2dde0b7d.jpg",
"previewUrl": null,
"provider": "local",
"provider_metadata": null,
"createdAt": "2022-06-16T23:32:42.135Z",
"updatedAt": "2022-06-16T23:32:42.135Z"
}
}
}
}
},
"meta": {}
}