docs: revise commerce modules overview pages (#10738)

* revise API Key Module overview

* revise auth module

* support ref sidebar items

* remove examples

* revise cart module

* revise currency

* revise customer module

* revise fulfillment module

* revise inventory module

* revise order module

* revise payment

* revise pricing module

* revise product module

* revise promotion module

* revise region module

* revise sales channel module

* revise stock location module

* revise store module

* revise tax module

* revise user module

* lint content + fix snippets
This commit is contained in:
Shahed Nasser authored and GitHub committed 2024-12-26 10:32:16 +02:00
1 parent c8f9938865
commit ebca8fed28
112 files changed
+9465 -7731

No files matched your search

@@ -1,325 +0,0 @@
import { CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `Examples of the Product Module`,
}
# {metadata.title}
In this guide, you’ll find common examples of how you can use the Product Module in your application.
<Note>
You should only use the Product Module's main service when implementing complex customizations. For common cases, check out [available workflows instead](../../../medusa-workflows-reference/page.mdx).
</Note>
## Create Product
<CodeTabs groupId="app-type">
<CodeTab value="medusa" label="Medusa API Router">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(request: MedusaRequest, res: MedusaResponse) {
const productModuleService = request.scope.resolve(
Modules.PRODUCT
)
const products = await productModuleService.createProducts([
{
title: "Medusa Shirt",
options: [
{
title: "Color",
},
],
variants: [
{
title: "Black Shirt",
options: [
{
value: "Black",
},
],
},
],
},
])
res.json({ products })
}
```
</CodeTab>
<CodeTab value="nextjs" label="Next.js App Router">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeProductModule } from "@medusajs/medusa/product"
export async function POST(request: Request) {
const productModuleService = await initializeProductModule()
const products = await productModuleService.createProducts([
{
title: "Medusa Shirt",
options: [
{
title: "Color",
},
],
variants: [
{
title: "Black Shirt",
options: [
{
value: "Black",
},
],
},
],
},
])
return NextResponse.json({ products })
}
```
</CodeTab>
</CodeTabs>
---
## List Products
<CodeTabs groupId="app-type">
<CodeTab value="medusa" label="Medusa API Router">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function GET(request: MedusaRequest, res: MedusaResponse) {
const productModuleService = request.scope.resolve(
Modules.PRODUCT
)
const products = await productModuleService.listProducts()
res.json({ products })
}
```
</CodeTab>
<CodeTab value="nextjs" label="Next.js App Router">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeProductModule } from "@medusajs/medusa/product"
export async function GET(request: Request) {
const productModuleService = await initializeProductModule()
const products = await productModuleService.listProducts()
return NextResponse.json({ products })
}
```
</CodeTab>
</CodeTabs>
---
## Retrieve a Product by its ID
<CodeTabs groupId="app-type">
<CodeTab value="medusa" label="Medusa API Router">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function GET(request: MedusaRequest, res: MedusaResponse) {
const productModuleService = request.scope.resolve(
Modules.PRODUCT
)
const product = await productModuleService.retrieveProduct(request.params.id)
res.json({ product })
}
```
</CodeTab>
<CodeTab value="nextjs" label="Next.js App Router">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeProductModule } from "@medusajs/medusa/product"
export async function GET(
request: Request,
{ params }: { params: Record<string, any> }
) {
const { id } = params
const productModuleService = await initializeProductModule()
const product = await productModuleService.retrieveProduct(id)
return NextResponse.json({ product })
}
```
</CodeTab>
</CodeTabs>
---
## Retrieve a Product by its Handle
<CodeTabs groupId="app-type">
<CodeTab value="medusa" label="Medusa API Router">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function GET(request: MedusaRequest, res: MedusaResponse) {
const productModuleService = request.scope.resolve(
Modules.PRODUCT
)
const data = await productModuleService.listProducts({
handle: "shirt",
})
res.json({ product: data[0] })
}
```
</CodeTab>
<CodeTab value="nextjs" label="Next.js App Router">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeProductModule } from "@medusajs/medusa/product"
export async function GET(request: Request) {
const productModuleService = await initializeProductModule()
const data = await productModuleService.listProducts({
handle: "shirt",
})
return NextResponse.json({ product: data[0] })
}
```
</CodeTab>
</CodeTabs>
---
## Retrieve Categories
<CodeTabs groupId="app-type">
<CodeTab value="medusa" label="Medusa API Router">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(request: MedusaRequest, res: MedusaResponse) {
const productModuleService = request.scope.resolve(
Modules.PRODUCT
)
const categories = await productModuleService.listProductCategories()
res.json({ categories })
}
```
</CodeTab>
<CodeTab value="nextjs" label="Next.js App Router">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeProductModule } from "@medusajs/medusa/product"
export async function GET(request: Request) {
const productModuleService = await initializeProductModule()
const categories = await productModuleService.listProductCategories()
return NextResponse.json({ categories })
}
```
</CodeTab>
</CodeTabs>
---
## Retrieve Category by Handle
<CodeTabs groupId="app-type">
<CodeTab value="medusa" label="Medusa API Router">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function POST(request: MedusaRequest, res: MedusaResponse) {
const productModuleService = request.scope.resolve(
Modules.PRODUCT
)
const data = await productModuleService.listProductCategories({
handle: request.params.handle,
})
res.json({ category: data[0] })
}
```
</CodeTab>
<CodeTab value="nextjs" label="Next.js App Router">
```ts
import { NextResponse } from "next/server"
import { initialize as initializeProductModule } from "@medusajs/medusa/product"
export async function GET(
request: Request,
{ params }: { params: Record<string, any> }
) {
const { handle } = params
const productModuleService = await initializeProductModule()
const data = await productModuleService.listProductCategories({
handle,
})
return NextResponse.json({ category: data[0] })
}
```
</CodeTab>
</CodeTabs>
---
## More Examples
The [Product Module's main service reference](/references/product) provides a reference to all the methods available for use with examples for each.
@@ -5,6 +5,7 @@ tags:
- pricing
- query
- tax
- server
---
export const metadata = {
@@ -4,6 +4,7 @@ tags:
- product
- pricing
- query
- server
---
export const metadata = {
@@ -50,8 +50,8 @@ To retrieve the line items of a product, pass `line_items.*` in `fields`.
const { data: variants } = await query.graph({
entity: "variant",
fields: [
"line_items.*"
]
"line_items.*",
],
})
// variants.line_items
@@ -68,8 +68,8 @@ import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
const { data: variants } = useQueryGraphStep({
entity: "variant",
fields: [
"line_items.*"
]
"line_items.*",
],
})
// variants.line_items
@@ -101,8 +101,8 @@ To retrieve the inventory items of a product variant with [Query](!docs!/learn/f
const { data: variants } = await query.graph({
entity: "variant",
fields: [
"inventory_items.*"
]
"inventory_items.*",
],
})
// variants.inventory_items
@@ -119,8 +119,8 @@ import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
const { data: variants } = useQueryGraphStep({
entity: "variant",
fields: [
"inventory_items.*"
]
"inventory_items.*",
],
})
// variants.inventory_items
@@ -199,8 +199,8 @@ To retrieve a product's order line items, pass `order_items.*` in `fields`.
const { data: variants } = await query.graph({
entity: "variant",
fields: [
"order_items.*"
]
"order_items.*",
],
})
// variants.order_items
@@ -217,8 +217,8 @@ import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
const { data: variants } = useQueryGraphStep({
entity: "variant",
fields: [
"order_items.*"
]
"order_items.*",
],
})
// variants.order_items
@@ -250,8 +250,8 @@ To retrieve the price set of a variant with [Query](!docs!/learn/fundamentals/mo
const { data: variants } = await query.graph({
entity: "variant",
fields: [
"price_set.*"
]
"price_set.*",
],
})
// variants.price_set
@@ -268,8 +268,8 @@ import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
const { data: variants } = useQueryGraphStep({
entity: "variant",
fields: [
"price_set.*"
]
"price_set.*",
],
})
// variants.price_set
@@ -343,8 +343,8 @@ To retrieve the sales channels of a product with [Query](!docs!/learn/fundamenta
const { data: products } = await query.graph({
entity: "product",
fields: [
"sales_channels.*"
]
"sales_channels.*",
],
})
// products.sales_channels
@@ -361,8 +361,8 @@ import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
const { data: products } = useQueryGraphStep({
entity: "product",
fields: [
"sales_channels.*"
]
"sales_channels.*",
],
})
// products.sales_channels
@@ -6,114 +6,166 @@ export const metadata = {
# {metadata.title}
The Product Module provides product-related features in your Medusa and Node.js applications.
In this section of the documentation, you will find resources to learn more about the Product Module and how to use it in your application.
## How to Use Product Module's Service
Medusa has product related features available out-of-the-box through the Product Module. A [module](!docs!/learn/fundamentals/modules) is a standalone package that provides features for a single domain. Each of Medusa's commerce features are placed in commerce modules, such as this Product Module.
You can use the Product Module's main service by resolving from the Medusa container the resource `Modules.PRODUCT`.
<Note>
Learn more about why modules are isolated in [this documentation](!docs!/learn/fundamentals/modules/isolation).
</Note>
## Product Features
- [Products Management](/references/product/models/Product): Store and manage products. Products have custom options, such as color or size, and each variant in the product sets the value for these options.
- [Product Organization](/references/product/models): The Product Module provides different data models used to organize products, including categories, collections, tags, and more.
---
## How to Use the Product Module
In your Medusa application, you build flows around commerce modules. A flow is built as a [Workflow](!docs!/learn/fundamentals/workflows), which is a special function composed of a series of steps that guarantees data consistency and reliable roll-back mechanism.
You can build custom workflows and steps. You can also re-use Medusa's workflows and steps, which are provided by the `@medusajs/medusa/core-flows` package.
For example:
<CodeTabs groupId="resource-type">
<CodeTab label="Workflow Step" value="workflow-step">
export const highlights = [
["12", "Modules.PRODUCT", "Resolve the module in a step."]
]
```ts title="src/workflows/hello-world/step1.ts"
import { createStep } from "@medusajs/framework/workflows-sdk"
```ts title="src/workflows/create-product.ts" highlights={highlights}
import {
createWorkflow,
WorkflowResponse,
createStep,
StepResponse,
} from "@medusajs/framework/workflows-sdk"
import { Modules } from "@medusajs/framework/utils"
const step1 = createStep("step-1", async (_, { container }) => {
const productModuleService = container.resolve(
Modules.PRODUCT
)
const createProductStep = createStep(
"create-product",
async ({}, { container }) => {
const productService = container.resolve(Modules.PRODUCT)
const products = await productModuleService.listProducts()
})
const product = await productService.createProducts({
title: "Medusa Shirt",
options: [
{
title: "Color",
values: ["Black", "White"],
},
],
variants: [
{
title: "Black Shirt",
options: {
Color: "Black",
},
},
],
})
return new StepResponse({ product }, product.id)
},
async (productId, { container }) => {
if (!productId) {
return
}
const productService = container.resolve(Modules.PRODUCT)
await productService.deleteProducts([productId])
}
)
export const createProductWorkflow = createWorkflow(
"create-product",
() => {
const { product } = createProductStep()
return new WorkflowResponse({
product,
})
}
)
```
</CodeTab>
You can then execute the workflow in your custom API routes, scheduled jobs, or subscribers:
<CodeTabs group="resource-types">
<CodeTab label="API Route" value="api-route">
```ts title="src/api/workflow/route.ts" highlights={[["11"], ["12"]]} collapsibleLines="1-6" expandButtonLabel="Show Imports"
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/framework/http"
import { createProductWorkflow } from "../../workflows/create-product"
```ts title="src/api/store/custom/route.ts"
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { Modules } from "@medusajs/framework/utils"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
) {
const { result } = await createProductWorkflow(req.scope)
.run()
export async function GET(request: MedusaRequest, res: MedusaResponse) {
const productModuleService = request.scope.resolve(
Modules.PRODUCT
)
res.json({
products: await productModuleService.listProducts(),
})
res.send(result)
}
```
</CodeTab>
<CodeTab label="Subscriber" value="subscribers">
<CodeTab label="Subscriber" value="subscriber">
```ts title="src/subscribers/user-created.ts" highlights={[["11"], ["12"]]} collapsibleLines="1-6" expandButtonLabel="Show Imports"
import {
type SubscriberConfig,
type SubscriberArgs,
} from "@medusajs/framework"
import { createProductWorkflow } from "../workflows/create-product"
```ts title="src/subscribers/custom-handler.ts"
import { SubscriberArgs } from "@medusajs/framework"
import { Modules } from "@medusajs/framework/utils"
export default async function handleUserCreated({
event: { data },
container,
}: SubscriberArgs<{ id: string }>) {
const { result } = await createProductWorkflow(container)
.run()
export default async function subscriberHandler({ container }: SubscriberArgs) {
const productModuleService = container.resolve(
Modules.PRODUCT
)
console.log(result)
}
const products = await productModuleService.listProducts()
export const config: SubscriberConfig = {
event: "user.created",
}
```
</CodeTab>
<CodeTab label="Scheduled Job" value="scheduled-job">
```ts title="src/jobs/run-daily.ts" highlights={[["7"], ["8"]]}
import { MedusaContainer } from "@medusajs/framework/types"
import { createProductWorkflow } from "../workflows/create-product"
export default async function myCustomJob(
container: MedusaContainer
) {
const { result } = await createProductWorkflow(container)
.run()
console.log(result)
}
export const config = {
name: "run-once-a-day",
schedule: `0 0 * * *`,
}
```
</CodeTab>
</CodeTabs>
Learn more about workflows in [this documentation](!docs!/learn/fundamentals/workflows).
---
## Features
### Products Management
Store and manage products. Products have custom options, such as color or size, and each variant in the product sets the value for these options.
```ts
const products = await productService.createProducts([
{
title: "Medusa Shirt",
options: [
{
title: "Color",
values: ["Black", "White"],
},
],
variants: [
{
title: "Black Shirt",
options: {
Color: "Black",
},
},
],
},
])
```
### Product Organization
The Product Module provides different data models used to organize products, including categories, collections, tags, and more.
```ts
const category = await productService.createProductCategories({
name: "Shirts",
})
const products = await productService.updateProducts([
{
id: product.id,
categories: [
{
id: category.id,
},
],
},
])
```
<CommerceModuleSections name="Product" />