Customizing Strapi — v4

Roshan Khandelwal
2 min readJan 5, 2022

Routes, Controllers & Services ( v4 )

By default when you do a findOne, Strapi would search by id, & since you cannot customize the id field ( not as of 1st Jan, 2022 ), so if you wanted to make a findOne call by a [slug], it would throw a 500 internal server error, since you tried passing a string to a field that expected a number.

Here is a Youtube link — that teaches you to do it with v3. With v4 things have changed a bit.

I am working with an Content Type called Pack

Custom route

We would first define a custom route.
https://docs.strapi.io/developer-docs/latest/development/backend-customization/routes.html#creating-custom-routers

Path — src > api > pack >routes > pack.js

This defines a custom handler to handle this route, with no authentication

Extending controller

https://docs.strapi.io/developer-docs/latest/development/backend-customization/controllers.html#adding-a-new-controller

Path — src > api > pack >controllers > pack.js

Created a new function, which then calls the service.

Extending Service

Even though Strapi provides an Entity Service, We are going to go beyond it, and look at the Query Engine, that it is built on.

Strapi provides an Entity Service API, built on top of the Query Engine API. The Entity Service is the layer that handles Strapi's complex data structures like components and dynamic zones, and uses the Query Engine API under the hood to execute database queries.

Reference- Query Engine & Service

Path — src > api > pack >services > pack.js

With all this in place, when we make a call to packs/:packId, it would be handled by the findOneByPackId method in the controller, which would call the findone method on the predefined EntityService, which has been overwritten.

In this case, we are overwriting the findOne method, since the pack would always be fetched via packId. However we could have as easily defined a custom method on the service, & referenced that in the controller.

--

--