290 lines
11 KiB
Plaintext
290 lines
11 KiB
Plaintext
---
|
||
slug: /references/file-provider-module
|
||
---
|
||
|
||
import { TypeList } from "docs-ui"
|
||
|
||
# How to Create a File Provider Module
|
||
|
||
In this document, you’ll learn how to create a file provider module and the methods you must implement in its main service.
|
||
|
||
---
|
||
|
||
## Create Module Provider Directory
|
||
|
||
Start by creating a new directory for your module provider.
|
||
|
||
If you're creating the module provider in a Medusa application, create it under the `src/modules` directory. For example, `src/modules/my-file`.
|
||
|
||
If you're creating the module provider in a plugin, create it under the `src/providers` directory. For example, `src/providers/my-file`.
|
||
|
||
<Note>
|
||
|
||
The rest of this guide always uses the `src/modules/my-file` directory as an example.
|
||
|
||
</Note>
|
||
|
||
---
|
||
|
||
## 2. Create the File Provider Service
|
||
|
||
Create the file `src/modules/my-file/service.ts` that holds the implementation of the module's main service. It must extend the `AbstractFileProviderService` class imported from `@medusajs/framework/utils`:
|
||
|
||
```ts title="src/modules/my-file/service.ts"
|
||
import { AbstractFileProviderService } from "@medusajs/framework/utils"
|
||
|
||
class MyFileProviderService extends AbstractFileProviderService {
|
||
// TODO implement methods
|
||
}
|
||
|
||
export default MyFileProviderService
|
||
```
|
||
|
||
### constructor
|
||
|
||
The constructor allows you to access resources from the module's container using the first parameter,
|
||
and the module's options using the second parameter.
|
||
|
||
If you're creating a client or establishing a connection with a third-party service, do it in the constructor.
|
||
|
||
#### Example
|
||
|
||
```ts
|
||
import { Logger } from "@medusajs/framework/types"
|
||
import { AbstractFileProviderService } from "@medusajs/framework/utils"
|
||
|
||
type InjectedDependencies = {
|
||
logger: Logger
|
||
}
|
||
|
||
type Options = {
|
||
apiKey: string
|
||
}
|
||
|
||
class MyFileProviderService extends AbstractFileProviderService {
|
||
protected logger_: Logger
|
||
protected options_: Options
|
||
static identifier = "my-file"
|
||
// assuming you're initializing a client
|
||
protected client
|
||
|
||
constructor (
|
||
{ logger }: InjectedDependencies,
|
||
options: Options
|
||
) {
|
||
super()
|
||
|
||
this.logger_ = logger
|
||
this.options_ = options
|
||
|
||
// assuming you're initializing a client
|
||
this.client = new Client(options)
|
||
}
|
||
}
|
||
|
||
export default MyFileProviderService
|
||
```
|
||
|
||
### identifier
|
||
|
||
Each file provider has a unique ID used to identify it. The provider's ID
|
||
will be stored as `fs_{identifier}_{id}`, where `{id}` is the provider's `id`
|
||
property in the `medusa-config.ts`.
|
||
|
||
#### Example
|
||
|
||
```ts
|
||
class MyFileProviderService extends AbstractFileProviderService {
|
||
static identifier = "my-file"
|
||
// ...
|
||
}
|
||
```
|
||
|
||
### validateOptions
|
||
|
||
This method validates the options of the provider set in `medusa-config.ts`.
|
||
Implementing this method is optional. It's useful if your provider requires custom validation.
|
||
|
||
If the options aren't valid, throw an error.
|
||
|
||
#### Example
|
||
|
||
```ts
|
||
class MyFileProviderService extends AbstractFileProviderService {
|
||
static validateOptions(options: Record<any, any>) {
|
||
if (!options.apiKey) {
|
||
throw new MedusaError(
|
||
MedusaError.Types.INVALID_DATA,
|
||
"API key is required in the provider's options."
|
||
)
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Parameters
|
||
|
||
<TypeList types={[{"name":"options","type":"`Record<any, any>`","description":"The provider's options.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="validateOptions"/>
|
||
|
||
### upload
|
||
|
||
This method uploads a file using your provider's custom logic. In this method, you can upload the file
|
||
into your provider's storage, and return the uploaded file's details.
|
||
|
||
This method will be used when uploading product images, CSV files for imports, or other
|
||
custom file uploads.
|
||
|
||
#### Example
|
||
|
||
```ts
|
||
class MyFileProviderService extends AbstractFileProviderService {
|
||
// ...
|
||
async upload(
|
||
file: ProviderUploadFileDTO
|
||
): Promise<ProviderFileResultDTO> {
|
||
// TODO upload file to third-party provider
|
||
// or using custom logic
|
||
// for example:
|
||
this.client.upload(file)
|
||
|
||
return {
|
||
url: "some-url.com",
|
||
key: "file-name-or-id"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Parameters
|
||
|
||
<TypeList types={[{"name":"file","type":"[ProviderUploadFileDTO](../../../types/FileTypes/interfaces/types.FileTypes.ProviderUploadFileDTO/page.mdx)","description":"The file to upload.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"filename","type":"`string`","description":"The filename of the uploaded file","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"mimeType","type":"`string`","description":"The mimetype of the uploaded file","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"content","type":"`string`","description":"The file content as a binary-encoded string","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"access","type":"`\"public\"` \\| `\"private\"`","description":"The access level of the file. Defaults to private if not passed","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="upload"/>
|
||
|
||
#### Returns
|
||
|
||
<TypeList types={[{"name":"Promise","type":"Promise<[ProviderFileResultDTO](../../../types/FileTypes/interfaces/types.FileTypes.ProviderFileResultDTO/page.mdx)>","optional":false,"defaultValue":"","description":"The uploaded file's details.","expandable":false,"children":[{"name":"ProviderFileResultDTO","type":"[ProviderFileResultDTO](../../../types/FileTypes/interfaces/types.FileTypes.ProviderFileResultDTO/page.mdx)","optional":false,"defaultValue":"","description":"","expandable":false,"children":[{"name":"url","type":"`string`","description":"The file's URL that users or systems\ncan use to access the file.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"key","type":"`string`","description":"The file's key allowing you to later\nidentify the file in the third-party\nsystem. For example, the S3 Module Provider\nreturns the file's key in S3, whereas the\nLocal File Module Provider returns the file's\npath.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="upload"/>
|
||
|
||
### delete
|
||
|
||
This method deletes the file from storage. It's used when an admin user deletes a product image,
|
||
or other custom file deletions.
|
||
|
||
#### Example
|
||
|
||
```ts
|
||
class MyFileProviderService extends AbstractFileProviderService {
|
||
// ...
|
||
async delete(file: ProviderDeleteFileDTO): Promise<void> {
|
||
// TODO logic to remove the file from storage
|
||
// Use the `file.fileKey` to delete the file
|
||
// for example:
|
||
this.client.delete(file.fileKey)
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Parameters
|
||
|
||
<TypeList types={[{"name":"file","type":"[ProviderDeleteFileDTO](../../../types/FileTypes/interfaces/types.FileTypes.ProviderDeleteFileDTO/page.mdx)","description":"The details of the file to delete.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"fileKey","type":"`string`","description":"The file's key. When uploading a file, the\nreturned key is used here.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="delete"/>
|
||
|
||
#### Returns
|
||
|
||
<TypeList types={[{"name":"Promise","type":"Promise<void>","optional":false,"defaultValue":"","description":"Resolves when the file is deleted.","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="delete"/>
|
||
|
||
### getPresignedDownloadUrl
|
||
|
||
This method is used to retrieve a download URL of the file. For some providers,
|
||
such as S3, a presigned URL indicates a temporary URL to get access to a file.
|
||
|
||
If your provider doesn’t perform or offer a similar functionality, you can
|
||
return the URL to download the file.
|
||
|
||
#### Example
|
||
|
||
```ts
|
||
class MyFileProviderService extends AbstractFileProviderService {
|
||
// ...
|
||
async getPresignedDownloadUrl(
|
||
fileData: ProviderGetFileDTO
|
||
): Promise<string> {
|
||
// TODO logic to get the presigned URL
|
||
// Use the `file.fileKey` to delete the file
|
||
// for example:
|
||
return this.client.getPresignedUrl(fileData.fileKey)
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Parameters
|
||
|
||
<TypeList types={[{"name":"fileData","type":"[ProviderGetFileDTO](../../../types/FileTypes/interfaces/types.FileTypes.ProviderGetFileDTO/page.mdx)","description":"The details of the file to get its\npresigned URL.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"fileKey","type":"`string`","description":"The file's key as returned during upload.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="getPresignedDownloadUrl"/>
|
||
|
||
#### Returns
|
||
|
||
<TypeList types={[{"name":"Promise","type":"Promise<string>","optional":false,"defaultValue":"","description":"The file's presigned URL.","expandable":false,"children":[{"name":"string","type":"`string`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="getPresignedDownloadUrl"/>
|
||
|
||
---
|
||
|
||
## 3. Create Module Definition File
|
||
|
||
Create the file `src/modules/my-file/index.ts` with the following content:
|
||
|
||
```ts title="src/modules/my-file/index.ts"
|
||
import MyFileProviderService from "./service"
|
||
import {
|
||
ModuleProvider,
|
||
Modules
|
||
} from "@medusajs/framework/utils"
|
||
|
||
export default ModuleProvider(Modules.FILE, {
|
||
services: [MyFileProviderService],
|
||
})
|
||
```
|
||
|
||
This exports the module's definition, indicating that the `MyFileProviderService` is the module's service.
|
||
|
||
---
|
||
|
||
## 4. Use Module
|
||
|
||
To use your File Module Provider, add it to the `providers` array of the File Module in `medusa-config.ts`:
|
||
|
||
<Note>
|
||
|
||
The File Module accepts one provider only.
|
||
|
||
</Note>
|
||
|
||
```ts title="medusa-config.ts"
|
||
module.exports = defineConfig({
|
||
// ...
|
||
modules: [
|
||
{
|
||
resolve: "@medusajs/medusa/file",
|
||
options: {
|
||
providers: [
|
||
// default provider
|
||
{
|
||
resolve: "@medusajs/medusa/file-local",
|
||
id: "local",
|
||
},
|
||
{
|
||
// if module provider is in a plugin, use `plugin-name/providers/my-file`
|
||
resolve: "./src/modules/my-file",
|
||
id: "my-file",
|
||
options: {
|
||
// provider options...
|
||
},
|
||
},
|
||
],
|
||
},
|
||
},
|
||
]
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Test it Out
|
||
|
||
To test out your file provider, use the Medusa Admin or the [Upload API route](https://docs.medusajs.com/v2/api/admin#uploads_postuploads) to upload a file.
|