How to Create Endpoints
In this document, you’ll learn how to create endpoints in Medusa.
Overview
Custom endpoints are created under the src/api
directory in your Medusa Backend. They're defined in a TypeScript or JavaScript file named index
(for example, index.ts
). This file should export a function that returns an Express router
They're then transpiled into the /dist/api
directory to be consumed.
Implementation
To create a new endpoint, start by creating a new file in src/api
called index.ts
. At its basic format, index.ts
should look something like this:
This exports a function that returns an Express router. The function receives two parameters:
rootDirectory
is the absolute path to the root directory that your backend is running from.pluginOptions
is an object that has your plugin's options. If your API route is not implemented in a plugin, then it will be an empty object.
Defining Multiple Routes or Middlewares
Instead of returning an Express router in the function, you can return an array of routes and middlewares.
For example:
import { Router } from "express"
export default (rootDirectory, pluginOptions) => {
const router = Router()
router.get("/hello", (req, res) => {
res.json({
message: "Welcome to My Store!",
})
})
// you can also define the middleware
// in another file and import it
const middleware = (res, req, next) => {
// TODO define global middleware
console.log("hello from middleware")
next()
}
const anotherRouter = Router()
anotherRouter.get("/store/*", (req, res, next) => {
// TODO perform an actions for all store endpoints
next()
})
return [middleware, router, anotherRouter]
}
This allows you to export multiple routers and middlewares from the same file. You can also import the routers, routes, and middlewares from other files, then import them in src/api/index.ts
instead of defining them within the same file.
Endpoints Path
Your endpoint can be under any path you wish.
By Medusa’s conventions:
- All Storefront REST APIs are prefixed by
/store
. For example, the/store/products
endpoint lets you retrieve the products to display them on your storefront. - All Admin REST APIs are prefixed by
/admin
. For example, the/admin/products
endpoint lets you retrieve the products to display them on your Admin.
You can also create endpoints that don't reside under these two prefixes, similar to the hello
endpoint in the previous example.
CORS Configuration
If you’re adding a storefront or admin endpoint and you want to access these endpoints from the storefront or Medusa admin, you need to pass your endpoints Cross-Origin Resource Origin (CORS) options using the cors
package.
First, you need to import the necessary utility functions and types from Medusa's packages with the cors
library:
Next, in the exported function, retrieve the CORS configurations of your backend using the utility functions you imported:
Then, create an object that will hold the CORS configurations. If it’s a storefront endpoint, pass the origin
property storefront options:
If it’s an admin endpoint, pass the origin
property admin options:
Finally, for each route you add, create an OPTIONS
request and add cors
as a middleware for the route passing it the CORS option:
Protected Routes
Protected routes are routes that should be accessible by logged-in customers or users only.
Protect Store Routes
To make a storefront route protected, first, import the authenticate-customer
middleware:
Then, add the middleware to your route:
Please note that the endpoint is still accessible by all users, however, you’ll be able to access the current logged-in customer if there’s any.
To disallow guest customers from accessing the endpoint, you can throw an error if req.user
is false
.
Protect Admin Routes
To make an admin route protected, first, import the authenticate
middleware:
Then, add the middleware to your route:
router.options("/admin/products/count", cors(corsOptions))
router.get(
"/admin/products/count",
cors(corsOptions),
authenticate(),
async (req, res) => {
// access current user
const id = req.user.userId
const userService = req.scope.resolve("userService")
const user = await userService.retrieve(id)
// ...
}
)
Now, only authenticated users can access this endpoint.
Use Services
Services in Medusa bundle a set of functionalities into one class. Then, you can use that class anywhere in your backend. For example, you can use the ProductService
to retrieve products or perform operations like creating or updating a product.
You can retrieve any registered service in your endpoint using req.scope.resolve
passing it the service’s registration name.
Here’s an example of an endpoint that retrieves the count of products in your store:
The productService
has a count
method that returns a Promise. This Promise resolves to the count of the products. You return a JSON of the product count.
Building Files
Custom endpoints must be transpiled and moved to the dist
directory before you can start consuming them. When you run your backend using the medusa develop
command, it watches the files under src
for any changes, then triggers the build
command and restarts the server.
The build isn't triggerd though when the backend first starts running. So, make sure to run the build
command before starting the backend: