Skip to main content

Overview

RAML Specification: https://api.petstoreapi.com/v1/specs/modern-petstore.raml Protocol: RESTful API over HTTP/HTTPS RAML Version: RAML 1.0 Format: YAML-based API description language RAML is a YAML-based language for describing RESTful APIs. It provides a structured, human-readable format for API design that emphasizes reusability, modularity, and developer experience.

What is RAML?

RAML (RESTful API Modeling Language) is a YAML-based language specifically designed for describing RESTful APIs. It focuses on making API design simple, reusable, and human-readable while providing powerful features for complex API specifications.

Key Features

  • Human-Readable: YAML syntax is clean and intuitive
  • Reusable Components: Types, traits, and resource types
  • Design-First: Facilitates API-first development
  • Documentation: Auto-generates interactive documentation
  • Code Generation: Generates server stubs and client SDKs
  • Validation: Strong typing with built-in validation
  • Modular: Split specifications across multiple files

When to Use RAML

RAML is particularly useful when:
  • Designing APIs before implementation (design-first approach)
  • Need highly modular, reusable API specifications
  • Working with MuleSoft or other RAML-first tools
  • Requiring strong type validation
  • Building APIs with consistent patterns
  • Collaborating with API designers and developers

RAML Structure

A RAML specification consists of these main sections:
#%RAML 1.0
title: Modern Petstore API
version: v1
baseUri: https://api.petstoreapi.com/{version}
protocols: [HTTPS]
mediaType: application/json

documentation:
  - title: Introduction
    content: |
      Modern Petstore API demonstrating RESTful best practices
      and OpenAPI 3.2 features.

# Types (Data Models)
types:
  Pet:
    type: object
    properties:
      id:
        type: string
        description: Unique identifier
      name:
        type: string
        description: Pet name
        minLength: 1
        maxLength: 100
      species:
        type: string
        enum: [DOG, CAT, RABBIT, BIRD, REPTILE, OTHER]

# Traits (Reusable Behaviors)
traits:
  paginated:
    queryParameters:
      page:
        type: integer
        default: 1
        minimum: 1
      limit:
        type: integer
        default: 20
        minimum: 1
        maximum: 100

  searchable:
    queryParameters:
      q:
        type: string
        required: false
        description: Search query

# Resource Types (Reusable Resources)
resourceTypes:
  collection:
    get:
      description: List all <<resourcePathName>>
      responses:
        200:
          body:
            application/json:
              type: <<resourcePathName | !uppercamelcase>>Collection
    post:
      description: Create a new <<resourcePathName | !singularize>>
      body:
        application/json:
          type: <<resourcePathName | !uppercamelcase | !singularize>>
      responses:
        201:
          body:
            application/json:
              type: <<resourcePathName | !uppercamelcase | !singularize>>

# API Resources
/pets:
  type: collection
  is: [paginated, searchable]
  get:
    queryParameters:
      species:
        type: string
        enum: [DOG, CAT, RABBIT, BIRD, REPTILE, OTHER]
      status:
        type: string
        enum: [AVAILABLE, PENDING, ADOPTED, NOT_AVAILABLE]
        default: AVAILABLE

  /{id}:
    uriParameters:
      id:
        type: string
        description: Unique pet identifier
    get:
      description: Get a specific pet
      responses:
        200:
          body:
            application/json:
              type: Pet
        404:
          body:
            application/json:
              type: Error

Understanding RAML Elements

Types (Data Models)

RAML uses types to define data structures:
types:
  # Object type
  Pet:
    type: object
    properties:
      id:
        type: string
        pattern: ^pet_[a-zA-Z0-9]+$
      name:
        type: string
        minLength: 1
        maxLength: 100
      species:
        type: PetSpecies
      ageMonths:
        type: integer
        minimum: 0
      status:
        type: PetStatus
      adoptionFee?:  # Optional property (?)
        type: number
        minimum: 0
    required: [id, name, species, ageMonths, status]

  # Enum type
  PetSpecies:
    type: string
    enum:
      - DOG
      - CAT
      - RABBIT
      - BIRD
      - REPTILE
      - OTHER

  # Enum type
  PetStatus:
    type: string
    enum: [AVAILABLE, PENDING, ADOPTED, NOT_AVAILABLE]

  # Array type
  PetArray:
    type: Pet[]

  # Collection wrapper
  PetCollection:
    type: object
    properties:
      data:
        type: Pet[]
      pagination:
        type: PaginationMetadata
      links:
        type: NavigationLinks

  # Nested type
  PaginationMetadata:
    type: object
    properties:
      page:
        type: integer
      limit:
        type: integer
      totalItems:
        type: integer
      totalPages:
        type: integer

  # Union type (polymorphism)
  PaymentSource:
    type: CardPaymentSource | BankAccountPaymentSource
    discriminator: object

  CardPaymentSource:
    type: object
    discriminatorValue: CARD
    properties:
      object:
        type: string
        enum: [CARD]
      cardNumber:
        type: string
        pattern: ^\d{13,19}$

  BankAccountPaymentSource:
    type: object
    discriminatorValue: BANK_ACCOUNT
    properties:
      object:
        type: string
        enum: [BANK_ACCOUNT]
      accountNumber:
        type: string

