docs: update endpoints to use file-routing approach (#5397)
- Move the original guides for creating endpoints and middlewares to sub-sections in the Endpoints category. - Replace existing guides for endpoints and middlewares with the new approach. - Update all endpoints-related snippets across docs to use this new approach.
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
---
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Troubleshooting from '@site/src/components/Troubleshooting'
|
||||
import ServiceLifetimeSection from '../../troubleshooting/awilix-resolution-error/_service-lifetime.md'
|
||||
import CustomRegistrationSection from '../../troubleshooting/awilix-resolution-error/_custom-registration.md'
|
||||
|
||||
# Middlewares
|
||||
|
||||
In this document, you’ll learn how to add a middleware to existing or custom API Routes in Medusa.
|
||||
|
||||
:::tip
|
||||
|
||||
v1.17.2 of `@medusajs/medusa` introduced a new approach to creating middlewares using a single `middlewares.ts` file. You can still use the [Express Router Approach](./add-middleware-express-route.mdx), however, it's highly recommended that you start using this new approach.
|
||||
|
||||
:::
|
||||
|
||||
## Basic Implementation
|
||||
|
||||
```ts title=src/api/middlewares.ts
|
||||
import type { MiddlewaresConfig } from "@medusajs/medusa"
|
||||
import type {
|
||||
MedusaNextFunction,
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
const storeMiddleware = (
|
||||
req: MedusaRequest,
|
||||
res: MedusaResponse,
|
||||
next: MedusaNextFunction
|
||||
) => {
|
||||
// do something
|
||||
next()
|
||||
}
|
||||
|
||||
export const config: MiddlewaresConfig = {
|
||||
routes: [
|
||||
{
|
||||
matcher: "/store/*",
|
||||
middlewares: [storeMiddleware],
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
A middleware is a function that has access to the `MedusaRequest` and `MedusaResponse` objects that are passed to API Route method handlers.
|
||||
|
||||
Middlewares are used to perform an action when a request is sent to an API Route, or modify the response of an API route, among other usages.
|
||||
|
||||
### middlewares.ts File
|
||||
|
||||
Middlewares are defined in the `src/api/middlewares.ts` file. This file must expose a config object of type `MiddlewaresConfig` imported from `@medusajs/medusa`.
|
||||
|
||||
This object accepts a parameter `routes`, whose value is an array of middleware route objects. Each middleware route object accepts the following properties:
|
||||
|
||||
- The `matcher` property accepts a string or a regular expression that will be used to check whether the middlewares should be applied on a API Routes.
|
||||
- The `middlewares` property is an array of middlewares that should be applied on API Routes matching the pattern specified in `matcher`.
|
||||
|
||||
---
|
||||
|
||||
## Build Files
|
||||
|
||||
Similar to custom API Routes, you must transpile the files under `src` into the `dist` directory for the backend to load them.
|
||||
|
||||
To do that, run the following command before running the Medusa backend:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can then test that the middleware is working by running the backend.
|
||||
|
||||
---
|
||||
|
||||
## Register New Resources in Dependency Container
|
||||
|
||||
In some cases, you may need to register a resource to use within your commerce application. For example, you may want to register the logged-in user to access it in other resources, such as services. You can do that in your middleware.
|
||||
|
||||
:::tip
|
||||
|
||||
If you want to register a logged-in user and access it in your resources, you can check out [this example guide](./example-logged-in-user.mdx).
|
||||
|
||||
:::
|
||||
|
||||
To register a new resource in the dependency container, use the `MedusaRequest` object's `scope.register` method. It accepts an object, where each key is the name to be registered in the dependency container, and its value is an object that has a `resolve` property.
|
||||
|
||||
The `resolve`'s value is a function that returns the resource to be registered in the dependency container.
|
||||
|
||||
For example:
|
||||
|
||||
```ts title=src/api/middlewares.ts
|
||||
import type { MiddlewaresConfig } from "@medusajs/medusa"
|
||||
import type {
|
||||
MedusaNextFunction,
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
const customResource = (
|
||||
req: MedusaRequest,
|
||||
res: MedusaResponse,
|
||||
next: MedusaNextFunction) => {
|
||||
req.scope.register({
|
||||
customResource: {
|
||||
resolve: () => "my custom resource",
|
||||
},
|
||||
})
|
||||
|
||||
next()
|
||||
}
|
||||
|
||||
export const config: MiddlewaresConfig = {
|
||||
routes: [
|
||||
{
|
||||
matcher: "/store/*",
|
||||
middlewares: [customResource],
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
You can then load this new resource within other resources. For example, to load it in a service:
|
||||
|
||||
<!-- eslint-disable prefer-rest-params -->
|
||||
|
||||
```ts title=src/services/custom-service.ts
|
||||
import { TransactionBaseService } from "@medusajs/medusa"
|
||||
|
||||
class CustomService extends TransactionBaseService {
|
||||
|
||||
constructor(container, options) {
|
||||
super(...arguments)
|
||||
|
||||
// use the registered resource.
|
||||
try {
|
||||
container.customResource
|
||||
} catch (e) {
|
||||
// avoid errors when the backend first loads
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default CustomService
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
Make sure to wrap your usage of the new resource in a try-catch block when you use it in a constructor. This is to avoid errors that can arise when the backend first loads, as the resource isn't registered yet.
|
||||
|
||||
:::
|
||||
|
||||
### Note About Services Lifetime
|
||||
|
||||
If you want to access new registrations in the dependency container within a service, you must set the lifetime of the service either to `Lifetime.SCOPED` or `Lifetime.TRANSIENT`. Services that have a `Lifetime.SINGLETON` lifetime can't access new registrations since they're resolved and cached in the root dependency container beforehand. You can learn more in the [Create Services documentation](../services/create-service.mdx#service-life-time).
|
||||
|
||||
For custom services, no additional action is required as the default lifetime is `Lifetime.SCOPED`. However, if you extend a core service, you must change the lifetime since the default lifetime for core services is `Lifetime.SINGLETON`.
|
||||
|
||||
For example:
|
||||
|
||||
<!-- eslint-disable prefer-rest-params -->
|
||||
|
||||
```ts
|
||||
import { Lifetime } from "awilix"
|
||||
import {
|
||||
ProductService as MedusaProductService,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
// extending ProductService from the core
|
||||
class ProductService extends MedusaProductService {
|
||||
// The default life time for a core service is SINGLETON
|
||||
static LIFE_TIME = Lifetime.SCOPED
|
||||
|
||||
constructor(container, options) {
|
||||
super(...arguments)
|
||||
|
||||
// use the registered resource.
|
||||
try {
|
||||
container.customResource
|
||||
} catch (e) {
|
||||
// avoid errors when the backend first loads
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default ProductService
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<Troubleshooting
|
||||
sections={[
|
||||
{
|
||||
title: 'AwilixResolutionError: Could Not Resolve X',
|
||||
content: <ServiceLifetimeSection />
|
||||
},
|
||||
{
|
||||
title: 'AwilixResolutionError: Could Not Resolve X (Custom Registration)',
|
||||
content: <CustomRegistrationSection />
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Store API reference](https://docs.medusajs.com/api/store)
|
||||
- [Admin API reference](https://docs.medusajs.com/api/admin)
|
||||
Reference in New Issue
Block a user