Medusa Starter Default

repository·master·Indexed 41 days ago

https://github.com/medusajs/medusa-starter-default

A starter template for Medusa projects compatible with @medusajs/medusa version 2 and above. This repository provides guidance on creating custom API routes, extending the Medusa Admin with React-based widgets and pages, developing custom modules and services, and implementing module links. It also includes instructions for writing integration tests using medusa-test-utils and creating custom CLI scripts. Note: This starter is deprecated in favor of dtc-starter.

Tokens
5K
Snippets
20
Records
26
Agent score
52%

What's inside Medusa

  1. Create associations between modules using Module Links

    master

    Module Links allow you to form associations between data models belonging to different modules while preserving module isolation. Instead of direct foreign key dependencies between modules, you define a link using the defineLink utility.

    To create a link, you must reference the .linkable property of the respective modules. For example, to associate a product from the ProductModule with a post from a custom BlogModule, you pass their linkable entities to defineLink.

    After defining your links in code, you must synchronize them with your database by running the migration command.

    import BlogModule from "../modules/blog"
    import ProductModule from "@medusajs/medusa/product"
    import { defineLink } from "@medusajs/framework/utils"
    
    export default defineLink(
      ProductModule.linkable.product,
      BlogModule.linkable.post
    )
  2. How Medusa modules work

    master
    A module is a package of reusable functionalities that can be integrated into a Medusa application without affecting the overall system. Modules can be created as part of a plugin. A complete module typically consists of a data model (representing database tables), a service (containing business logic), and a module definition that exports the service to the Medusa container.
  3. Create a custom Medusa module

    master

    To create a new module, follow these five steps:

    1. Create a Data Model: Define your database schema in a file under the models directory using model.define from @medusajs/framework/utils.
    2. Create a Service: Define a class that extends MedusaService and includes your models. This service holds your business logic.
    3. Export Module Definition: Create an index.ts file in the module's root directory. Use the Module utility to export the module name and its service.
    4. Register the Module: Add the module to the modules array in your medusa-config.ts using the resolve key pointing to the module path.
    5. Run Migrations: Generate and apply database changes using the Medusa CLI.
  4. Use path parameters in API Routes

    master

    To define dynamic path parameters, use directory names in the format [param]. These parameters are then accessible via req.params.

    • Single parameter: Create a directory like [productId] (e.g., /api/products/[productId]/route.ts).
    • Multiple parameters: Nest multiple bracketed directories (e.g., /api/products/[productId]/variants/[variantId]/route.ts).
    import type {
      MedusaRequest,
      MedusaResponse,
    } from "@medusajs/framework/http"
    
    export async function GET(req: MedusaRequest, res: MedusaResponse) {
      const { productId } = req.params;
    
      res.json({
        message: `You're looking for product ${productId}`
      })
    }
  5. How to create a custom CLI script

    master

    Custom CLI scripts allow you to execute custom logic through the Medusa CLI. To create one, create a TypeScript (.ts) or JavaScript (.js) file inside the src/scripts directory. The file must contain a default export of an async function.

    The function receives an ExecArgs object as its parameter, which includes a container property. The container is an instance of the Medusa Container, allowing you to resolve services and resources (e.g., product module service) within your script.

    import { 
      ExecArgs,
    } from "@medusajs/framework/types"
    
    export default async function myScript ({ 
      container 
    }: ExecArgs) {
      const productModuleService = container.resolve("product")
      const [, count] = await productModuleService.listAndCountProducts()
    
      console.log(`You have ${count} product(s)`)
    }
  6. Create a custom Admin Widget

    master

    A widget is a React component that can be injected into specific locations (zones) within existing Medusa Admin pages. To create a widget, you must export a default React component and a config object created via defineWidgetConfig. The zone property in the configuration determines where the widget appears (e.g., product.details.after places it at the end of the product details page).

    import { defineWidgetConfig } from "@medusajs/admin-sdk"
    
    // The widget component
    const ProductWidget = () => {
      return (
        <div>
          <h2>Product Widget</h2>
        </div>
      )
    }
    
    // The widget's configuration
    export const config = defineWidgetConfig({
      zone: "product.details.after",
    })
    
    export default ProductWidget
  7. Configure Middleware for API Routes

    master

    To apply middleware to specific routes, create an /api/middlewares.ts file. This file must export a configuration object using the defineMiddlewares function.

    • matcher: A string or regular expression that defines which routes the middleware applies to.
    • middlewares: An array of middleware functions. A middleware function typically receives (req, res, next) and must call next() to proceed.
    import { defineMiddlewares } from "@medusajs/framework/http"
    import type {
      MedusaRequest,
      MedusaResponse,
      MedusaNextFunction,
    } from "@medusajs/framework/http";
    
    async function logger(
      req: MedusaRequest,
      res: MedusaResponse,
      next: MedusaNextFunction,
    ) {
      console.log("Request received");
      next();
    }
    
    export default defineMiddlewares({
      routes: [
        {
          matcher: "/store/custom",
          middlewares: [logger],
        },
      ],
    })
  8. Create integration tests for API routes with medusa-test-utils

    master

    Use the medusaIntegrationTestRunner from the medusa-test-utils package to write integration tests for your Medusa API routes and workflows. The runner provides a testSuite function that gives you access to an api object for making HTTP requests and a getContainer function to access the Medusa dependency injection container. This allows you to test endpoints and verify their responses, status codes, and data structures.

    import { medusaIntegrationTestRunner } from "medusa-test-utils"
    
    medusaIntegrationTestRunner({
      testSuite: ({ api, getContainer }) => {
        describe("Custom endpoints", () => {
          describe("GET /store/custom", () => {
            it("returns correct message", async () => {
              const response = await api.get(
                `/store/custom`
              )
      
              expect(response.status).toEqual(200)
              expect(response.data).toHaveProperty("message")
              expect(response.data.message).toEqual("Hello, World!")
            })
          })
        })
      }
    })
  9. Create a custom subscriber

    master

    Subscribers are asynchronous functions that handle events emitted within the Medusa application. To create one, place a TypeScript or JavaScript file in the src/subscribers directory.

    Each subscriber file must export two specific members:

    1. An asynchronous default export function: This is the handler that executes when the event is triggered.
    2. A config constant: An object of type SubscriberConfig that defines which event the subscriber is listening to.
    import {
      type SubscriberConfig,
    } from "@medusajs/framework"
    
    // subscriber function
    export default async function productCreateHandler() {
      console.log("A product was created")
    }
    
    // subscriber config
    export const config: SubscriberConfig = {
      event: "product.created",
    }
  10. Create Custom API Routes

    master

    An API Route is a REST API endpoint defined using file-based routing. To create a route, place a route.ts or route.js file within the /src/api directory. The directory structure determines the URL path.

    For example, to create a GET endpoint at /store/hello-world, create the file at src/api/store/hello-world/route.ts.

    import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
    
    export async function GET(req: MedusaRequest, res: MedusaResponse) {
      res.json({
        message: "Hello world!",
      });
    }