Розробка кастомного сервісу Medusa.js
У Medusa 2.x сервіс — це TypeScript-клас, зареєстрований в IoC-контейнері та доступний через container.resolve(). Кастомні сервіси можуть інкапсулювати бізнес-логіку, інтегрувати зовнішні API, оркеструвати кілька вбудованих модулів та використовуватися в Workflows, Subscribers, API-роутах.
Типи сервісів
| Тип | Використання | Реєстрація |
|---|---|---|
| Module Service | CRUD для модульних сутностей | Module() декоратор |
| Custom Service | Бізнес-логіка, оркестрація | src/modules/*/service.ts |
| Workflow Step | Повторно-використовуюча step-логіка | createStep() |
| Provider Service | Платіж, доставка, файли | Extends Abstract клас |
Кастомний сервіс
type LoyaltyServiceDeps = {
logger: Logger;
};
export default class LoyaltyService {
protected logger: Logger;
constructor({ logger }: LoyaltyServiceDeps) {
this.logger = logger;
}
async getCustomerPoints(customerId: string): Promise<number> {
const db = // отримати connection через MikroORM
const result = await db.query<{ total: number }>(
`SELECT COALESCE(SUM(points), 0) as total
FROM loyalty_points
WHERE customer_id = $1 AND expires_at > NOW()`,
[customerId]
);
return result[0]?.total ?? 0;
}
async addPoints(data: LoyaltyPoint): Promise<void> {
this.logger.info(`Adding ${data.points} points to customer ${data.customerId}`);
await db.query(
`INSERT INTO loyalty_points (customer_id, points, reason, order_id, expires_at)
VALUES ($1, $2, $3, $4, NOW() + INTERVAL '1 year')`,
[data.customerId, data.points, data.reason, data.orderId ?? null]
);
}
}
Реєстрація
export const LOYALTY_MODULE = 'loyaltyModuleService';
export default Module(LOYALTY_MODULE, {
service: LoyaltyService,
});
Використання в Workflow
const addLoyaltyPointsStep = createStep(
'add-loyalty-points',
async (input, context) => {
const loyaltyService: LoyaltyService = context.container.resolve(LOYALTY_MODULE);
const pointsToAdd = Math.floor(input.orderTotal / 100);
await loyaltyService.addPoints({
customerId: input.customerId,
points: pointsToAdd,
reason: 'order_completed',
});
return new StepResponse({ pointsAdded: pointsToAdd });
}
);
Використання в API-роуті
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
const session = req.session as { customer_id?: string };
if (!session.customer_id) return res.status(401).json({ message: 'Не авторизовано' });
const loyaltyService: LoyaltyService = req.scope.resolve(LOYALTY_MODULE);
const points = await loyaltyService.getCustomerPoints(session.customer_id);
res.json({ points, customer_id: session.customer_id });
};
Терміни розробки
- Простий сервіс (отримання/запис даних, 1–2 операції): 1–2 дні
- Сервіс з інтеграцією зовнішнього API, retry логікою, тестами: 3–5 днів
- Складний сервіс (loyalty-програма, B2B pricing, кастомний інвентар): 1–3 тижні







