docs: add Query documentation (#9079)
- Replace remote query documentation with new Query documentation - Add redirect from old remote query to new query documentation - Update remote query usages across docs to use new query usage.
This commit is contained in:
@@ -17,7 +17,7 @@ export const arrowHighlights = [
|
||||
|
||||
```ts highlights={arrowHighlights}
|
||||
// Don't
|
||||
function ProductWidget () {
|
||||
function ProductWidget() {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ const ProductWidget = () => {
|
||||
}
|
||||
|
||||
fetch(`/admin/products`, {
|
||||
credentials: "include"
|
||||
credentials: "include",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(({ count }) => {
|
||||
|
||||
@@ -256,7 +256,7 @@ import {
|
||||
defineMiddlewares,
|
||||
MedusaNextFunction,
|
||||
MedusaRequest,
|
||||
MedusaResponse
|
||||
MedusaResponse,
|
||||
} from "@medusajs/medusa"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
|
||||
@@ -268,9 +268,9 @@ export default defineMiddlewares({
|
||||
next: MedusaNextFunction
|
||||
) => {
|
||||
res.status(400).json({
|
||||
error: "Something happened."
|
||||
error: "Something happened.",
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ For example:
|
||||
```ts title="src/api/admin/custom/route.ts" highlights={[["15"]]}
|
||||
import type {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse
|
||||
MedusaResponse,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
export const GET = async (
|
||||
|
||||
@@ -17,14 +17,14 @@ export const jsonHighlights = [
|
||||
]
|
||||
|
||||
```ts title="src/api/store/custom/route.ts" highlights={jsonHighlights} apiTesting testApiUrl="http://localhost:9000/store/custom" testApiMethod="GET"
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
|
||||
|
||||
export const GET = async (
|
||||
req: MedusaRequest,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
res.json({
|
||||
message: "Hello, World!"
|
||||
message: "Hello, World!",
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -52,14 +52,14 @@ export const statusHighlight = [
|
||||
]
|
||||
|
||||
```ts title="src/api/store/custom/route.ts" highlights={statusHighlight} apiTesting testApiUrl="http://localhost:9000/store/custom" testApiMethod="GET"
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
|
||||
|
||||
export const GET = async (
|
||||
req: MedusaRequest,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
res.status(201).json({
|
||||
message: "Hello, World!"
|
||||
message: "Hello, World!",
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -84,7 +84,7 @@ export const streamHighlights = [
|
||||
]
|
||||
|
||||
```ts highlights={streamHighlights}
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
|
||||
|
||||
export const GET = async (
|
||||
req: MedusaRequest,
|
||||
|
||||
@@ -27,7 +27,7 @@ import { z } from "zod"
|
||||
|
||||
export const PostStoreCustomSchema = z.object({
|
||||
a: z.number(),
|
||||
b: z.number()
|
||||
b: z.number(),
|
||||
})
|
||||
```
|
||||
|
||||
@@ -48,7 +48,7 @@ For example, create the file `src/api/middlewares.ts` with the following content
|
||||
```ts title="src/api/middlewares.ts"
|
||||
import { defineMiddlewares } from "@medusajs/medusa"
|
||||
import {
|
||||
validateAndTransformBody
|
||||
validateAndTransformBody,
|
||||
} from "@medusajs/medusa/dist/api/utils/validate-body"
|
||||
import { PostStoreCustomSchema } from "./store/custom/validators"
|
||||
|
||||
@@ -58,7 +58,7 @@ export default defineMiddlewares({
|
||||
matcher: "/store/custom",
|
||||
method: "POST",
|
||||
middlewares: [
|
||||
validateAndTransformBody(PostStoreCustomSchema)
|
||||
validateAndTransformBody(PostStoreCustomSchema),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -87,9 +87,9 @@ export const routeHighlights = [
|
||||
]
|
||||
|
||||
```ts title="src/api/store/custom/route.ts" highlights={routeHighlights}
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
|
||||
import { z } from "zod"
|
||||
import { PostStoreCustomSchema } from "./validators";
|
||||
import { PostStoreCustomSchema } from "./validators"
|
||||
|
||||
type PostStoreCustomSchemaType = z.infer<
|
||||
typeof PostStoreCustomSchema
|
||||
@@ -100,7 +100,7 @@ export const POST = async (
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
res.json({
|
||||
sum: req.validatedBody.a + req.validatedBody.b
|
||||
sum: req.validatedBody.a + req.validatedBody.b,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
@@ -84,7 +84,7 @@ export const retrieveHighlights = [
|
||||
const product = await helloModuleService.retrieveProduct(
|
||||
"123",
|
||||
{
|
||||
relations: ["orders"]
|
||||
relations: ["orders"],
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
@@ -22,10 +22,10 @@ export const highlights = [
|
||||
|
||||
```ts highlights={highlights}
|
||||
import {
|
||||
createWorkflow
|
||||
createWorkflow,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import {
|
||||
emitEventStep
|
||||
emitEventStep,
|
||||
} from "@medusajs/core-flows"
|
||||
|
||||
const helloWorldWorkflow = createWorkflow(
|
||||
@@ -36,8 +36,8 @@ const helloWorldWorkflow = createWorkflow(
|
||||
emitEventStep({
|
||||
eventName: "custom.created",
|
||||
data: {
|
||||
id: "123"
|
||||
}
|
||||
id: "123",
|
||||
},
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
import { TypeList, Tabs, TabsList, TabsTriggerVertical, TabsContent, TabsContentWrapper } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Query`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn about the Query utility and how to use it to fetch data from modules.
|
||||
|
||||
<Note>
|
||||
|
||||
Remote Query is now deprecated in favor of Query. Follow this documentation to see the difference in the usage.
|
||||
|
||||
</Note>
|
||||
|
||||
## What is Query?
|
||||
|
||||
Query fetches data across modules. It’s a set of methods registered in the Medusa container under the `query` key.
|
||||
|
||||
In your resources, such as API routes or workflows, you can resolve Query to fetch data across custom modules and Medusa’s commerce modules.
|
||||
|
||||
---
|
||||
|
||||
## Query Example
|
||||
|
||||
For example, create the route `src/api/store/query/route.ts` with the following content:
|
||||
|
||||
export const exampleHighlights = [
|
||||
["13", "", "Resolve Query from the Medusa container."],
|
||||
["15", "graph", "Run a query to retrieve data."],
|
||||
["16", "entryPoint", "The name of the data model you're querying."],
|
||||
["17", "fields", "An array of the data model’s properties to retrieve in the result."],
|
||||
]
|
||||
|
||||
```ts title="src/api/store/query/route.ts" highlights={exampleHighlights} apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query" collapsibleLines="1-8" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/medusa"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
export const GET = async (
|
||||
req: MedusaRequest,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||
|
||||
const { data: myCustoms } = await query.graph({
|
||||
entryPoint: "my_custom",
|
||||
fields: ["id", "name"],
|
||||
})
|
||||
|
||||
res.json({ my_customs: myCustoms })
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, you resolve Query from the Medusa container using the `ContainerRegistrationKeys.QUERY` (`query`) key.
|
||||
|
||||
Then, you run a query using its `graph` method. This method accepts as a parameter an object with the following required properties:
|
||||
|
||||
- `entryPoint`: The data model's name, as specified in the first parameter of the `model.define` method used for the data model's definition.
|
||||
- `fields`: An array of the data model’s properties to retrieve in the result.
|
||||
|
||||
The method returns an object that has a `data` property, which holds an array of the retrieved data. For example:
|
||||
|
||||
```json title="Returned Data"
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "123",
|
||||
"name": "test"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Retrieve Linked Records
|
||||
|
||||
Retrieve the records of a linked data model by passing in `fields` the data model's name suffixed with `.*`.
|
||||
|
||||
For example:
|
||||
|
||||
```ts highlights={[["6"]]}
|
||||
const { data: myCustoms } = await query.graph({
|
||||
entryPoint: "my_custom",
|
||||
fields: [
|
||||
"id",
|
||||
"name",
|
||||
"product.*",
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
`.*` means that all of data model's properties should be retrieved. To retrieve a specific property, replace the `*` with the property's name. For example, `product.title`.
|
||||
|
||||
</Note>
|
||||
|
||||
### Retrieve List Link Records
|
||||
|
||||
If the linked data model has `isList` enabled in the link definition, pass in `fields` the data model's plural name suffixed with `.*`.
|
||||
|
||||
For example:
|
||||
|
||||
```ts highlights={[["6"]]}
|
||||
const { data: myCustoms } = await query.graph({
|
||||
entryPoint: "my_custom",
|
||||
fields: [
|
||||
"id",
|
||||
"name",
|
||||
"products.*",
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Apply Filters
|
||||
|
||||
```ts highlights={[["6"], ["7"], ["8"], ["9"]]}
|
||||
const { data: myCustoms } = await query.graph({
|
||||
entryPoint: "my_custom",
|
||||
fields: ["id", "name"],
|
||||
variables: {
|
||||
filters: {
|
||||
id: [
|
||||
"mc_01HWSVWR4D2XVPQ06DQ8X9K7AX",
|
||||
"mc_01HWSVWK3KYHKQEE6QGS2JC3FX",
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
Filters don't apply on fields of linked data models from other modules.
|
||||
|
||||
</Note>
|
||||
|
||||
The `query.graph` function accepts a `variables` property. You can use this property to filter retrieved records.
|
||||
|
||||
<TypeList
|
||||
types={[
|
||||
{
|
||||
name: "variables",
|
||||
type: "`object`",
|
||||
description: "Variables to pass to the query.",
|
||||
children: [
|
||||
{
|
||||
name: "filters",
|
||||
type: "`object`",
|
||||
description: "The filters to apply on any of the data model's properties."
|
||||
}
|
||||
]
|
||||
},
|
||||
]}
|
||||
sectionTitle="Apply Filters"
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
## Sort Records
|
||||
|
||||
```ts highlights={[["5"], ["6"], ["7"]]}
|
||||
const { data: myCustoms } = await query.graph({
|
||||
entryPoint: "my_custom",
|
||||
fields: ["id", "name"],
|
||||
variables: {
|
||||
order: {
|
||||
name: "DESC",
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
Sorting doesn't work on fields of linked data models from other modules.
|
||||
|
||||
</Note>
|
||||
|
||||
To sort returned records, pass an `order` property to `variables`.
|
||||
|
||||
The `order` property is an object whose keys are property names, and values are either:
|
||||
|
||||
- `ASC` to sort records by that property in ascending order.
|
||||
- `DESC` to sort records by that property in descending order.
|
||||
|
||||
---
|
||||
|
||||
## Apply Pagination
|
||||
|
||||
```ts highlights={[["8", "skip", "The number of records to skip before fetching the results."], ["9", "take", "The number of records to fetch."]]}
|
||||
const {
|
||||
data: myCustoms,
|
||||
metadata: { count, take, skip },
|
||||
} = await query.graph({
|
||||
entryPoint: "my_custom",
|
||||
fields: ["id", "name"],
|
||||
variables: {
|
||||
skip: 0,
|
||||
take: 10,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
To paginate the returned records, pass the following properties to `variables`:
|
||||
|
||||
- `skip`: (required to apply pagination) The number of records to skip before fetching the results.
|
||||
- `take`: The number of records to fetch.
|
||||
|
||||
When you provide the pagination fields, the `query.graph` method's returned object has a `metadata` property. Its value is an object having the following properties:
|
||||
|
||||
<TypeList types={[
|
||||
{
|
||||
name: "skip",
|
||||
type: "`number`",
|
||||
description: "The number of records skipped."
|
||||
},
|
||||
{
|
||||
name: "take",
|
||||
type: "`number`",
|
||||
description: "The number of records requested to fetch."
|
||||
},
|
||||
{
|
||||
name: "count",
|
||||
type: "`number`",
|
||||
description: "The total number of records."
|
||||
}
|
||||
]} sectionTitle="Apply Pagination" />
|
||||
@@ -1,410 +0,0 @@
|
||||
import { TypeList, Tabs, TabsList, TabsTriggerVertical, TabsContent, TabsContentWrapper } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Remote Query`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn about the remote query and how to use it to fetch data from modules.
|
||||
|
||||
## What is the Remote Query?
|
||||
|
||||
The remote query fetches data across modules. It’s a function registered in the Medusa container under the `remoteQuery` key.
|
||||
|
||||
In your resources, such as API routes or workflows, you can resolve the remote query to fetch data across custom modules and Medusa’s commerce modules.
|
||||
|
||||
---
|
||||
|
||||
## Remote Query Example
|
||||
|
||||
For example, create the route `src/api/store/query/route.ts` with the following content:
|
||||
|
||||
export const exampleHighlights = [
|
||||
["18", "", "Resolve the remote query from the Medusa container."],
|
||||
["21", "remoteQueryObjectFromString", "Utility function to build the query."],
|
||||
["22", "entryPoint", "The name of the data model you're querying."],
|
||||
["23", "fields", "An array of the data model’s properties to retrieve in the result."],
|
||||
["27", "remoteQuery", "Run the query using the remote query."]
|
||||
]
|
||||
|
||||
```ts title="src/api/store/query/route.ts" highlights={exampleHighlights} apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query" collapsibleLines="1-12" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/medusa"
|
||||
import {
|
||||
remoteQueryObjectFromString,
|
||||
ContainerRegistrationKeys,
|
||||
} from "@medusajs/utils"
|
||||
import type {
|
||||
RemoteQueryFunction,
|
||||
} from "@medusajs/modules-sdk"
|
||||
|
||||
export async function GET(
|
||||
req: MedusaRequest,
|
||||
res: MedusaResponse
|
||||
): Promise<void> {
|
||||
const remoteQuery: RemoteQueryFunction = req.scope.resolve(
|
||||
ContainerRegistrationKeys.REMOTE_QUERY
|
||||
)
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "my_custom",
|
||||
fields: ["id", "name"],
|
||||
})
|
||||
|
||||
res.json({
|
||||
my_customs: await remoteQuery(query),
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, you resolve `remoteQuery` from the Medusa container.
|
||||
|
||||
Then, you create a query using the `remoteQueryObjectFromString` utility function imported from `@medusajs/utils`. This function accepts as a parameter an object with the following required properties:
|
||||
|
||||
- `entryPoint`: The data model's name, as specified in the first parameter of the `model.define` method used for the data model's definition.
|
||||
- `fields`: An array of the data model’s properties to retrieve in the result.
|
||||
|
||||
You then pass the query to the `remoteQuery` function to retrieve the results.
|
||||
|
||||
---
|
||||
|
||||
## Retrieve Linked Records
|
||||
|
||||
Retrieve the records of a linked data model by passing in `fields` the data model's name suffixed with `.*`.
|
||||
|
||||
For example:
|
||||
|
||||
```ts highlights={[["6"]]}
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "my_custom",
|
||||
fields: [
|
||||
"id",
|
||||
"name",
|
||||
"product.*",
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
`.*` means that all of data model's properties should be retrieved. To retrieve a specific property, replace the `*` with the property's name. For example, `product.title`.
|
||||
|
||||
</Note>
|
||||
|
||||
### Retrieve List Link Records
|
||||
|
||||
If the linked data model has `isList` enabled in the link definition, pass in `fields` the data model's plural name suffixed with `.*`.
|
||||
|
||||
For example:
|
||||
|
||||
```ts highlights={[["6"]]}
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "my_custom",
|
||||
fields: [
|
||||
"id",
|
||||
"name",
|
||||
"products.*",
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Apply Filters
|
||||
|
||||
```ts highlights={[["6"], ["7"], ["8"], ["9"]]}
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "my_custom",
|
||||
fields: ["id", "name"],
|
||||
variables: {
|
||||
filters: {
|
||||
id: [
|
||||
"mc_01HWSVWR4D2XVPQ06DQ8X9K7AX",
|
||||
"mc_01HWSVWK3KYHKQEE6QGS2JC3FX",
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const result = await remoteQuery(query)
|
||||
```
|
||||
|
||||
The `remoteQueryObjectFromString` function accepts a `variables` property. You can use this property to filter retrieved records.
|
||||
|
||||
<TypeList
|
||||
types={[
|
||||
{
|
||||
name: "variables",
|
||||
type: "`object`",
|
||||
description: "Variables to pass to the query.",
|
||||
children: [
|
||||
{
|
||||
name: "filters",
|
||||
type: "`object`",
|
||||
description: "The filters to apply on any of the data model's properties."
|
||||
}
|
||||
]
|
||||
},
|
||||
]}
|
||||
sectionTitle="Apply Filters"
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
## Sort Records
|
||||
|
||||
```ts highlights={[["5"], ["6"], ["7"]]}
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "my_custom",
|
||||
fields: ["id", "name"],
|
||||
variables: {
|
||||
order: {
|
||||
name: "DESC",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const result = await remoteQuery(query)
|
||||
```
|
||||
|
||||
To sort returned records, pass an `order` property to `variables`.
|
||||
|
||||
The `order` property is an object whose keys are property names, and values are either:
|
||||
|
||||
- `ASC` to sort records by that property in ascending order.
|
||||
- `DESC` to sort records by that property in descending order.
|
||||
|
||||
---
|
||||
|
||||
## Apply Pagination
|
||||
|
||||
```ts highlights={[["5", "skip", "The number of records to skip before fetching the results."], ["6", "take", "The number of records to fetch."]]}
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "my_custom",
|
||||
fields: ["id", "name"],
|
||||
variables: {
|
||||
skip: 0,
|
||||
take: 10,
|
||||
},
|
||||
})
|
||||
|
||||
const {
|
||||
rows,
|
||||
metadata: { count, take, skip },
|
||||
} = await remoteQuery(query)
|
||||
```
|
||||
|
||||
To paginate the returned records, pass the following properties to `variables`:
|
||||
|
||||
- `skip`: (required to apply pagination) The number of records to skip before fetching the results.
|
||||
- `take`: The number of records to fetch.
|
||||
|
||||
When the pagination fields are provided, the `remoteQuery` returns an object having two properties:
|
||||
|
||||
<TypeList types={[
|
||||
{
|
||||
name: "rows",
|
||||
type: "`array`",
|
||||
description: "The returned records."
|
||||
},
|
||||
{
|
||||
name: "metadata",
|
||||
type: "`object`",
|
||||
description: "The pagination details",
|
||||
children: [
|
||||
{
|
||||
name: "skip",
|
||||
type: "`number`",
|
||||
description: "The number of records skipped."
|
||||
},
|
||||
{
|
||||
name: "take",
|
||||
type: "`number`",
|
||||
description: "The number of records requested to fetch."
|
||||
},
|
||||
{
|
||||
name: "count",
|
||||
type: "`number`",
|
||||
description: "The total number of records."
|
||||
}
|
||||
]
|
||||
}
|
||||
]} sectionTitle="Apply Pagination" />
|
||||
|
||||
---
|
||||
|
||||
## Using GraphQL
|
||||
|
||||
The remote query function alternatively accepts a string with GraphQL syntax as the query.
|
||||
|
||||
<Tabs defaultValue="basic" layoutType="vertical" className="mt-2">
|
||||
<TabsList>
|
||||
<TabsTriggerVertical value="basic">Basic Usage</TabsTriggerVertical>
|
||||
<TabsTriggerVertical value="filters">Apply Filters</TabsTriggerVertical>
|
||||
<TabsTriggerVertical value="sort">Sort Records</TabsTriggerVertical>
|
||||
<TabsTriggerVertical value="pagination">Apply Pagination</TabsTriggerVertical>
|
||||
</TabsList>
|
||||
<TabsContentWrapper>
|
||||
<TabsContent value="basic" className="[&_h3]:!mt-0">
|
||||
|
||||
### Basic GraphQL usage
|
||||
|
||||
```ts title="src/api/store/query/route.ts" apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query" collapsibleLines="1-10" expandButtonLabel="Show Imports"
|
||||
import {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "@medusajs/medusa"
|
||||
import { ContainerRegistrationKeys } from "@medusajs/utils"
|
||||
import type {
|
||||
RemoteQueryFunction,
|
||||
} from "@medusajs/modules-sdk"
|
||||
|
||||
export async function GET(
|
||||
req: MedusaRequest,
|
||||
res: MedusaResponse
|
||||
): Promise<void> {
|
||||
const remoteQuery: RemoteQueryFunction = req.scope.resolve(
|
||||
ContainerRegistrationKeys.REMOTE_QUERY
|
||||
)
|
||||
|
||||
const query = `
|
||||
query {
|
||||
my_custom {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const result = await remoteQuery(query)
|
||||
|
||||
res.json({
|
||||
my_customs: result,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
</TabsContent>
|
||||
<TabsContent value="filters" className="[&_h3]:!mt-0">
|
||||
|
||||
### Apply Filters with GraphQL
|
||||
|
||||
The `remoteQuery` function accepts as a second parameter an object of variables to reference in the GraphQL query.
|
||||
|
||||
```ts highlights={[["2"], ["3"], ["13"], ["14"], ["15"], ["16"]]}
|
||||
const query = `
|
||||
query($id: ID) {
|
||||
my_custom(id: $id) {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const result = await remoteQuery(
|
||||
query,
|
||||
{
|
||||
id: [
|
||||
"mc_01HWSVWR4D2XVPQ06DQ8X9K7AX",
|
||||
"mc_01HWSVWK3KYHKQEE6QGS2JC3FX",
|
||||
]
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
</TabsContent>
|
||||
<TabsContent value="sort" className="[&_h3]:!mt-0">
|
||||
|
||||
### Sort Records with GraphQL
|
||||
|
||||
To sort the records by a property, pass in the query an `order` argument whose value is an object. The object’s key is the property’s name, and the value is either:
|
||||
|
||||
- `ASC` to sort items by that property in ascending order.
|
||||
- `DESC` to sort items by that property in descending order.
|
||||
|
||||
For example:
|
||||
|
||||
```ts highlights={[["3"]]}
|
||||
const query = `
|
||||
query {
|
||||
my_custom(order: {name: DESC}) {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const result = await remoteQuery(query)
|
||||
```
|
||||
|
||||
</TabsContent>
|
||||
<TabsContent value="pagination" className="[&_h3]:!mt-0">
|
||||
|
||||
### Pagination with GraphQL
|
||||
|
||||
To paginate the records retrieved, pass a `skip` and `take` records in your query, and pass their values in the second parameter of the `remoteQuery` function.
|
||||
|
||||
For example:
|
||||
|
||||
```ts highlights={[["2"], ["3"]]}
|
||||
const query = `
|
||||
query($skip: Int, $take: Int) {
|
||||
my_custom(skip: $skip, take: $take) {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const {
|
||||
rows,
|
||||
metadata: { count, take, skip }
|
||||
} = await remoteQuery(
|
||||
query,
|
||||
{
|
||||
skip: 0,
|
||||
take: 10
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
This skips no records and returns the first `10` records.
|
||||
|
||||
When the pagination fields are provided, the `remoteQuery` returns an object having two properties:
|
||||
|
||||
<TypeList types={[
|
||||
{
|
||||
name: "rows",
|
||||
type: "`array`",
|
||||
description: "The returned records."
|
||||
},
|
||||
{
|
||||
name: "metadata",
|
||||
type: "`object`",
|
||||
description: "The pagination details",
|
||||
children: [
|
||||
{
|
||||
name: "skip",
|
||||
type: "`number`",
|
||||
description: "The number of records skipped."
|
||||
},
|
||||
{
|
||||
name: "take",
|
||||
type: "`number`",
|
||||
description: "The number of records requested to fetch."
|
||||
},
|
||||
{
|
||||
name: "count",
|
||||
type: "`number`",
|
||||
description: "The total number of records."
|
||||
}
|
||||
]
|
||||
}
|
||||
]} sectionTitle="Pagination with GraphQL" />
|
||||
|
||||
</TabsContent>
|
||||
</TabsContentWrapper>
|
||||
</Tabs>
|
||||
@@ -94,7 +94,7 @@ This property is an object that holds additional data passed to the workflow.
|
||||
To pass that additional data when executing the workflow, pass it as a parameter to the `.run` method of the workflow:
|
||||
|
||||
```ts highlights={[["10", "additional_data"]]}
|
||||
import type { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
|
||||
import type { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
|
||||
import { createProductsWorkflow } from "@medusajs/core-flows"
|
||||
|
||||
export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
||||
@@ -104,8 +104,8 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
||||
// ...
|
||||
],
|
||||
additional_data: {
|
||||
custom_field: "test"
|
||||
}
|
||||
custom_field: "test",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
+12
-12
@@ -29,7 +29,7 @@ export async function GET(
|
||||
res: MedusaResponse
|
||||
){
|
||||
res.json({
|
||||
message: "Hello, World!"
|
||||
message: "Hello, World!",
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -58,7 +58,7 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
@@ -107,7 +107,7 @@ And consider that the file `src/api/store/custom/route.ts` defines another route
|
||||
|
||||
```ts title="src/api/store/custom/route.ts"
|
||||
// other imports...
|
||||
import HelloModuleService from "../../../modules/hello/service";
|
||||
import HelloModuleService from "../../../modules/hello/service"
|
||||
|
||||
// ...
|
||||
|
||||
@@ -124,7 +124,7 @@ export async function POST(
|
||||
)
|
||||
|
||||
res.json({
|
||||
my_custom: myCustom
|
||||
my_custom: myCustom,
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -155,7 +155,7 @@ medusaIntegrationTestRunner({
|
||||
`/store/custom`,
|
||||
{
|
||||
id,
|
||||
name: "Test"
|
||||
name: "Test",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -170,7 +170,7 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
@@ -210,7 +210,7 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
@@ -223,8 +223,8 @@ The `afterAll` hook resolves the `HelloModuleService` and use its `deleteMyCusto
|
||||
Consider a `/store/custom/:id` API route created at `src/api/store/custom/[id]/route.ts`:
|
||||
|
||||
```ts title="src/api/store/custom/[id]/route.ts"
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
|
||||
import HelloModuleService from "../../../modules/hello/service";
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
|
||||
import HelloModuleService from "../../../modules/hello/service"
|
||||
|
||||
export async function DELETE(
|
||||
req: MedusaRequest,
|
||||
@@ -237,7 +237,7 @@ export async function DELETE(
|
||||
await helloModuleService.deleteMyCustoms(req.params.id)
|
||||
|
||||
res.json({
|
||||
success: true
|
||||
success: true,
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -266,7 +266,7 @@ medusaIntegrationTestRunner({
|
||||
|
||||
await helloModuleService.createMyCustoms({
|
||||
id,
|
||||
name: "Test"
|
||||
name: "Test",
|
||||
})
|
||||
})
|
||||
|
||||
@@ -281,7 +281,7 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ api, getContainer }) => {
|
||||
// TODO write tests...
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ import {
|
||||
createWorkflow,
|
||||
createStep,
|
||||
StepResponse,
|
||||
WorkflowResponse
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
|
||||
const step1 = createStep("step-1", () => {
|
||||
@@ -59,7 +59,7 @@ medusaIntegrationTestRunner({
|
||||
expect(result).toEqual("Hello, World!")
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ moduleIntegrationTestRunner<HelloModuleService>({
|
||||
expect(message).toEqual("Hello, World!")
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ moduleIntegrationTestRunner<HelloModuleService>({
|
||||
resolve: "./modules/hello",
|
||||
testSuite: ({ service }) => {
|
||||
// TODO write tests
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
@@ -88,7 +88,7 @@ import HelloModuleService from "../service"
|
||||
|
||||
moduleIntegrationTestRunner<HelloModuleService>({
|
||||
moduleOptions: {
|
||||
apiKey: "123"
|
||||
apiKey: "123",
|
||||
},
|
||||
// ...
|
||||
})
|
||||
@@ -108,7 +108,7 @@ import HelloModuleService from "../service"
|
||||
import { model } from "@medusajs/utils"
|
||||
|
||||
const DummyModel = model.define("dummy_model", {
|
||||
id: model.id().primaryKey()
|
||||
id: model.id().primaryKey(),
|
||||
})
|
||||
|
||||
moduleIntegrationTestRunner<HelloModuleService>({
|
||||
|
||||
@@ -41,8 +41,8 @@ npm install --save-dev jest @types/jest @swc/jest
|
||||
Then, create the file `jest.config.js` with the following content:
|
||||
|
||||
```js title="jest.config.js"
|
||||
const { loadEnv } = require('@medusajs/utils')
|
||||
loadEnv('test', process.cwd())
|
||||
const { loadEnv } = require("@medusajs/utils")
|
||||
loadEnv("test", process.cwd())
|
||||
|
||||
module.exports = {
|
||||
transform: {
|
||||
|
||||
@@ -6,7 +6,7 @@ export const generatedEditDates = {
|
||||
"app/basics/modules-and-services/page.mdx": "2024-09-03T07:45:28.079Z",
|
||||
"app/basics/commerce-modules/page.mdx": "2024-09-03T07:48:48.148Z",
|
||||
"app/advanced-development/workflows/retry-failed-steps/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||
"app/advanced-development/workflows/workflow-hooks/page.mdx": "2024-08-13T09:55:37+03:00",
|
||||
"app/advanced-development/workflows/workflow-hooks/page.mdx": "2024-09-10T11:39:51.168Z",
|
||||
"app/cheatsheet/page.mdx": "2024-07-11T13:53:40+03:00",
|
||||
"app/debugging-and-testing/logging/page.mdx": "2024-07-04T17:26:03+03:00",
|
||||
"app/more-resources/page.mdx": "2024-07-04T17:26:03+03:00",
|
||||
@@ -33,19 +33,19 @@ export const generatedEditDates = {
|
||||
"app/advanced-development/admin/widgets/page.mdx": "2024-08-06T09:44:22+02:00",
|
||||
"app/advanced-development/data-models/page.mdx": "2024-07-04T17:26:03+03:00",
|
||||
"app/advanced-development/modules/remote-link/page.mdx": "2024-07-24T09:16:01+02:00",
|
||||
"app/advanced-development/api-routes/protected-routes/page.mdx": "2024-09-04T10:11:25.860Z",
|
||||
"app/advanced-development/api-routes/protected-routes/page.mdx": "2024-09-10T11:39:51.166Z",
|
||||
"app/advanced-development/workflows/add-workflow-hook/page.mdx": "2024-08-13T09:55:37+03:00",
|
||||
"app/advanced-development/events-and-subscribers/data-payload/page.mdx": "2024-07-16T17:12:05+01:00",
|
||||
"app/advanced-development/data-models/default-properties/page.mdx": "2024-07-02T12:34:44+03:00",
|
||||
"app/advanced-development/workflows/advanced-example/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||
"app/advanced-development/events-and-subscribers/emit-event/page.mdx": "2024-08-05T11:39:47+03:00",
|
||||
"app/advanced-development/events-and-subscribers/emit-event/page.mdx": "2024-09-10T11:39:51.168Z",
|
||||
"app/advanced-development/workflows/conditions/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||
"app/advanced-development/modules/module-link-directions/page.mdx": "2024-07-24T09:16:01+02:00",
|
||||
"app/advanced-development/admin/page.mdx": "2024-05-29T13:50:19+03:00",
|
||||
"app/advanced-development/workflows/long-running-workflow/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||
"app/advanced-development/workflows/constructor-constraints/page.mdx": "2024-07-17T13:19:51+01:00",
|
||||
"app/advanced-development/data-models/write-migration/page.mdx": "2024-07-15T17:46:10+02:00",
|
||||
"app/advanced-development/data-models/manage-relationships/page.mdx": "2024-08-15T16:30:00+03:00",
|
||||
"app/advanced-development/data-models/manage-relationships/page.mdx": "2024-09-10T11:39:51.167Z",
|
||||
"app/advanced-development/modules/remote-query/page.mdx": "2024-07-21T21:20:24+02:00",
|
||||
"app/advanced-development/modules/options/page.mdx": "2024-08-05T07:23:49+00:00",
|
||||
"app/advanced-development/data-models/relationships/page.mdx": "2024-08-15T16:30:00+03:00",
|
||||
@@ -57,7 +57,7 @@ export const generatedEditDates = {
|
||||
"app/advanced-development/scheduled-jobs/execution-number/page.mdx": "2024-07-02T09:41:15+00:00",
|
||||
"app/advanced-development/api-routes/parameters/page.mdx": "2024-09-04T08:17:50.071Z",
|
||||
"app/advanced-development/api-routes/http-methods/page.mdx": "2024-09-04T08:15:11.609Z",
|
||||
"app/advanced-development/admin/tips/page.mdx": "2024-08-05T13:20:34+03:00",
|
||||
"app/advanced-development/admin/tips/page.mdx": "2024-09-10T11:39:51.165Z",
|
||||
"app/advanced-development/api-routes/cors/page.mdx": "2024-09-04T08:24:47.068Z",
|
||||
"app/advanced-development/admin/ui-routes/page.mdx": "2024-08-06T09:44:22+02:00",
|
||||
"app/advanced-development/api-routes/middlewares/page.mdx": "2024-09-04T09:45:12.441Z",
|
||||
@@ -66,14 +66,18 @@ export const generatedEditDates = {
|
||||
"app/advanced-development/data-models/index/page.mdx": "2024-07-04T17:26:03+03:00",
|
||||
"app/advanced-development/custom-cli-scripts/page.mdx": "2024-07-04T17:26:03+03:00",
|
||||
"app/advanced-development/data-models/property-types/page.mdx": "2024-07-04T17:26:03+03:00",
|
||||
"app/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2024-09-02T10:57:08.040Z",
|
||||
"app/debugging-and-testing/testing-tools/integration-tests/page.mdx": "2024-09-02T10:56:09.872Z",
|
||||
"app/debugging-and-testing/testing-tools/integration-tests/workflows/page.mdx": "2024-09-02T10:57:04.202Z",
|
||||
"app/debugging-and-testing/testing-tools/page.mdx": "2024-09-02T10:08:29.388Z",
|
||||
"app/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2024-09-10T11:39:51.170Z",
|
||||
"app/debugging-and-testing/testing-tools/integration-tests/page.mdx": "2024-09-10T11:39:51.170Z",
|
||||
"app/debugging-and-testing/testing-tools/integration-tests/workflows/page.mdx": "2024-09-10T11:39:51.171Z",
|
||||
"app/debugging-and-testing/testing-tools/page.mdx": "2024-09-10T11:39:51.172Z",
|
||||
"app/debugging-and-testing/testing-tools/unit-tests/module-example/page.mdx": "2024-09-02T11:04:27.232Z",
|
||||
"app/debugging-and-testing/testing-tools/unit-tests/page.mdx": "2024-09-02T11:03:26.997Z",
|
||||
"app/advanced-development/api-routes/page.mdx": "2024-09-04T09:36:33.961Z",
|
||||
"app/advanced-development/api-routes/responses/page.mdx": "2024-09-04T09:40:38.986Z",
|
||||
"app/advanced-development/api-routes/validation/page.mdx": "2024-09-04T09:50:52.129Z",
|
||||
"app/advanced-development/api-routes/errors/page.mdx": "2024-09-04T11:03:55.017Z"
|
||||
"app/advanced-development/api-routes/responses/page.mdx": "2024-09-10T11:39:51.167Z",
|
||||
"app/advanced-development/api-routes/validation/page.mdx": "2024-09-10T11:39:51.167Z",
|
||||
"app/advanced-development/api-routes/errors/page.mdx": "2024-09-10T11:39:51.166Z",
|
||||
"app/advanced-development/admin/constraints/page.mdx": "2024-09-10T11:39:51.165Z",
|
||||
"app/advanced-development/modules/query/page.mdx": "2024-09-10T11:39:51.168Z",
|
||||
"app/debugging-and-testing/testing-tools/modules-tests/module-example/page.mdx": "2024-09-10T11:39:51.171Z",
|
||||
"app/debugging-and-testing/testing-tools/modules-tests/page.mdx": "2024-09-10T11:39:51.171Z"
|
||||
}
|
||||
@@ -127,6 +127,15 @@ const nextConfig = {
|
||||
],
|
||||
}
|
||||
},
|
||||
async redirects() {
|
||||
return [
|
||||
{
|
||||
source: "/advanced-development/modules/remote-query",
|
||||
destination: "/advanced-development/modules/query",
|
||||
permanent: true,
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
export default withMDX(nextConfig)
|
||||
|
||||
@@ -172,8 +172,8 @@ export const sidebar = numberSidebarItems(
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
path: "/advanced-development/modules/remote-query",
|
||||
title: "Remote Query",
|
||||
path: "/advanced-development/modules/query",
|
||||
title: "Query",
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
|
||||
Reference in New Issue
Block a user