Skip to content

Commit 7bf8ecc

Browse files
authored
docs: update list of resources in module containers + conventions on loaders (medusajs#13107)
1 parent fcb8036 commit 7bf8ecc

File tree

8 files changed

+373
-81
lines changed

8 files changed

+373
-81
lines changed

www/apps/book/app/learn/fundamentals/data-models/json-properties/page.mdx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ const brand = await brandModuleService.updateBrands({
9797
id: "brand_123",
9898
metadata: {
9999
category: "electronics",
100-
}
100+
},
101101
})
102102
```
103103

@@ -119,7 +119,7 @@ const brand = await brandModuleService.updateBrands({
119119
id: "brand_123",
120120
metadata: {
121121
is_featured: true,
122-
}
122+
},
123123
})
124124
```
125125

@@ -146,7 +146,7 @@ const brand = await brandModuleService.updateBrands({
146146
id: "brand_123",
147147
metadata: {
148148
category: "home appliances",
149-
}
149+
},
150150
})
151151
```
152152

@@ -189,9 +189,9 @@ const brand = await brandModuleService.updateBrands({
189189
metadata: {
190190
details: {
191191
warranty: "2 years",
192-
origin: "China"
193-
}
194-
}
192+
origin: "China",
193+
},
194+
},
195195
})
196196
```
197197