Traits (Reusable Behaviors)

Traits are reusable method characteristics:
traits:
  # Pagination trait
  paginated:
    queryParameters:
      page:
        type: integer
        default: 1
        minimum: 1
        description: Page number
      limit:
        type: integer
        default: 20
        minimum: 1
        maximum: 100
        description: Items per page

  # Search trait
  searchable:
    queryParameters:
      q:
        type: string
        required: false
        description: Search query

  # Authentication trait
  authenticated:
    headers:
      Authorization:
        type: string
        pattern: ^Bearer .+$
        description: Bearer token
        example: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

  # Rate limiting trait
  rateLimited:
    responses:
      429:
        description: Rate limit exceeded
        headers:
          RateLimit-Limit:
            type: integer
            description: Request limit per window
          RateLimit-Remaining:
            type: integer
            description: Remaining requests
          RateLimit-Reset:
            type: integer
            description: Reset timestamp (Unix time)

# Apply traits to resources
/pets:
  get:
    is: [paginated, searchable, rateLimited]
  post:
    is: [authenticated, rateLimited]

Resource Types (Reusable Resources)

Resource types define reusable resource patterns:
resourceTypes:
  # Standard collection pattern
  collection:
    description: Collection of <<resourcePathName>>
    get:
      description: List all <<resourcePathName>>
      is: [paginated]
      responses:
        200:
          body:
            application/json:
              type: <<resourcePathName | !uppercamelcase>>Collection
    post:
      description: Create a new <<resourcePathName | !singularize>>
      is: [authenticated]
      body:
        application/json:
          type: <<resourcePathName | !uppercamelcase | !singularize>>
      responses:
        201:
          description: Created successfully
          headers:
            Location:
              description: URL of created resource
          body:
            application/json:
              type: <<resourcePathName | !uppercamelcase | !singularize>>

  # Standard member pattern
  member:
    description: Single <<resourcePathName | !singularize>>
    get:
      description: Get <<resourcePathName | !singularize>>
      responses:
        200:
          body:
            application/json:
              type: <<resourcePathName | !uppercamelcase | !singularize>>
        404:
          body:
            application/json:
              type: Error
    put:
      description: Update <<resourcePathName | !singularize>>
      is: [authenticated]
      body:
        application/json:
          type: <<resourcePathName | !uppercamelcase | !singularize>>
      responses:
        200:
          body:
            application/json:
              type: <<resourcePathName | !uppercamelcase | !singularize>>
    delete:
      description: Delete <<resourcePathName | !singularize>>
      is: [authenticated]
      responses:
        204:
          description: Deleted successfully

# Apply resource types
/pets:
  type: collection
  /{id}:
    type: member

/users:
  type: collection
  /{id}:
    type: member

/orders:
  type: collection
  /{id}:
    type: member

Code Examples

TypeScript

import axios from 'axios';

const baseURL = 'https://api.petstoreapi.com/v1';

// List pets with filtering and pagination
async function listPets() {
  const response = await axios.get(`${baseURL}/pets`, {
    params: {
      species: 'DOG',
      status: 'AVAILABLE',
      page: 1,
      limit: 20
    }
  });

  const { data, pagination } = response.data;
  console.log(`Found ${pagination.totalItems} pets`);
  return data;
}

// Get a specific pet
async function getPet(id: string) {
  const response = await axios.get(`${baseURL}/pets/${id}`);
  return response.data;
}

