chore: reorganize docs apps (#7228)

* reorganize docs apps

* add README

* fix directory

* add condition for old docs
This commit is contained in:
Shahed Nasser
2024-05-03 17:36:38 +03:00
committed by GitHub
parent 224ebb2154
commit 4fe28f5a95
6187 changed files with 601447 additions and 598226 deletions
@@ -0,0 +1,104 @@
export const metadata = {
title: `${pageNumber} Handling CORS in API Routes`,
}
# {metadata.title}
In this chapter, youll learn about the CORS middleware and how to configure it for custom API routes.
## CORS Overview
Cross-Origin Resource Sharing (CORS) allows only configured origins to access your API Routes. For example, if you allow only origins starting with `http://localhost:7001` to access your Admin API Routes, other origins accessing those routes get a CORS error.
### CORS Configurations
You can configure allowed origins for Store and Admin API Routes using the `store_cors` and `admin_cors` configurations in `medusa-config.js`. Each of these configurations accepts a URL pattern to identify allowed origins.
For example:
```js title="medusa-config.js"
module.exports = {
projectConfig: {
admin_cors: "http://localhost:7001",
store_cors: "http://localhost:8000",
// ...
},
// ...
}
```
This allows the `http://localhost:7001` origin to access the Admin API Routes, and the `http://localhost:8000` origin to access Store API Routes.
---
## CORS in Store and Admin Routes
Medusa applies the CORS middleware with the specified configurations in `medusa-config.js` on all routes starting with `/store` and `/admin`.
To disable the CORS middleware for a route, export a `CORS` variable in the route file with its value set to `false`.
For example:
```ts title="src/api/store/custom/route.ts" highlights={[["15"]]}
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
export const GET = (
req: MedusaRequest,
res: MedusaResponse
) => {
res.json({
message: "[GET] Hello world!",
})
}
export const CORS = false
```
This disables the CORS middleware on API Routes at the path `/store/custom`.
---
## CORS in Custom Routes
If you create a route that doesnt start with `/store` or `/admin`, you must apply the CORS middleware manually. Otherwise, all requests to your API route cause a CORS error.
You can do that in the exported middlewares configurations in `src/api/middlewares.ts`.
For example:
export const highlights = [["18", "parseCorsOrigins", "A utility function that parses the CORS configurations in `medusa-config.js`"]]
```ts title="src/api/middlewares.ts" highlights={highlights}
import {
ConfigModule,
MiddlewaresConfig,
} from "@medusajs/medusa"
import { parseCorsOrigins } from "medusa-core-utils"
import cors from "cors"
export const config: MiddlewaresConfig = {
routes: [
{
matcher: "/custom*",
middlewares: [
(req, res, next) => {
const configModule: ConfigModule =
req.scope.resolve("configModule")
return cors({
origin: parseCorsOrigins(
configModule.projectConfig.store_cors
),
credentials: true,
})(req, res, next)
},
],
},
],
}
```
This retrieves the configurations exported from `medusa-config.js` and applies the `store_cors` to routes starting with `/custom`.
@@ -0,0 +1,47 @@
export const metadata = {
title: `${pageNumber} HTTP Methods`,
}
# {metadata.title}
In this chapter, you'll learn about how to add new API routes for each HTTP method.
## Handlers of HTTP Methods
You can define a handler function for each HTTP method in a route file. The functions name is the name of the HTTP method it handles.
Allowed HTTP methods are: `GET`, `POST`, `DELETE`, `PUT`, `PATCH`, `OPTIONS`, and `HEAD`.
Creating a route handler function for any of the above HTTP methods exposes a new API route for that method.
For example, create the file `src/api/store/hello-world/route.ts` with the following content:
```ts title="src/api/store/hello-world/route.ts"
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
export const GET = (
req: MedusaRequest,
res: MedusaResponse
) => {
res.json({
message: "[GET] Hello world!",
})
}
export const POST = (
req: MedusaRequest,
res: MedusaResponse
) => {
res.json({
message: "[POST] Hello world!",
})
}
```
This adds two API Routes:
- A `GET` route at `localhost:9000/store/hello-world`.
- A `POST` route at `localhost:9000/store/hello-world`.
@@ -0,0 +1,130 @@
export const metadata = {
title: `${pageNumber} Middlewares`,
}
# {metadata.title}
In this chapter, youll learn about middlewares and how to create them.
## What is a Middleware?
A middleware is a function executed when a request is sent to an API Route.
---
## How to Create a Middleware?
Middlewares are defined in the special file `src/api/middleware.ts`. The file must export an object of middleware configurations.
For example:
```ts title="src/api/middleware.ts"
import { MiddlewaresConfig } from "@medusajs/medusa"
export const config: MiddlewaresConfig = {
routes: [
{
matcher: "/store*",
middlewares: [
(req, res, next) => {
console.log("Received a request!")
next()
},
],
},
],
}
```
The middleware configurations object has the property `routes`. Its value is an array of middleware route objects, where each object is a middleware to apply to a route pattern.
In the example above, you define a middleware that logs the message `Received a request!` whenever a request is sent to an API route path starting with `/store`.
<Note>
The `matcher` property can be a string or a regular expression.
</Note>
### Test Middleware
To test the middleware, start the application:
```bash npm2yarn
npm run dev
```
Then, send a request to any API route starting with `/store`, such as `localhost:9000/store/products`:
```bash apiTesting testApiUrl="localhost:9000/store/products" testApiMethod="GET"
curl localhost:9000/store/products
```
Once you send the request, youll see the following message in the terminal:
```bash
Received a request!
```
---
## When to Use
<Note type="success" title="Use middlewares when">
- You want to guard API routes by a custom condition.
- You're modifying the request body.
- You're registering custom resources in the Medusa container.
</Note>
---
## Middleware Function Parameters
The middleware function accepts three parameters:
1. A request object of type `MedusaRequest`.
2. A response object of type `MedusaResponse`.
3. A function of type `MedusaNextFunction` that executes the next middleware in the stack.
<Note title="Important">
You must call the `next` function in the middleware. Otherwise, other middlewares and the API route handler wont execute.
</Note>
---
## Restrict HTTP Methods
In addition to the `matcher` configuration, you can restrict which HTTP methods the middleware is applied to.
The object in the `routes` array accepts the property `method` whose value is either a string or an array of strings. Each string is an allowed HTTP method. If no value is specified, the middlewares are applied to requests of all HTTP methods.
For example:
export const highlights = [["7", "", "Apply the middleware only on `POST` requests"]]
```ts title="src/api/middlewares.ts" highlights={highlights}
import { MiddlewaresConfig } from "@medusajs/medusa"
export const config: MiddlewaresConfig = {
routes: [
{
matcher: "/store*",
method: "POST",
middlewares: [
(req, res, next) => {
console.log("Received a request!")
next()
},
],
},
],
}
```
This applies the middleware only when a `POST` request is sent to an API route path starting with `/store`.
@@ -0,0 +1,146 @@
export const metadata = {
title: `${pageNumber} API Route Parameters`,
}
# {metadata.title}
In this chapter, youll learn about path, query, and request body parameters.
## Path Parameters
To define a path parameter for an API route, create a directory as part of the route files path. The directorys name is of the format `[param]`, where `param` is the name of the parameters.
For example, to create an API Route at the path `/message/{id}`, where `{id}` is an ID that can be passed to the route, create the file `src/api/store/hello-world/[id]/route.ts` with the following content:
export const singlePathHighlights = [
["11", "req.params.id", "Access the path parameter `id`"]
]
```ts title="src/api/store/hello-world/[id]/route.ts" highlights={singlePathHighlights}
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
export const GET = (
req: MedusaRequest,
res: MedusaResponse
) => {
res.json({
message: `[GET] Hello ${req.params.id}!`,
})
}
```
You can access the path parameter using the `params` property of the `MedusaRequest` parameter. The `params` property is an object whose keys are the parameter names, and the values are each parameters value passed in the routes path.
### Multiple Path Parameters
Each directory in the route files path whose name is of the format `[param]` is considered a path parameter. However, every parameter name must be unique.
For example, you can create an API route at `src/api/store/hello-world/[id]/name/[name]/route.ts`:
export const multiplePathHighlights = [
["11", "req.params.id", "Access the path parameter `id`"],
["11", "req.params.name", "Access the path parameter `name`"]
]
```ts title="src/api/store/hello-world/[id]/name/[name]/route.ts" highlights={multiplePathHighlights}
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
export const GET = (
req: MedusaRequest,
res: MedusaResponse
) => {
res.json({
message: `[GET] Hello ${req.params.id} - ${req.params.name}!`,
})
}
```
This API route expects two path parameters: `id` and `name`.
---
## Query Parameters
You can access all query parameters in the `query` property of the `MedusaRequest` parameter.
For example:
export const queryHighlights = [
["11", "req.query.name", "Access the query parameter `name`"],
]
```ts title="src/api/store/hello-world/route.ts" highlights={queryHighlights}
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
res.json({
message: `Hello ${req.query.name}`,
})
}
```
---
## Request Body Parameters
By default, any request sent to your Medusa application with its `Content-Type` header set to `application/json` is parsed into an object and attached to the `MedusaRequest`'s `body` property.
For example:
export const bodyHighlights = [
["15", "req.body.name", "Access the request body parameter `name`"],
]
```ts title="src/api/store/hello-world/route.ts" highlights={bodyHighlights}
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
type HelloWorldReq = {
name: string
}
export const POST = (
req: MedusaRequest<HelloWorldReq>,
res: MedusaResponse
) => {
res.json({
message: `[POST] Hello ${req.body.name}!`,
})
}
```
The `MedusaRequest` type accepts a type argument indicating the expected request body parameters.
In this example, you use the `name` request body parameter to create the message in the returned response.
To test it out, send the following request to your Medusa application:
```bash apiTesting testApiUrl="http://localhost:9000/store/hello-world" testApiMethod="POST" testBodyParams={{ "name": "John" }}
curl -X POST http://localhost:9000/store/hello-world \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "John"
}'
```
This returns the following JSON object:
```json
{
"message": "[POST] Hello John!"
}
```
@@ -0,0 +1,155 @@
export const metadata = {
title: `${pageNumber} Protected Routes`,
}
# {metadata.title}
In this chapter, youll learn how to create protected routes.
## Default Protected Routes
A protected route is a route that requires requests to be user-authenticated before performing the route's functionality. Otherwise, the request fails, and the user is prevented access.
Medusa applies an authentication guard on the following routes:
- Routes starting with `/admin` require an authenticated admin user.
- Routes starting with `/store/me` require an authenticated customer.
<Note>
Refer to the API Reference for [Admin](https://docs.medusajs.com/api/admin#authentication) and [Store](https://docs.medusajs.com/api/store#authentication) authentication methods.
</Note>
---
## Authentication Opt-Out
To disable the authentication guard on custom routes under the `/admin` or `/store/me` path prefixes, export an `AUTHENTICATE` variable in the route file with its value set to `false`.
For example:
```ts title="src/api/store/me/custom/route.ts" highlights={[["15"]]} apiTesting testApiUrl="http://localhost:9000/store/me/custom" testApiMethod="GET"
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
export const GET = async (
req: MedusaRequest,
res: MedusaResponse
) => {
res.json({
message: "Hello",
})
}
export const AUTHENTICATE = false
```
Now, any request sent to the `/store/me/custom` API route is allowed, regardless if the customer is authenticated or not.
---
## Access Logged-In Customer
You can access the logged-in customers ID in all API routes starting with `/store` using the `user.customer_id` property of the `MedusaRequest` object.
For example:
```ts title="src/api/store/custom/route.ts" highlights={[["16", "", "Access the logged-in customer's ID."]]}
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICustomerModuleService } from "@medusajs/types"
export const GET = async (
req: MedusaRequest,
res: MedusaResponse
) => {
const customerService: ICustomerModuleService =
req.scope.resolve(ModuleRegistrationName.CUSTOMER)
const customer = await customerService.retrieve(
req.user.customer_id
)
// ...
}
```
In the route handler, you resolve the `CustomerService`, then use it to retrieve the logged-in customer, if available.
---
## Access Logged-In Admin User
You can access the logged-in admin users ID in all API Routes starting with `/admin` using the `user.userId` property of the `MedusaRequest` object.
For example:
```ts title="src/api/admin/custom/route.ts" highlights={[["16", "req.user.userId", "Access the logged-in admin user's ID."]]}
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IUserModuleService } from "@medusajs/types"
export const GET = async (
req: MedusaRequest,
res: MedusaResponse
) => {
const userService: IUserModuleService = req.scope.resolve(
ModuleRegistrationName.USER
)
const user = await userService.retrieve(req.user.userId)
// ...
}
```
In the route handler, you resolve the `UserService`, and then use it to retrieve the logged-in admin user.
---
## Protect Custom API Routes
To protect custom API Routes that dont start with `/store/me` or `/admin`, apply one of the following middlewares exported by the `@medusajs/medusa` package on your routes:
- `authenticate`: only authenticated admin users can access the API Route. You can access the user's ID in the API Route method handler using the `MedusaRequest` object's `user.userId`.
- `authenticateCustomer`: customer authentication isnt required, but if a customer is logged in, it attaches their ID to the `MedusaRequest` object's `user.customer_id`.
- `requireCustomerAuthentication`: only authenticated customers can access the API Route. You can access the customer's ID in the API Route method handler using the `MedusaRequest` object's `user.customer_id`.
For example:
export const highlights = [
["11", "authenticate", "Only authenticated admin users can access routes starting with `/custom/admin`"],
["15", "requireCustomerAuthentication", "Only authenticated customers can access routes starting with `/custom/customers`"]
]
```ts title="src/api/middlewares.ts" highlights={highlights}
import {
authenticate,
requireCustomerAuthentication,
type MiddlewaresConfig,
} from "@medusajs/medusa"
export const config: MiddlewaresConfig = {
routes: [
{
matcher: "/custom/admin*",
middlewares: [authenticate()],
},
{
matcher: "/custom/customer*",
middlewares: [requireCustomerAuthentication()],
},
],
}
```
@@ -0,0 +1,66 @@
export const metadata = {
title: `${pageNumber} Request Body Parsers`,
}
# {metadata.title}
In this chapter, youll learn how to configure request-body parsing and add new parsers.
## Add a Request-Body Parser
You can parse request bodies of other content types by adding the parser as a middleware to the routes.
For example:
export const parserHighlights = [
["13", "", "Add a parser for the `application/x-www-form-urlencoded` content type."]
]
```ts title="src/api/middlewares.ts" highlights={parserHighlights}
import type {
MiddlewaresConfig,
} from "@medusajs/medusa"
import {
urlencoded,
} from "body-parser"
export const config: MiddlewaresConfig = {
routes: [
{
matcher: "*",
middlewares: [
urlencoded({ extended: true }),
],
},
],
}
```
This adds a parser for the `application/x-www-form-urlencoded` content type and attaches the parsed data to the `MedusaRequest` objects `body` property.
---
## Parse Webhook Body Parameters
Webhook API Routes may require the `raw` body parser middleware rather than the default `json`.
To change the default parser, set the `bodyParser` property of a middleware route object to `false`, and pass the preferred body-parser middleware in the `middlewares` property.
For example:
```ts title="src/api/middlewares.ts" highlights={[["8", "", "Disables the default request-body parser."], ["9", "raw", "Add a new body parser."]]}
import { MiddlewaresConfig } from "@medusajs/medusa"
import { raw } from "body-parser"
export const config: MiddlewaresConfig = {
routes: [
{
matcher: "/webhooks*",
bodyParser: false,
middlewares: [raw({ type: "application/json" })],
},
],
}
```
This changes the request-body parser to use the `raw` middleware on routes starting with `/webhooks`.