Manual YAML writing guide (design-first approach)

This guide teaches you how to create OpenAPI specifications by hand-crafting YAML files. You’ll learn the design-first approach where you create the API documentation before (or alongside) the implementation, giving you complete control over the documentation structure and content.

Duration: 60-90 minutes Prerequisites: Basic understanding of YAML syntax and REST APIs


Overview: design-first documentation

In the design-first approach, you create the OpenAPI specification manually in YAML format, then use it to guide both development and documentation:

API Design → YAML Specification → Validation → Implementation → Testing
     ↓              ↓                ↓             ↓           ↓
   Planning    Documentation    Live Preview    Code Dev    Accuracy Check

Step 1: understanding OpenAPI structure

Before writing YAML specifications, understand the basic OpenAPI 3.0 structure:

openapi: 3.0.1                    # Version specification
info:                             # API metadata
  title: Your API Name
  version: 1.0.0
  description: What your API does

servers:                          # Where the API is hosted
  - url: http://localhost:8080
    description: Development server

paths:                            # API endpoints
  /endpoint:
    get:                          # HTTP methods
      summary: Brief description
      description: Detailed explanation
      responses:                  # Possible responses
        '200':
          description: Success response

components:                       # Reusable schemas
  schemas:
    ModelName:                    # Data models
      type: object
      properties:
        field: type

For this tutorial, you’ll work with a Customer Management API that handles:

  • Creating, reading, updating, and deleting customers
  • Customer search and pagination
  • Nested address information
  • Different customer types (INDIVIDUAL, BUSINESS, VIP, PREMIUM)

Step 2: setting up your YAML editor

Choose your option for configuring your YAML editor.

  1. Open Swagger Editor: https://editor.swagger.io/
  2. Start with example: Copy the demo file to get started
    # Copy the demo file content
    cat api-assets/openapi/examples/swagger-editor-demo.yaml
    
  3. Paste and edit: Replace the content in Swagger Editor with our demo file
  4. Live validation: See real-time validation and preview as you edit

Option 2: online validators

  • Swagger Inspector: https://inspector.swagger.io/
  • OpenAPI Validator: https://validator.swagger.io/

Step 3: hands-on YAML writing tutorial

Follow these exercises to start writing YAML API specifications.

Exercise 1: complete the practice template

Start with the practice template that has TODO items for you to complete:

# Open the practice file
open api-assets/openapi/practice-exercise.yaml

Your task: Complete the TODO items in order.

Exercise 2: add complete endpoint documentation

Add POST /customers endpoint

Find the TODO:

# TODO: Add POST /customers endpoint

Add this complete endpoint:

  /customers:
    post:
      summary: Create a new customer
      description: |
        Creates a new customer with complete profile information.

        **Business Rules:**
        - Customer ID must be unique and follow CUSTXXX format
        - All required fields must be provided
        - Phone numbers are validated for basic format
        - Address information is required for all customer types

        **Workflow:**
        1. Validate customer data format
        2. Check for duplicate customer ID
        3. Save customer to database
        4. Return success confirmation
      tags:
        - Customer Operations
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Customer'
            examples:
              individual_customer:
                summary: Individual customer example
                value:
                  id: "CUST001"
                  name: "Alice Johnson"
                  phone: "555-0123"
                  type: "INDIVIDUAL"
                  address:
                    street: "123 Main St"
                    city: "New York"
                    state: "NY"
                    zipCode: "10001"
                    country: "USA"
              business_customer:
                summary: Business customer example
                value:
                  id: "CUST002"
                  name: "Acme Corporation"
                  phone: "555-0199"
                  type: "BUSINESS"
                  address:
                    street: "456 Business Ave"
                    city: "Chicago"
                    state: "IL"
                    zipCode: "60601"
                    country: "USA"
      responses:
        '200':
          description: Customer created successfully
          content:
            text/plain:
              schema:
                type: string
              example: "Customer added successfully"
        '400':
          description: Invalid customer data provided
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                message: "Invalid customer data: ID format must be CUSTXXX"
                timestamp: "2026-01-25T10:30:00.000Z"
                status: 400
                error: "Bad Request"
        '409':
          description: Customer with this ID already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                message: "Customer with ID CUST001 already exists"
                timestamp: "2026-01-25T10:30:00.000Z"
                status: 409
                error: "Conflict"