// Create a new pet
async function createPet(token: string) {
  const response = await axios.post(
    `${baseURL}/pets`,
    {
      name: 'Buddy',
      species: 'DOG',
      breed: 'Golden Retriever',
      ageMonths: 24,
      status: 'AVAILABLE',
      adoptionFee: 150.00,
      currency: 'USD'
    },
    {
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      }
    }
  );

  console.log(`Created pet: ${response.data.id}`);
  return response.data;
}

// Update a pet
async function updatePet(id: string, token: string) {
  const response = await axios.put(
    `${baseURL}/pets/${id}`,
    {
      name: 'Buddy',
      species: 'DOG',
      ageMonths: 25,
      status: 'ADOPTED'
    },
    {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    }
  );

  return response.data;
}

// Delete a pet
async function deletePet(id: string, token: string) {
  await axios.delete(`${baseURL}/pets/${id}`, {
    headers: {
      'Authorization': `Bearer ${token}`
    }
  });

  console.log('Pet deleted successfully');
}

Python

import requests

BASE_URL = 'https://api.petstoreapi.com/v1'

# List pets with filtering
def list_pets():
    response = requests.get(f'{BASE_URL}/pets', params={
        'species': 'DOG',
        'status': 'AVAILABLE',
        'page': 1,
        'limit': 20
    })

    data = response.json()
    print(f"Found {data['pagination']['totalItems']} pets")
    return data['data']

# Get a specific pet
def get_pet(pet_id):
    response = requests.get(f'{BASE_URL}/pets/{pet_id}')
    response.raise_for_status()
    return response.json()

# Create a new pet
def create_pet(token):
    response = requests.post(
        f'{BASE_URL}/pets',
        json={
            'name': 'Buddy',
            'species': 'DOG',
            'breed': 'Golden Retriever',
            'ageMonths': 24,
            'status': 'AVAILABLE',
            'adoptionFee': 150.00,
            'currency': 'USD'
        },
        headers={
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json'
        }
    )

    response.raise_for_status()
    pet = response.json()
    print(f"Created pet: {pet['id']}")
    return pet

# Handle errors with RAML-defined error format
try:
    pet = get_pet('invalid_id')
except requests.HTTPError as e:
    if e.response.status_code == 404:
        error = e.response.json()
        print(f"Error: {error['title']} - {error['detail']}")

cURL

# List pets with filtering
curl "https://api.petstoreapi.com/v1/pets?species=DOG&status=AVAILABLE&page=1&limit=20"

# Get a specific pet
curl https://api.petstoreapi.com/v1/pets/pet_fYrZzCW9E1WIOyGw

# Create a new pet (requires authentication)
curl -X POST https://api.petstoreapi.com/v1/pets \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Buddy",
    "species": "DOG",
    "breed": "Golden Retriever",
    "ageMonths": 24,
    "status": "AVAILABLE",
    "adoptionFee": 150.00,
    "currency": "USD"
  }'

# Update a pet
curl -X PUT https://api.petstoreapi.com/v1/pets/pet_fYrZzCW9E1WIOyGw \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Buddy",
    "species": "DOG",
    "ageMonths": 25,
    "status": "ADOPTED"
  }'

# Delete a pet
curl -X DELETE https://api.petstoreapi.com/v1/pets/pet_fYrZzCW9E1WIOyGw \
  -H "Authorization: Bearer YOUR_TOKEN"

RAML Tools

API Console

Interactive API documentation:
# Install RAML API Console
npm install -g api-console-cli

# Serve API Console
api-console dev https://api.petstoreapi.com/v1/specs/modern-petstore.raml

# Opens at http://localhost:8080

Code Generation

Generate Node.js Server (Osprey)

# Install Osprey
npm install -g osprey-cli

# Generate Express.js server
osprey-gen --language node https://api.petstoreapi.com/v1/specs/modern-petstore.raml ./server

cd server
npm install
npm start

Generate Client SDK (raml-client-generator)

# Install generator
npm install -g raml-client-generator

# Generate TypeScript client
raml-client-generator https://api.petstoreapi.com/v1/specs/modern-petstore.raml \
  --language typescript \
  --output ./client

Validation

Validate RAML Specification

# Install RAML parser
npm install -g raml-1-parser

# Validate RAML
raml-validate petstore.raml

# Parse and display structure
raml-parse petstore.raml

Design Patterns

1. Modular Specifications

