Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 24

Defining Reusable Schemas

Recommended resources

Introduction

In the previous lesson, you successfully configured your application to serve an interactive documentation page at the /api-docs endpoint. While the page is live, it currently shows "No operations defined," because we haven't described our API's data structures or endpoints yet.

This lesson addresses the first part of that: defining our data. We will create a reusable schema component for the primary resource your API will manage. Think of this as creating a template for your data model (e.g., a "Product," "User," or "Task") that Swagger can use to understand the shape of your API's inputs and outputs. This is a crucial step for maintaining clean, consistent, and easy-to-manage documentation—a core practice known as "Don't Repeat Yourself" (DRY).

By the end of this lesson, you will have defined a complete schema for your resource, including its properties, data types, required fields, and example values, which will appear in the "Schemas" section of your Swagger UI.


What is a Reusable Schema Component?

In OpenAPI/Swagger, a schema component is a definition of a data object that can be reused across multiple parts of your documentation. Instead of defining the structure of a "Product" object every time you mention it (in the response for "get all products," in the request for "create a new product," etc.), you define it once and then simply reference it.

We will define this component within a JSDoc comment block, right in our source code. The swagger-jsdoc package will find this block and add it to the final specification under the components.schemas path.

Let's watch a video that demonstrates this concept perfectly.

NodeJS Swagger API Documentation Tutorial Using Swagger JSDoc

This clip from Maksim Ivanov's tutorial clearly shows how to define a reusable schema for a 'Book' model. It covers the exact YAML structure you'll need: defining the type, required fields, properties, and an example object.

Watch from 12:20 to 14:45. Focus on how the JSDoc comment is structured with YAML to define the Book schema inside components.schemas.


Implementing the Schema

As you saw in the video, the schema is defined using YAML syntax inside a /** ... */ comment block. Let's break down the structure for our own resource. For this course, we will build an API to manage "Products."

The schema definition goes at the top of the relevant route file, which for us will be src/routes/productRoutes.js.

Here is the general structure:

/**
 * @swagger
 * components:
 *   schemas:
 *     Product:
 *       type: object
 *       required:
 *         - name
 *         - price
 *       properties:
 *         _id:
 *           type: string
 *           description: The auto-generated id of the product
 *         name:
 *           type: string
 *           description: The name of the product
 *         description:
 *           type: string
 *           description: The description of the product
 *         price:
 *           type: number
 *           description: The price of the product
 *         createdAt:
 *           type: string
 *           format: date-time
 *           description: The date the product was added
 *       example:
 *         _id: d5fE_asz
 *         name: "Sample Product"
 *         description: "This is a sample product description."
 *         price: 29.99
 *         createdAt: "2023-01-01T12:00:00.000Z"
 */

Let's analyze the key parts:

  • components: schemas: Product:: This path tells swagger-jsdoc to create a reusable schema named Product.
  • type: object: Specifies that our Product is a JSON object.
  • required:: An array listing the fields that must be provided when creating or updating a product. This matches the required: true option in your Mongoose schema.
  • properties:: This is where each field of the model is defined.
    • _id, name, price, etc.: Each key is a property name.
    • type: The data type (e.g., string, number, integer, boolean). Note that MongoDB's ObjectId is represented as a string in JSON. Dates are also represented as string with a format: date-time.
    • description: A brief explanation of the field's purpose.
    • format: Provides more detail on the type (e.g., date-time for ISO 8601 date strings).
  • example:: A complete example object. This is extremely helpful as it shows users of your API exactly what a Product object looks like.

For another excellent code-based example, you can review the text resource below.

How to Document an Express API with Swagger UI and JSDoc

This article from Dev.to, 'How to Document an Express API with Swagger UI and JSDoc', provides another clear, text-based example of defining and referencing a reusable schema. It's a great reference to have open as you write your own.

Focus on section '3.4: Document the resources.' Notice how it defines a User schema under components/schemas and provides properties with types, descriptions, and examples. This pattern is exactly what we're implementing.


Your Turn: Define the Product Schema

Now, it's time to add this to your project.

  1. Open your main route file (e.g., src/routes/productRoutes.js). If you don't have this file yet, create it.
  2. At the very top of the file, add the JSDoc comment block shown above. You can copy and paste it directly.
  3. Verification:
    • Restart your server (npm run dev or node src/server.js).
    • Refresh the Swagger UI page in your browser (http://localhost:YOUR_PORT/api-docs).
    • Scroll to the bottom. You should now see a "Schemas" section with your Product model beautifully rendered, including its properties and the example payload.

It should look something like this:

Swagger Editor: Defining a Reusable Employee Schema
This image shows how a correctly defined schema component (in this case, for an 'employee') is rendered in the Swagger UI. You should see a similar collapsible section for your 'Product' model.

A Critical Note on Indentation

YAML, the language used inside JSDoc for Swagger, is extremely sensitive to indentation. Every level of nesting must be indented by exactly two spaces. If your schema doesn't appear, or if you get errors later, the first thing to check is your indentation.

The TomDoesTech video Automatically Generate Swagger Docs With ExpressJS & NodeJS (resource ID LINK) highlights this perfectly between 28:18 and 28:43. An incorrect indent can cause the entire definition to be ignored by swagger-jsdoc without any explicit error in your console.

Correct:

properties:
  _id:
    type: string

Incorrect (will fail silently):

properties:
 _id: // one space
    type: string // four spaces

Conclusion

Excellent work. You have now defined a clean, reusable data model for your API documentation. This is a foundational practice that will dramatically speed up the process of documenting individual endpoints and ensure your API documentation is consistent and professional.

Key Takeaways:

  • Reusable schemas are defined under components: schemas: in your JSDoc comments.
  • Each schema should define its type, required fields, and properties (including their type, description, and example values).
  • A top-level example: object provides a complete sample payload for users of your API.
  • YAML indentation is strict and must be correct (two spaces per level) for the schema to be parsed.

Next Up:

Our documentation page now knows what a Product is, but it still doesn't list any API operations. In the next lesson, we will put our new schema to use. We'll document our first endpoint—GET /api/products—and use a $ref to reference the Product schema, finally bringing your API operations to life in the Swagger UI.