@@ -221,7 +221,7 @@ const brand = await brandModuleService.updateBrands({
221221
id: "brand_123",
222222
metadata: {
223223
is_featured: "",
224-
}
224+
},
225225
})
226226
```
227227

www/apps/book/app/learn/fundamentals/modules/container/page.mdx

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ export const metadata = {
44

55
# {metadata.title}
66

7-
In this chapter, you'll learn about the module's container and how to resolve resources in that container.
7+
In this chapter, you'll learn about the module container and how to resolve resources from it.
88

9-
Since modules are [isolated](../isolation/page.mdx), each module has a local container only used by the resources of that module.
9+
Since modules are [isolated](../isolation/page.mdx), each module has a local container used only by the resources of that module.
1010

1111
So, resources in the module, such as services or loaders, can only resolve other resources registered in the module's container, and some Framework tools that the Medusa application registers in the module's container.
1212

@@ -16,13 +16,13 @@ Find a list of resources or dependencies registered in a module's container in [
1616

1717
---
1818

19-
## Resolve Resources
19+
## Resolve Resources from the Module Container
2020

21-
### Services
21+
### Resolve in Services
2222

23-
A service's constructor accepts as a first parameter an object used to resolve resources registered in the module's container.
23+
A service's constructor accepts as a first parameter an object used to resolve resources registered in the module's container. To resolve a resource, add the resource's registration name as a property of the object.
2424

25-
For example:
25+
For example, to resolve the [Logger](../../../debugging-and-testing/logging/page.mdx) from the container:
2626

2727
```ts highlights={[["4"], ["10"]]}
2828
import { Logger } from "@medusajs/framework/types"
@@ -44,11 +44,13 @@ export default class BlogModuleService {
4444
}
4545
```
4646

47-
### Loader
47+
You can then use the logger in the service's methods.
4848

49-
A loader function accepts as a parameter an object having the property `container`. Its value is the module's container used to resolve resources.
49+
### Resolve in Loaders
5050

51-
For example:
51+
[Loaders](../loaders/page.mdx) accept an object parameter with the property `container`. Its value is the module's container that can be used to resolve resources using its `resolve` method.
52+
53+
For example, to resolve the [Logger](../../../debugging-and-testing/logging/page.mdx) in a loader:
5254

5355
```ts highlights={[["9"]]}
5456
import {
@@ -66,3 +68,69 @@ export default async function helloWorldLoader({
6668
logger.info("[helloWorldLoader]: Hello, World!")
6769
}
6870
```
71+
72+
You can then use the logger in the loader's code.
73+
74+
---
75+
76+
## Caveat: Resolving Module Services in Loaders
77+
78+
Consider a module that has a main service `BrandModuleService`, and an internal service `CmsService`. Medusa will register both of these services in the module's container.
79+
80+
However, loaders are executed before any services are initialized and registered in the module's container. So, you can't resolve the `BrandModuleService` and `CmsService` in a loader.
81+
82+
Instead, if your main service extends the `MedusaService` [service factory](../service-factory/page.mdx), you can resolve the internal services generated for each data model passed to the `MedusaService` function.
83+
84+
For example, if the `BrandModuleService` is defined as follows:
85+
86+
```ts
87+
import { MedusaService } from "@medusajs/framework/utils"
88+
import Brand from "./models/brand"
89+
90+
class BrandModuleService extends MedusaService({
91+
Brand,
92+
}) {
93+
}
94+
95+
export default BrandModuleService
96+
```
97+
98+
Then, you can resolve the `brandService` that allows you to manage brands in the module's loader:
99+
100+
```ts
101+
import {
102+
LoaderOptions,
103+
} from "@medusajs/framework/types"
104+
105+
export default async function helloWorldLoader({
106+
container,
107+
}: LoaderOptions) {
108+
const brandService = container.resolve("brandService")
109+
110+
const brands = await brandService.list()
111+
112+
console.log("[helloWorldLoader]: Brands:", brands)
113+
}
114+
```
115+
116+
Refer to the [Service Factory reference](!resources!/service-factory-reference) for details on the available methods in the generated services.
117+
118+
---
119+
120+
## Alternative to Resolving Other Modules' Services
121+
122+
Since modules are [isolated](../isolation/page.mdx), you can't resolve resources that belong to other modules from the module's container. For example, you can't resolve the Product Module's service in the Blog Module's service.
123+
124+
Instead, to build commerce features that span multiple modules, you can create [workflows](../../workflows/page.mdx). In those workflows, you can resolve services of all modules registered in the Medusa application, including the services of the Product and Blog modules.
125+
126+
Then, you can execute the workflows in [API routes](../../api-routes/page.mdx), [subscribers](../../events-and-subscribers/page.mdx), or [scheduled jobs](../../scheduled-jobs/page.mdx).
127+
128+
Learn more and find examples in the [Module Isolation](../isolation/page.mdx) chapter.
129+
130+
---
131+
132+
## Avoid Circular Dependencies
133+
134+
When resolving resources in a module's services, make sure you don't create circular dependencies. For example, if `BlogModuleService` resolves `CmsService`, and `CmsService` resolves `BlogModuleService`, it will cause a circular dependency error.
135+
136+
Instead, you should generally only resolve services within the main service. For example, `BlogModuleService` can resolve `CmsService`, but `CmsService` should not resolve `BlogModuleService`.

www/apps/book/app/learn/fundamentals/modules/service-factory/page.mdx

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ In this chapter, you’ll learn about what the service factory is and how to use
1212

1313
Medusa provides a service factory that your module’s main service can extend.
1414

15-
The service factory generates data management methods for your data models in the database, so you don't have to implement these methods manually.
15+
The service factory generates data management methods for your data models, saving you time on implementing these methods manually.
1616

1717
<Note title="Extend the service factory when" type="success">
1818

19-
Your service provides data-management functionalities of your data models.
19+
Your service provides data-management functionality for your data models.
2020

2121
</Note>
2222

@@ -48,15 +48,15 @@ export default BlogModuleService
4848

4949
### MedusaService Parameters
5050

51-
The `MedusaService` function accepts one parameter, which is an object of data models to generate data-management methods for.
51+
The `MedusaService` function accepts one parameter, which is an object of data models for which to generate data-management methods.
5252

5353
In the example above, since the `BlogModuleService` extends `MedusaService`, it has methods to manage the `Post` data model, such as `createPosts`.
5454

5555
### Generated Methods
5656

5757
The service factory generates methods to manage the records of each of the data models provided in the first parameter in the database.
5858

59-
The method's names are the operation's name, suffixed by the data model's key in the object parameter passed to `MedusaService`.
59+
The method names are the operation name, suffixed by the data model's key in the object parameter passed to `MedusaService`.
6060

6161
For example, the following methods are generated for the service above:
6262

@@ -66,7 +66,7 @@ Find a complete reference of each of the methods in [this documentation](!resour
6666

6767
</Note>
6868

69-
<Tabs defaultValue="listMyCustoms" layoutType="vertical" className="mt-2">
69+
<Tabs defaultValue="listPosts" layoutType="vertical" className="mt-2">
7070
<TabsList>
7171
<TabsTriggerVertical value="listPosts">listPosts</TabsTriggerVertical>
7272
<TabsTriggerVertical value="listAndCountPosts">listAndCountPosts</TabsTriggerVertical>
@@ -78,7 +78,7 @@ Find a complete reference of each of the methods in [this documentation](!resour
7878
<TabsTriggerVertical value="restorePosts">restorePosts</TabsTriggerVertical>
7979
</TabsList>
8080
<TabsContentWrapper className="[&_h3]:!mt-0">
81-
<TabsContent value="listMyCustoms">
81+
<TabsContent value="listPosts">
8282

8383
### listPosts
8484

@@ -279,7 +279,7 @@ Find a complete reference of each of the methods in [this documentation](!resour
279279

280280
### Using a Constructor
281281

282-
If you implement the `constructor` of your service, make sure to call `super` passing it `...arguments`.
282+
If you implement a `constructor` in your service, make sure to call `super` and pass it `...arguments`.
283283

284284
For example:
285285

@@ -297,3 +297,45 @@ class BlogModuleService extends MedusaService({
297297

298298
export default BlogModuleService
299299
```
300+
301+
---
302+
303+
## Generated Internal Services
304+
305+
The service factory also generates internal services for each data model passed to the `MedusaService` function. These services are registered in the module's container and can be resolved using their camel-cased names.
306+
307+
For example, if the `BlogModuleService` is defined as follows:
308+
309+
```ts
310+
import { MedusaService } from "@medusajs/framework/utils"
311+
import Post from "./models/post"
312+
313+
class BlogModuleService extends MedusaService({
314+
Post,
315+
}){
316+
}
317+
318+
export default BlogModuleService
319+
```
320+
321+
Then, you'll have a `postService` registered in the module's container that allows you to manage posts.
322+
323+
Generated internal services have the same methods as the `BlogModuleService`, such as `create`, `retrieve`, `update`, and `delete`, but without the data model name suffix.
324+
325+
These services are useful when you need to perform database operations in loaders, as they are executed before the module's services are registered. Learn more in the [Module Container](../container/page.mdx) documentation.
326+
327+
For example, you can create a loader that logs the number of posts in the database:
328+
329+
```ts
330+
import { LoaderOptions } from "@medusajs/framework/types"
331+
332+
export default async function helloWorldLoader({
333+
container,
334+
}: LoaderOptions) {
335+
const postService = container.resolve("postService")
336+
337+
const [_, count] = await postService.listAndCount()
338+
339+
console.log(`[helloWorldLoader]: There are ${count} posts in the database.`)
340+
}
341+
```

www/apps/book/generated/edit-dates.mjs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const generatedEditDates = {
1616
"app/learn/fundamentals/api-routes/page.mdx": "2025-07-25T15:19:33.365Z",
1717
"app/learn/fundamentals/modules/modules-directory-structure/page.mdx": "2025-07-25T15:40:20.362Z",
1818
"app/learn/fundamentals/events-and-subscribers/page.mdx": "2025-05-16T13:40:16.111Z",
19-
"app/learn/fundamentals/modules/container/page.mdx": "2025-05-21T15:07:12.059Z",
19+
"app/learn/fundamentals/modules/container/page.mdx": "2025-07-31T14:24:04.087Z",
2020
"app/learn/fundamentals/workflows/execute-another-workflow/page.mdx": "2024-12-09T15:56:22.895Z",
2121
"app/learn/fundamentals/modules/loaders/page.mdx": "2025-06-16T13:34:16.462Z",
2222
"app/learn/fundamentals/admin/widgets/page.mdx": "2025-07-25T15:08:07.035Z",
@@ -38,7 +38,7 @@ export const generatedEditDates = {
3838
"app/learn/fundamentals/modules/options/page.mdx": "2025-03-18T15:12:34.510Z",
3939
"app/learn/fundamentals/data-models/relationships/page.mdx": "2025-07-16T09:51:22.141Z",
4040
"app/learn/fundamentals/workflows/compensation-function/page.mdx": "2025-04-24T13:16:00.941Z",
41-
"app/learn/fundamentals/modules/service-factory/page.mdx": "2025-03-18T15:14:13.486Z",
41+
"app/learn/fundamentals/modules/service-factory/page.mdx": "2025-07-31T13:27:53.791Z",
4242
"app/learn/fundamentals/modules/module-links/page.mdx": "2024-09-30T08:43:53.126Z",
4343
"app/learn/fundamentals/scheduled-jobs/execution-number/page.mdx": "2025-07-25T15:54:56.135Z",
4444
"app/learn/fundamentals/api-routes/parameters/page.mdx": "2025-02-14T08:34:03.184Z",
@@ -127,5 +127,5 @@ export const generatedEditDates = {
127127
"app/learn/fundamentals/generated-types/page.mdx": "2025-07-25T13:17:35.319Z",
128128
"app/learn/introduction/from-v1-to-v2/page.mdx": "2025-07-30T08:13:48.592Z",
129129
"app/learn/debugging-and-testing/debug-workflows/page.mdx": "2025-07-30T13:45:14.117Z",
130-
"app/learn/fundamentals/data-models/json-properties/page.mdx": "2025-07-31T10:47:27.882Z"
130+
"app/learn/fundamentals/data-models/json-properties/page.mdx": "2025-07-31T14:25:01.268Z"
131131
}

0 commit comments

Comments
 (0)