Split large RAML files into modules: main.raml:
#%RAML 1.0
title: Petstore API
version: v1

uses:
  types: ./types.raml
  traits: ./traits.raml

/pets:
  type: types.collection
  is: [traits.paginated]
types.raml:
#%RAML 1.0 Library

types:
  Pet:
    type: object
    properties:
      id: string
      name: string

  collection:
    get:
      responses:
        200:
          body:
            application/json
traits.raml:
#%RAML 1.0 Library

traits:
  paginated:
    queryParameters:
      page:
        type: integer
        default: 1

2. Overlays

Extend RAML specifications without modifying the original: base.raml:
#%RAML 1.0
title: Petstore API

/pets:
  get:
    description: List pets
overlay.raml:
#%RAML 1.0 Overlay
extends: base.raml

/pets:
  get:
    queryParameters:
      species:
        type: string
        enum: [DOG, CAT]

3. Examples

Include realistic examples:
types:
  Pet:
    type: object
    properties:
      id: string
      name: string
      species: string
    example:
      id: pet_fYrZzCW9E1WIOyGw
      name: Buddy
      species: DOG

/pets:
  get:
    responses:
      200:
        body:
          application/json:
            type: PetCollection
            example:
              data:
                - id: pet_fYrZzCW9E1WIOyGw
                  name: Buddy
                  species: DOG
                - id: pet_abc123
                  name: Whiskers
                  species: CAT
              pagination:
                page: 1
                limit: 20
                totalItems: 2
                totalPages: 1

RAML vs OpenAPI

FeatureRAMLOpenAPI
FormatYAML onlyYAML or JSON
ReusabilityExcellent (traits, types, resource types)Good (components)
ModularityLibraries, overlays, fragments$ref (external files)
Learning CurveModerateEasier
ToolingMuleSoft-focusedBroader ecosystem
Type SystemBuilt-in typesJSON Schema
Design PatternsResource types, traitsComponents, schemas
CommunitySmallerLarger (OpenAPI Initiative)
Use CaseAPI design, MuleSoftAPI documentation, tooling

When to Use RAML

✅ Choose RAML when:
  • Using MuleSoft Anypoint Platform
  • Need highly modular specifications
  • Want design-first approach with strong patterns
  • Require reusable resource types and traits
  • Building APIs with consistent patterns
  • Team prefers YAML

When to Use OpenAPI

✅ Choose OpenAPI when:
  • Need broad tooling support
  • Want industry-standard format
  • Building APIs for multiple platforms
  • Using Swagger/Redoc documentation
  • Integrating with API gateways
  • Want JSON Schema compatibility

Best Practices

1. Use Descriptive Resource Names

✅ GOOD:
/pets              # Plural, descriptive
/orders            # Clear purpose
/users             # Standard naming

❌ BAD:
/pet               # Singular
/get-pets          # Verb in URL
/p                 # Too short

2. Leverage Resource Types

resourceTypes:
  collection:
    get:
      is: [paginated]
    post:
      is: [authenticated]

# Apply to multiple resources
/pets: { type: collection }
/users: { type: collection }
/orders: { type: collection }

3. Use Traits for Cross-Cutting Concerns

traits:
  authenticated: ...
  paginated: ...
  searchable: ...
  rateLimited: ...

/pets:
  get:
    is: [paginated, searchable, rateLimited]
  post:
    is: [authenticated, rateLimited]

4. Document with Examples

/pets/{id}:
  get:
    description: Retrieve pet details
    responses:
      200:
        body:
          application/json:
            type: Pet
            example:
              id: pet_fYrZzCW9E1WIOyGw
              name: Buddy
              species: DOG
              ageMonths: 24
              status: AVAILABLE

Migration Guide

From RAML to OpenAPI

Convert RAML specifications to OpenAPI:
# Install oas-raml-converter
npm install -g oas-raml-converter

# Convert RAML to OpenAPI 3.0
oas-raml-converter --from RAML --to OAS30 petstore.raml > petstore-openapi.yaml
Manual Mapping:
RAMLOpenAPI 3.x
TypesComponents/Schemas
TraitsReusable parameters/responses
Resource TypesPath item templates
Security SchemesSecurity Schemes
ExamplesExamples

From OpenAPI to RAML

Our conversion script generates RAML from OpenAPI:
npm run oas30-to-raml

Additional Resources


Support

For questions or issues with the RAML specification: