[RFC-01] Changing the way cache middlewares are injected to native route mutation instead of new koa-router routes #64
Pinned
derrickmehaffy
started this conversation in
Ideas
Replies: 2 comments 1 reply
-
Since I got some beautiful diagrams from the Strapi engineering team sharing them on UID structure: |
Beta Was this translation helpful? Give feedback.
1 reply
-
Pull request that is working towards implementing this: #75 |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Summary
Currently this plugin injects the cache route middlewares (recv, purge, admin) by using a largely supported method by Strapi itself which uses koa-router directly to effectively copy the existing route and replace it.
For example when routes are being looked for we are hitting Strapi internal APIs that just directly expose the koa-router stack directly as seen in this util function and then it uses the mounted koa-router during bootstrap to overwrite these routes as see here.
Ideally what this RFC proposes instead is to register these route middlewares during the Strapi register phase and utilize a few different Strapi APIs that interface with the Strapi router configurations BEFORE they are parsed by koa-router directly and properly inject the route middlewares into the koa-router stack.
Detailed design
Functional breakdown
Within Strapi there are several different types of routes including:
api::test.test
api::test:custom
api::global.global
plugin::example.example
admin::user
Currently Strapi UIDs have very purposes depending on their namespace and structure and which parts of the code you are working with however generally they reference an API that also contains a content-type (with the small exception for plugins) and are basically broken down into three parts. Using the following examples of
api::test.test
andplugin::strapi-chatgpt.chatGptService
lets break these down:api::test.test
In the case of the normal API UIDs the namespace will always be
api
with the name and suffix using the content-type singular name, the one extra case is the suffix is largely based on how specific files are registered.api
::
test
.
test
For this RFC what matters here is largely how these UIDs are used with routes, for the case of normal APIs we can see this UID referenced in the file-system as such:
While it's not entirely true to say that these UIDs are directly related to the file-system structure (since the files aren't actually required since routes can be injected directly into the namespace without any files to hold them) it provides a rough reference to assist in understanding them. It should be noted that UIDs matter in context and the same UID can be used in other contexts that may not relate to each other such as when using an ID with a service or a controller.
plugin::strapi-chatgpt.chatGptService
In the case of plugin UIDs, the namespace SHOULD be
plugin
, however in certain novice built plugins this may not be the case while the name SHOULD be the plugin name. In this example we shall take the assumption that the plugin was built correctly and properly constructs the UIDs. For this example I am showing a service UID since plugin routes themselves (or any part of the plugin) are not expected or required to directly reference a content-type since all content-types, controllers, services, and routes are entirely independent of each other.plugin
::
strapi-chatgpt
.
chatGptService
The unique part of plugins is you handle registration of content-api and admin-api routes differently where the routes have a
type
attribute assigned to the route themselves. By default if thetype
is not specified then the route is considered part of the admin-api such as in the following example:Functional proposed implementation
Armed with the knowledge above lets break down exactly how this RFC proposes the implementation. Within Strapi there are native ways to get the Strapi specific routes depending on the namespaces.
API Namespace
For the main core-apis (and any custom/unique routes) we have direct access to these via
strapi.api
. First lets navigate down the API stack for getting the findOne route for the content-typetest
. A quick summary of this path will bestrapi.api.test.routes.test.routes
and in this example it exists in this array with an index ID of 1. We can match this to a findOne core route based on themethod
andpath
.Image for
strapi.api
Image for router object within the namespace::name (it's at this point we can see the custom suffix added)
Image for the default suffix containing the route we want
Image for showing custom suffix routes
Plugin Namespace
Plugins with Strapi have their own API to access everything which is simply
strapi.plugin('plugin-name')
from here we can find the specific suffixes we want depending on the context. In this example we will get the API path for the content-api route/prompt
and for this the example path will bestrapi.plugin('strapi-chatgpt').routes['content-api'].routes
with the index id of 0 but matching aginst the method and path. Something important to note that plugins by default will set a routeprefix
to the actual plugin name in order to prevent route conflicts where multiple plugins share the same route. Plugin maintains can specifically remote or change this prefix on a per-route basis at their discretion so it's important not to expect that the prefix will always exist or be the plugin name.Image showing contexts for the plugin
strapi-chatgpt
Image showing routes based on if these are registered for the admin-api or content-api
Image showing the
/prompt
routeImage showing the default prefix added into the file route (shown using the
yarn strapi routes:list
command, else we would see the prefix config key either be''
or'something'
)Admin Namespace
TODO
Injecting route middlewares to these namespaces
In each of the examples (api, plugin, and admin) these routes all have the same configuration structure:
method
: One ofGET
,POST
,PUT
,HEAD
, andDELETE
(note that plugin authors can use any accepted http method here includingPATCH
,CONNECT
,OPTIONS
, andTRACE
but these are not used by Strapi by default)path
: The direct path in the form of a string, including a leading/
and may contain some parameters defined by a:
handler
: Reference to a Strapi controller function which for the API namespace should be the controller UID + the function name and for plugins will be the suffix + function nameconfig
: object containing the route configuration optionsmiddlewares
: Array of middleware UIDs (strings) or objects containing the middleware UID and a custom configuration for that middlewarepolicies
: Array of policy UIDs (strings) or objects containing the policy UID and a custom configuration for that policyauth
: Either a boolean (with a false value) to completely disable auth or an object containing a scope array to define specific auth scopes (these are still experimental and should not be set manually)info
: Strapi info object containing internal information about the route such as the plugin type, plugin name, and api nameImage showing a plugin and api route structure
The proposed implementation here is that instead of reconstructing the koa-router routes is instead to parse through the user stragey configuration and directly interface with the previously described APIs to push the cache middlewares into the config.middlewares array.
Sample code for api UID (default routes)
Potential enhancements
It could also be possible to provide options to select which default routes have middlewares injected such as disabling caching on a specific route type (aka findOne) such as requested in the following enhancement: #50
Tradeoffs
While this is considered the current proper way to add route middlewares by Strapi, there is no central location to manage this, a proposal has been made to the Strapi team to construct a routes container much like their existing containers for services, controllers, and content-types that would include all of the Strapi routes for the api, plugin, and admin and provide easier maintaining of this plugin in the future but as of now this does not exist nor is there a timeline for when this will be implemented.
Beta Was this translation helpful? Give feedback.
All reactions