Step 4: advanced YAML features

Once you’re comfortable writing basic YAML, try out these advanced YAML features.

Using references ($ref)

Instead of repeating schema definitions, use references:

# Define once in components
components:
  schemas:
    Customer:
      type: object
      properties:
        # ... customer properties

# Reference multiple times
paths:
  /customers:
    post:
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Customer'  # Reference
    get:
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Customer'  # Reference again

Multiple examples

Provide different examples for different scenarios:

requestBody:
  content:
    application/json:
      schema:
        $ref: '#/components/schemas/Customer'
      examples:
        minimal_example:
          summary: Minimal required fields
          description: Example with only required fields
          value:
            id: "CUST001"
            name: "John Doe"
            type: "INDIVIDUAL"
        complete_example:
          summary: Complete customer data
          description: Example with all optional fields included
          value:
            id: "CUST002"
            name: "Jane Smith"
            phone: "555-0123"
            type: "VIP"
            address:
              street: "123 Main St"
              city: "New York"
              state: "NY"
              zipCode: "10001"
              country: "USA"

Advanced validation

Add detailed validation rules:

Customer:
  type: object
  properties:
    id:
      type: string
      pattern: '^CUST[0-9]{3}$'          # Regex validation
      description: Must follow format CUSTXXX
    name:
      type: string
      minLength: 1                        # Minimum length
      maxLength: 100                      # Maximum length
    phone:
      type: string
      pattern: '^[0-9\-\+\(\)\s]+$'      # Phone number format
    email:
      type: string
      format: email                       # Built-in email validation

Step 5: validating your YAML specification

Once you’ve written your YAML specification, validation ensures it meets OpenAPI standards and will work correctly with tools.

Real-time validation in editors

  1. Swagger editor: Shows errors immediately in the right panel.
  2. VS Code with OpenAPI extension: Underlines errors with red squiggles.
  3. Online validators: Paste your YAML for validation.

Testing against running API

Validate your handwritten specification against the actual API:

# Start the API
./mvnw spring-boot:run

# Test your documented examples
curl -X POST http://localhost:8080/customer \
  -H "Content-Type: application/json" \
  -d '{
    "id": "CUST001",
    "name": "Alice Johnson",
    "phone": "555-0123",
    "type": "INDIVIDUAL",
    "address": {
      "street": "123 Main St",
      "city": "New York",
      "state": "NY",
      "zipCode": "10001",
      "country": "USA"
    }
  }'

Common validation errors

YAML Syntax Errors:

# Wrong - inconsistent indentation
info:
  title: My API
   version: 1.0.0  # Extra space causes error

# Correct - consistent indentation
info:
  title: My API
  version: 1.0.0

Missing Required Fields:

# Wrong - missing required 'info' section
openapi: 3.0.1
paths:
  /test: {}

# Correct - includes required fields
openapi: 3.0.1
info:
  title: Test API
  version: 1.0.0
paths:
  /test: {}

Invalid References:

# Wrong - reference doesn't exist
schema:
  $ref: '#/components/schemas/NonexistentSchema'

# Correct - reference exists in components
components:
  schemas:
    Customer:
      type: object
# Later in document:
schema:
  $ref: '#/components/schemas/Customer'

Step 6: comparing with generated documentation

Understanding how your manual specification differs from automatically generated documentation helps you leverage the strengths of each approach.

Compare your handwritten specification with the auto-generated one:

# Get the generated specification
curl http://localhost:8080/v3/api-docs.yaml > generated-spec.yaml

# Compare with your hand-written version
diff my-api-spec.yaml generated-spec.yaml

Key differences to observe:

  • Structure organization:
    • Generated: Follows code structure
    • Manual: Can be organized for user understanding
  • Description quality
    • Generated: Technical, developer-focused
    • Manual: Can include business context and user guidance
  • Example completeness

Next steps