docs: added file module docs (#7278)

This commit is contained in:
Shahed Nasser authored and GitHub committed 2024-05-13 18:54:59 +03:00
1 parent 8b2429d24f
commit 803e4aad02
32 files changed
+745 -3448

No files matched your search

@@ -12,8 +12,6 @@ An architectural module implements features and mechanisms related to the Medusa
Since modules are interchangeable, you have more control over Medusa’s architecture. For example, you can choose to use Memcached for event handling instead of Redis.
Medusa currently supports two types of architectural modules: Cache and event modules.
<Note>
Refer to the [Architectural Modules reference](!resources!/architectural-modules) for a list of Medusa’s architectural modules.
@@ -26,4 +24,4 @@ Refer to the [Architectural Modules reference](!resources!/architectural-modules
You create an architectural module like you’ve been creating custom modules: create a module with a service and export that service in the module’s definition file. The module's service extends an abstract class or interface provided by Medusa with predefined method signatures.
The next chapters explain the different architectural module types and how to create an architectural module for each.
The next chapters explain the different architectural module types and how to create an architectural module for each.
@@ -1,165 +0,0 @@
export const metadata = {
title: `${pageNumber} How to Create a Cache Module`,
}
# {metadata.title}
In this chapter, you’ll learn how to create a Cache Module.
## 1. Create Module Directory
Start by creating a new directory for your module. For example, `src/modules/my-cache`.
---
## 2. Create the Cache Service
Create the file `src/modules/my-cache/service.ts` that holds the implementation of the cache service.
The Cache Module's main service must implement the `ICacheService` interface imported from `@medusajs/types`:
```ts title="src/modules/my-cache/service.ts"
import { ICacheService } from "@medusajs/types"
class MyCacheService implements ICacheService {
get<T>(key: string): Promise<T> {
throw new Error("Method not implemented.")
}
set(key: string, data: unknown, ttl?: number): Promise<void> {
throw new Error("Method not implemented.")
}
invalidate(key: string): Promise<void> {
throw new Error("Method not implemented.")
}
}
export default MyCacheService
```
The service implements the required methods based on the desired caching mechanism.
### Implement get Method
The `get` method retrieves the value of a cached item based on its key.
The method accepts a string as a first parameter, which is the key in the cache. It either returns the cached item or `null` if it doesn’t exist.
For example, to implement this method using Memcached:
```ts title="src/modules/my-cache/service.ts"
class MyCacheService implements ICacheService {
// ...
async get<T>(cacheKey: string): Promise<T | null> {
return new Promise((res, rej) => {
this.memcached.get(cacheKey, (err, data) => {
if (err) {
res(null)
} else {
if (data) {
res(JSON.parse(data))
} else {
res(null)
}
}
})
})
}
}
```
### Implement set Method
The `set` method is used to set an item in the cache. It accepts three parameters:
1. The first parameter is a string indicating the key of the data being added to the cache. This key can be used later to get or invalidate the cached item.
2. The second parameter is the data to be added to the cache. The data can be of any type.
3. The third parameter is optional. It’s a number indicating how long (in seconds) the data should be kept in the cache.
For example, to implement this method using Memcached:
```ts title="src/modules/my-cache/service.ts"
class MyCacheService implements ICacheService {
protected TTL = 60
// ...
async set(
key: string,
data: Record<string, unknown>,
ttl: number = this.TTL // or any value
): Promise<void> {
return new Promise((res, rej) =>
this.memcached.set(
key, JSON.stringify(data), ttl, (err) => {
if (err) {
rej(err)
} else {
res()
}
})
)
}
}
```
### Implement invalidate Method
The `invalidate` method removes an item from the cache using its key.
By default, items are removed from the cache when their time-to-live (ttl) expires. The `invalidate` method can be used to remove the item beforehand.
The method accepts a string as a first parameter, which is the key of the item to invalidate and remove from the cache.
For example, to implement this method using Memcached:
```ts title="src/modules/my-cache/service.ts"
class MyCacheService implements ICacheService {
// ...
async invalidate(key: string): Promise<void> {
return new Promise((res, rej) => {
this.memcached.del(key, (err) => {
if (err) {
rej(err)
} else {
res()
}
})
})
}
}
```
---
## 3. Create Module Definition File
Create the file `src/modules/my-cache/index.ts` with the following content:
```ts title="src/modules/my-cache/index.ts"
import MyCacheService from "./service"
export default {
service: MyCacheService,
}
```
This exports the module's definition, indicating that the `MyCacheService` is the main service of the module.
---
## 4. Use Module
To use your Cache Module, add it to the `modules` object exported as part of the configurations in `medusa-config.js`. A Cache Module is added under the `cacheService` key.
For example:
```js title="medusa-config.js"
const modules = {
// other modules...
cacheService: {
resolve: "./dist/modules/my-cache/index.ts",
options: {
// any necessary options
ttl: 30,
},
},
}
```
@@ -18,4 +18,16 @@ The underlying database, third-party service, or caching logic is flexible since
By default, Medusa uses the In-Memory Cache Module. This module uses a plain JavaScript Map object to store the cache data.
This is useful for development. However, for production, it's highly recommended to use other Cache Modules, such as the [Redis Cache Module](!resources!/architectural-modules/cache/redis).
This is useful for development. However, for production, it's highly recommended to use other Cache Modules, such as the [Redis Cache Module](!resources!/architectural-modules/cache/redis).
---
## List of Cache Modules
Refer to the Medusa Learning Resources for a [list of available cache modules](!resources!/architectural-modules/cache).
---
## Create a Cache Module
To create a cache module, refer to [this guide in the Medusa Learning Resources](!resources!/architectural-modules/cache/create).
@@ -1,119 +0,0 @@
export const metadata = {
title: `${pageNumber} How to Create an Event Module`,
}
# {metadata.title}
In this chapter, you’ll learn how to create an Event Module.
## 1. Create Module Directory
Start by creating a new directory for your module. For example, `src/modules/my-event`.
---
## 2. Create the Event Service
Create the file `src/modules/my-event/service.ts` that holds the implementation of the event service.
The Event Module's main service must extend the `AbstractEventBusModuleService` class imported from `@medusajs/utils`:
```ts title="src/modules/my-event/service.ts"
import { EmitData, Message } from "@medusajs/types"
import { AbstractEventBusModuleService } from "@medusajs/utils"
class MyEventService extends AbstractEventBusModuleService {
emit<T>(eventName: string, data: T, options: Record<string, unknown>): Promise<void>;
emit<T>(data: EmitData<T>[]): Promise<void>;
emit<T>(data: Message<T>[]): Promise<void>;
emit(eventName: unknown, data?: unknown, options?: unknown): Promise<void> {
throw new Error("Method not implemented.")
}
}
export default MyEventService
```
The service implements the required methods based on the desired publish/subscribe logic.
### Note About the eventToSubscribersMap Property
The `AbstractEventBusModuleService` has a field `eventToSubscribersMap`, which is a JavaScript Map. The map's keys are the event names, whereas the value of each key is an array of subscribed handler functions.
In your custom implementation, you can use this property to manage the subscribed handler functions:
```ts
const eventSubscribers =
this.eventToSubscribersMap.get(eventName) || []
```
### Implement emit Method
The `emit` method is used to push an event from the Medusa application into your messaging system. The subscribers to that event would then pick up the message and execute their asynchronous tasks.
The `emit` method has three different signatures:
1. The first signature accepts three parameters:
- The first parameter is a string indicating the name of the event to trigger.
- The second parameter is data to send to subscribers of that event.
- The third optional parameter can be used to pass options specific to the event service.
2. The second signature accepts one parameter, which is an array of objects having the following properties:
- `eventName`: A string indicating the name of the event to trigger.
- `data`: The data to send to subsribers of that event.
- `options`: (optional) options specific to the event service.
3. The third signature accepts one parameter, which is an array of objects having the following properties:
- `eventName`: A string indicating the name of the event to trigger.
- `body`: An object of event-related data. It has two properties: `data` holding the data of the event, and `metadata` which is an object with more details on how the event was emitted, such as the action that occurred or the service that emitted it.
- `options`: (optional) options specific to the event service.
You can implement your method in a way that supports both signatures by checking the type of the first input. For example:
```ts title="src/modules/my-event/service.ts"
class MyEventService extends AbstractEventBusModuleService {
// ...
emit<T>(eventName: string, data: T, options: Record<string, unknown>): Promise<void>;
emit<T>(data: EmitData<T>[]): Promise<void>;
emit<T>(data: Message<T>[]): Promise<void>;
emit(eventOrData: unknown, data?: unknown, options?: unknown): Promise<void> {
const isBulkEmit = Array.isArray(eventOrData)
// ...
}
}
```
---
## 3. Create Module Definition File
Create the file `src/modules/my-event/index.ts` with the following content:
```ts
import MyEventService from "./service"
export default {
service: MyEventService,
}
```
This exports the module's definition, indicating that the `MyEventService` is the main service of the module.
---
## 4. Use Module
To use your Event Module, add it to the `modules` object exported as part of the configurations in `medusa-config.js`. An Event Module is added under the `eventBus` key.
For example:
```js title="medusa-config.js"
const modules = {
// other modules...
eventBus: {
resolve: "./dist/modules/my-event/index.ts",
options: {
// any necessary options
},
},
}
```
@@ -12,7 +12,7 @@ In previous chapters, you learned that the Medusa application emits events, and
The Event Module implements the underlying publish/subscribe system that handles queueing events, emitting them, and executing their subscribers.
This makes the event architecture customizable, as you can either choose one of Medusa’s Event Modules or create your own.
This makes the event architecture customizable, as you can either choose one of Medusa’s event modules or create your own.
---
@@ -21,3 +21,15 @@ This makes the event architecture customizable, as you can either choose one of
By default, Medusa uses the Local Event Module. This module uses Node’s EventEmitter to implement the publish/subscribe system.
This is useful for development. However, for production, it’s highly recommended to use other Event Modules, such as the [Redis Event Module](!resources!/architectural-modules/event/redis).
---
## List of Event Modules
Refer to the Medusa Learning Resources for a [list of available event modules](!resources!/architectural-modules/event).
---
## Create a Event Module
To create an event module, refer to [this guide in the Medusa Learning Resources](!resources!/architectural-modules/event/create).
@@ -0,0 +1,35 @@
export const metadata = {
title: `${pageNumber} File Module`,
}
# {metadata.title}
In this chapter, you’ll learn about what the File Module is.
## What is the File Module?
The File Module exposes the functionalities to upload assets, such as product images, to the Medusa application.
---
## What is a File Provider Module?
A file provider module implements the logic of handling uploads and downloads. The File Module must have one file provider module configured.
By default, Medusa uses the Local File Module. This module uploads files to the `uploads` directory of your Medusa application.
{/* TODO add once s3 module is working/published? */}
{/* This is useful for development. However, for production, it’s highly recommended to use other File Modules, such as the [S3 Module](!resources!/architectural-modules/event/redis). */}
---
## List of File Provider Modules
Refer to the Medusa Learning Resources for a [list of available file provider modules](!resources!/architectural-modules/file).
---
## Create a File Provider Module
To create a file provider module, refer to [this guide in the Medusa Learning Resources](!resources!/architectural-modules/references/file-provider-module).
@@ -9,5 +9,4 @@ In the next chapters, you’ll learn more about customizable aspects of Medusa
By the end of these chapters, you’ll learn about:
- What an architectural module is.
- The cache architectural module and how to create one.
- The events architectural module and how to create one.
- The different types of architectural modules, including cache and event modules.
+4 -12
View File
@@ -253,22 +253,14 @@ export const sidebar = sidebarAttachHrefCommonOptions(
{
path: "/architectural-concepts/cache-module",
title: "Cache Module",
children: [
{
path: "/architectural-concepts/cache-module/create",
title: "Create Cache Module",
},
],
},
{
path: "/architectural-concepts/event-module",
title: "Event Module",
children: [
{
path: "/architectural-concepts/event-module/create",
title: "Create Event Module",
},
],
},
{
path: "/architectural-concepts/file-module",
title: "File Module",
},
],
},