0
# File Service
1
2
Interface for file storage service implementations providing upload and delete operations for handling file assets across different storage providers.
3
4
**Deprecation Notice**: Use `AbstractFileService` from @medusajs/medusa instead.
5
6
## Capabilities
7
8
### Static Methods
9
10
Type checking and identification methods for file services.
11
12
```javascript { .api }
13
/**
14
* Static property identifying this as a file service
15
*/
16
static _isFileService: boolean;
17
18
/**
19
* Checks if an object is a file service
20
* @param {object} obj - Object to check
21
* @returns {boolean} True if obj is a file service
22
*/
23
static isFileService(obj: object): boolean;
24
```
25
26
### Core File Operations
27
28
Abstract methods that must be implemented by child classes for file storage operations.
29
30
```javascript { .api }
31
/**
32
* Uploads files to the storage provider
33
* @returns {any} Upload result
34
* @throws {Error} If not overridden by child class
35
*/
36
upload(): any;
37
38
/**
39
* Deletes files from the storage provider
40
* @returns {any} Deletion result
41
* @throws {Error} If not overridden by child class
42
*/
43
delete(): any;
44
```
45
46
## Implementation Example
47
48
```javascript
49
import { FileService } from "medusa-interfaces";
50
import fs from "fs";
51
import path from "path";
52
53
class LocalFileService extends FileService {
54
constructor(options) {
55
super();
56
this.uploadDir = options.upload_dir || "./uploads";
57
this.baseUrl = options.base_url || "http://localhost:9000";
58
}
59
60
async upload(files) {
61
const uploadedFiles = [];
62
63
// Handle single file or array of files
64
const fileArray = Array.isArray(files) ? files : [files];
65
66
for (const file of fileArray) {
67
// Generate unique filename
68
const filename = `${Date.now()}-${file.originalname}`;
69
const filepath = path.join(this.uploadDir, filename);
70
71
// Ensure upload directory exists
72
if (!fs.existsSync(this.uploadDir)) {
73
fs.mkdirSync(this.uploadDir, { recursive: true });
74
}
75
76
// Write file to disk
77
fs.writeFileSync(filepath, file.buffer);
78
79
uploadedFiles.push({
80
url: `${this.baseUrl}/uploads/${filename}`,
81
key: filename,
82
originalname: file.originalname,
83
size: file.size,
84
mimetype: file.mimetype
85
});
86
}
87
88
return uploadedFiles.length === 1 ? uploadedFiles[0] : uploadedFiles;
89
}
90
91
async delete(fileKey) {
92
try {
93
const filepath = path.join(this.uploadDir, fileKey);
94
95
if (fs.existsSync(filepath)) {
96
fs.unlinkSync(filepath);
97
return { success: true, key: fileKey };
98
} else {
99
throw new Error(`File not found: ${fileKey}`);
100
}
101
} catch (error) {
102
throw new Error(`Failed to delete file: ${error.message}`);
103
}
104
}
105
}
106
107
// AWS S3 implementation example
108
class S3FileService extends FileService {
109
constructor(options) {
110
super();
111
this.s3Client = new AWS.S3({
112
accessKeyId: options.access_key_id,
113
secretAccessKey: options.secret_access_key,
114
region: options.region
115
});
116
this.bucket = options.bucket;
117
}
118
119
async upload(files) {
120
const uploadedFiles = [];
121
const fileArray = Array.isArray(files) ? files : [files];
122
123
for (const file of fileArray) {
124
const key = `${Date.now()}-${file.originalname}`;
125
126
const uploadParams = {
127
Bucket: this.bucket,
128
Key: key,
129
Body: file.buffer,
130
ContentType: file.mimetype,
131
ACL: 'public-read'
132
};
133
134
const result = await this.s3Client.upload(uploadParams).promise();
135
136
uploadedFiles.push({
137
url: result.Location,
138
key: result.Key,
139
originalname: file.originalname,
140
size: file.size,
141
mimetype: file.mimetype
142
});
143
}
144
145
return uploadedFiles.length === 1 ? uploadedFiles[0] : uploadedFiles;
146
}
147
148
async delete(fileKey) {
149
try {
150
const deleteParams = {
151
Bucket: this.bucket,
152
Key: fileKey
153
};
154
155
await this.s3Client.deleteObject(deleteParams).promise();
156
return { success: true, key: fileKey };
157
} catch (error) {
158
throw new Error(`Failed to delete file from S3: ${error.message}`);
159
}
160
}
161
}
162
```
163
164
## Usage in Medusa
165
166
File services are typically used in Medusa for:
167
168
- **Product Images**: Uploading and managing product photos
169
- **User Avatars**: Profile picture management
170
- **Document Storage**: Invoices, receipts, and other documents
171
- **Media Assets**: General file asset management
172
173
**Basic Usage Pattern:**
174
175
```javascript
176
// In a Medusa service or API route
177
class ProductService {
178
constructor({ fileService }) {
179
this.fileService_ = fileService;
180
}
181
182
async uploadProductImages(productId, imageFiles) {
183
// Upload images using the file service
184
const uploadedImages = await this.fileService_.upload(imageFiles);
185
186
// Store image URLs in product record
187
await this.updateProduct(productId, {
188
images: uploadedImages.map(img => img.url)
189
});
190
191
return uploadedImages;
192
}
193
194
async deleteProductImage(imageKey) {
195
// Delete image file
196
await this.fileService_.delete(imageKey);
197
198
// Remove from product record
199
// ... update logic
200
}
201
}
202
```
203
204
## Error Handling
205
206
Both abstract methods throw descriptive errors when not implemented:
207
208
- `"upload must be overridden by the child class"`
209
- `"delete must be overridden by the child class"`
210
211
## Common Implementation Patterns
212
213
### File Upload Parameters
214
215
Most implementations expect file objects with these properties:
216
217
```javascript
218
{
219
originalname: string, // Original filename
220
buffer: Buffer, // File data
221
mimetype: string, // MIME type
222
size: number // File size in bytes
223
}
224
```
225
226
### Return Value Patterns
227
228
Upload operations typically return:
229
230
```javascript
231
{
232
url: string, // Public URL to access the file
233
key: string, // Storage identifier/key
234
originalname: string, // Original filename
235
size: number, // File size
236
mimetype: string // MIME type
237
}
238
```
239
240
Delete operations typically return:
241
242
```javascript
243
{
244
success: boolean, // Operation success status
245
key: string // Key of deleted file
246
}
247
```