Skip to main content

The Problem with the Old Petstore

For over a decade, every developer learning OpenAPI (formerly Swagger) has encountered the same example: the Petstore API. While it served its purpose as a teaching tool, the original Petstore has become outdated, failing to reflect modern API design practices and the full capabilities of OpenAPI 3.x specifications.

🚨 Critical Issue: Violation of RESTful Principles

The biggest problem? The old Petstore doesn’t even follow basic RESTful design principles. This is catastrophic because it teaches developers anti-patterns that they carry into production systems. Here are the specific RESTful violations in the original Swagger Petstore:

1. Plural vs Singular Resource Names

❌ BAD (Old Petstore):
/pet/{id}         ← Singular (incorrect)
/store/inventory  ← Plural (inconsistent)

βœ… GOOD (Modern Petstore):
/pets/{id}        ← Always plural for collections
/orders/{id}      ← Consistent pattern
Problem: Inconsistent naming confuses developers and breaks conventions.

2. Non-RESTful URL Design

❌ BAD (Old Petstore):
GET /pet/findByStatus?status=available  ← Action verb in URL
GET /pet/findByTags?tags=tag1,tag2      ← Action verb in URL

βœ… GOOD (Modern Petstore):
GET /pets?status=AVAILABLE              ← Resource-oriented
QUERY /pets/search                       ← Complex queries use QUERY method
Problem: URLs should represent resources (nouns), not actions (verbs).

3. Missing Standard HTTP Status Codes

❌ BAD (Old Petstore):
POST /pet β†’ Returns 200 OK (should be 201 Created)
DELETE /pet/{id} β†’ Returns 200 with body (should be 204 No Content)

βœ… GOOD (Modern Petstore):
POST /pets β†’ Returns 201 Created + Location header
DELETE /pets/{id} β†’ Returns 204 No Content
Problem: Incorrect status codes confuse clients and break HTTP semantics.

3. Wrong HTTP Methods for Authentication

❌ BAD (Old Petstore):
GET /user/login?username=john&password=secret123

βœ… GOOD (Modern Petstore):
POST /login
Content-Type: application/json
{
  "username": "john",
  "password": "secret123"
}
Problem: The old Petstore uses GET for login, which:
  • Exposes passwords in URL query parameters (visible in browser history, server logs, referrer headers)
  • Violates the HTTP specification (GET must be safe and idempotent)
  • Creates a massive security vulnerability
  • Is NOT cacheable despite using GET

5. No Collection Wrappers

❌ BAD (Old Petstore):
GET /pets β†’ Returns bare array
[
  {"id": "019b4132-70aa-764f-b315-e2803d882a24", "name": "Fluffy"},
  {"id": "019b4127-54d5-76d9-b626-0d4c7bfce5b6", "name": "Buddy"}
]

βœ… GOOD (Modern Petstore):
GET /pets β†’ Returns wrapped collection with metadata
{
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "totalItems": 45,
    "totalPages": 3
  },
  "links": {
    "self": "...",
    "next": "..."
  }
}
Problem: Bare arrays can’t be extended with metadata, breaking forward compatibility.

Other Critical Problems

Beyond RESTful violations, the old Petstore has:
  • Poor error handling: Generic error messages without structured validation
  • Weak security models: API keys in query parameters (another security disaster)
  • Missing standards: No RFC 9457 error format, outdated X-RateLimit headers
  • Incomplete examples: Lacks webhooks, SSE, polymorphic types
  • Non-production ready: No rate limiting, no proper validation, no real business logic
Teaching developers with the old Petstore is like teaching driving with a car that has the brake and gas pedals swapped. It actively harms the industry. It was time for a complete rewrite.

Introducing Modern Petstore API

We’ve built a completely reimagined Petstore API from the ground upβ€”one that showcases current best practices and demonstrates the full power of OpenAPI 3.2. This isn’t just an update; it’s a comprehensive reference implementation designed to be the new industry standard.

Our Mission

Create a pet store API that:
  • βœ… Demonstrates every OpenAPI 3.2 feature with production-ready examples
  • βœ… Follows current web standards (RFC 9457, IETF rate limiting, ISO formats)
  • βœ… Provides realistic business logic (payments, webhooks, AI features)
  • βœ… Includes comprehensive code samples across multiple languages
  • βœ… Serves as a learning resource for API designers and developers
  • βœ… Can be deployed to production with minimal modifications

What Makes It Modern?

βœ… Multi-Protocol Architecture

Modern PetstoreAPI is the only reference implementation supporting multiple API protocols and specifications: Unlike the classic Petstore (REST-only) and other examples (typically REST-only), we provide a complete multi-protocol architecture:
  • REST (OpenAPI 3.2) - Resource-oriented API following pure RESTful principles
  • Webhooks - Event-driven HTTP callbacks for asynchronous notifications
  • Callbacks - OpenAPI 3.x callback patterns for async request-response flows
  • SSE (Server-Sent Events) - Real-time streaming for live updates and AI responses
  • WebSocket - Full-duplex bidirectional real-time communication
  • Socket.IO - WebSocket with automatic fallback and enhanced features
  • MQTT - Lightweight publish-subscribe messaging protocol for IoT devices
  • MCP (Model Context Protocol) - AI assistant integration for Claude Desktop and other MCP clients
  • GraphQL - Flexible query language for complex data requirements
  • gRPC - High-performance RPC protocol for microservices
  • AsyncAPI 3.0 - Event-driven architecture specification
  • WSDL - SOAP web services for enterprise integration
  • WADL - Web Application Description Language support
  • RAML - RESTful API Modeling Language for API specification
This demonstrates that modern APIs can serve multiple client types and use cases from a single backend. Choose REST for simplicity, webhooks/callbacks for event-driven integration, SSE for real-time streaming, WebSocket/Socket.IO/MQTT for bidirectional real-time communication, MCP for AI assistant integration, GraphQL for flexibility, gRPC for performance, AsyncAPI for event-driven architecture, RAML for API modeling, or SOAP/WADL for legacy integration.

βœ… First and Foremost: True RESTful Design

This is the foundation everything else builds on. We follow RESTful principles rigorously:

1. Correct HTTP Methods for Every Operation

# Authentication
POST /login          ← POST for state-changing operations
POST /logout         ← POST (not GET)

# Resource Operations
GET    /pets         ← Safe, idempotent retrieval
POST   /pets         ← Create new resource
GET    /pets/{id}    ← Retrieve specific resource
PUT    /pets/{id}    ← Full update (idempotent)
PATCH  /pets/{id}    ← Partial update (idempotent)
DELETE /pets/{id}    ← Remove resource (idempotent)
Every method follows HTTP semantics:
  • GET: Safe (no side effects) and idempotent
  • POST: Create resources, submit forms, non-idempotent operations
  • PUT/PATCH: Idempotent updates
  • DELETE: Idempotent removal

2. Proper HTTP Status Codes

We use the right status code for every situation:
# Success Codes
201 Created          ← POST success + Location header pointing to new resource
200 OK               ← GET/PUT/PATCH success
204 No Content       ← DELETE success (no response body)

# Client Error Codes
400 Bad Request      ← Malformed request (invalid JSON, wrong content-type)
401 Unauthorized     ← Missing or invalid authentication
403 Forbidden        ← Authenticated but lacks permission
404 Not Found        ← Resource doesn't exist
409 Conflict         ← Resource conflict (duplicate creation)
422 Unprocessable    ← Valid request but validation failed

# Server Error Codes
500 Internal Error   ← Server-side failure
503 Service Unavailable ← Temporary service disruption
Example response with proper status code:
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "pet_fYrZzCW9E1WIOyGw",
  "species": "DOG",
  "name": "Buddy",
  ...
}

3. Resource-Oriented URL Design

URLs represent resources (nouns), not actions (verbs):
❌ BAD:
/getPets
/createPet
/updatePet
/deletePet
/findPetsByStatus

βœ… GOOD:
GET    /pets
POST   /pets
PUT    /pets/{id}
DELETE /pets/{id}
GET    /pets?status=AVAILABLE
For complex operations that don’t fit CRUD, we use:
  • Sub-resources: POST /orders/{id}/payment
  • Query parameters: GET /pets?status=AVAILABLE&species=DOG
  • QUERY method (OpenAPI 3.2): QUERY /pets/search with request body

4. Consistent Plural Nouns for Collections

βœ… Always use plural:
/pets           ← Collection
/pets/{id}      ← Single resource from collection
/users          ← Collection
/users/{id}     ← Single resource
/orders         ← Collection
/orders/{id}    ← Single resource
This consistency makes APIs predictable and intuitive.

5. Uniform Path Parameter Naming

βœ… Root resources use {id}:
/pets/{id}
/users/{id}
/orders/{id}

βœ… Nested resources use {parentId} for parent, {id} for child:
/users/{userId}/pets/{id}
/orders/{orderId}/items/{id}
Why this matters: Clients can predict URL patterns without reading docs.

6. Collection Wrappers with Pagination

Every collection endpoint returns a consistent structure:
{
  "data": [
    { "id": "pet_fYrZzCW9E1WIOyGw", "name": "Whiskers", ... },
    { "id": "pet_fYrZzCW9E1WIOyGw", "name": "Buddy", ... }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "totalItems": 145,
    "totalPages": 8
  },
  "links": {
    "self": "https://api.petstoreapi.com/v1/pets?page=1",
    "next": "https://api.petstoreapi.com/v1/pets?page=2",
    "prev": null,
    "first": "https://api.petstoreapi.com/v1/pets?page=1",
    "last": "https://api.petstoreapi.com/v1/pets?page=8"
  }
}
Benefits:
  • Never break pagination: Add totalItems later without breaking clients
  • Navigation links: Clients follow links, not construct URLs
  • Consistent structure: Every collection works the same way
Every resource includes navigational links:
{
  "id": "pet_fYrZzCW9E1WIOyGw",
  "name": "Whiskers",
  "species": "CAT",
  "status": "AVAILABLE",
  "links": {
    "self": "https://api.petstoreapi.com/v1/pets/pet_fYrZzCW9E1WIOyGw",
    "adopt": "https://api.petstoreapi.com/v1/adoptions",
    "images": "https://api.petstoreapi.com/v1/pets/pet_fYrZzCW9E1WIOyGw/images"
  }
}
Clients can:
  • Discover available operations
  • Navigate without hardcoding URLs
  • Evolve independently from URL changes

8. Content Negotiation

Support multiple representations:
GET /pets/{id}
Accept: application/json      ← Returns JSON
Accept: application/xml       ← Returns XML (if supported)
We standardize on JSON but the pattern supports future formats.

9. Idempotency Where Required

Operations that should be idempotent are:
βœ… Idempotent (same result when called multiple times):
GET    /pets/{id}      ← Always returns same pet
PUT    /pets/{id}      ← Update to same state produces same result
DELETE /pets/{id}      ← Deleting twice same as deleting once
PATCH  /pets/{id}      ← Partial update to same fields is idempotent

❌ Not idempotent (different result each time):
POST   /pets           ← Creates new pet with new ID each time
POST   /orders         ← Creates new order each time
This allows safe retries on network failures.

10. Caching Support

We include proper cache headers:
HTTP/1.1 200 OK
Cache-Control: public, max-age=300
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Last-Modified: Tue, 15 Nov 2025 12:45:26 GMT

# Conditional requests
GET /pets/{id}
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

HTTP/1.1 304 Not Modified
This reduces bandwidth and improves performance.

πŸ†• OpenAPI 3.2 Exclusive Features

Beyond RESTful fundamentals, we leverage the latest OpenAPI 3.2 specification features:

Hierarchical Tags

Organize your API endpoints with structured tagging:
tags:
  - name: Store
    summary: Store operations
    kind: category
  - name: Pet
    summary: Pet management
    parent: Store  # Nested under Store
    kind: resource
This creates a clean hierarchy in documentation tools, making large APIs easier to navigate.

QUERY HTTP Method

For complex searches that exceed URL length limits:
// Traditional GET has URL length limits
GET /pets?species=dog&age_min=12&age_max=36&good_with_kids=true...

// QUERY method uses request body while maintaining safe, idempotent semantics
QUERY /pets/search
{
  "criteria": {
    "species": ["DOG", "CAT"],
    "ageRange": { "min": 12, "max": 36 },
    "compatibility": { "goodWithKids": true }
  },
  "sort": { "field": "ageMonths", "order": "ASC" }
}

OAuth Device Flow

Perfect for smart TVs, IoT devices, and kiosks:
securitySchemes:
  oauth2:
    flows:
      deviceCode:
        deviceAuthorizationUrl: https://auth.petstoreapi.com/device/authorize
        tokenUrl: https://auth.petstoreapi.com/token
        scopes:
          read:pets: View pet information
          write:pets: Manage pets

Reusable Path Items

DRY principle for consistent resource patterns:
components:
  pathItems:
    PetResource:
      get:
        summary: Get Pet
      put:
        summary: Update Pet
      delete:
        summary: Delete Pet

paths:
  /pets/{id}:
    $ref: '#/components/pathItems/PetResource'

πŸ“š Modern API Standards

We don’t just follow OpenAPIβ€”we implement current web standards across the board:

RFC 9457: Problem Details for HTTP APIs

No more generic error messages. Every error response follows the standard:
{
  "type": "https://petstoreapi.com/errors/validation-error",
  "title": "Validation Error",
  "status": 422,
  "detail": "The request body contains validation errors",
  "instance": "/v1/pets",
  "errors": [
    {
      "field": "ageMonths",
      "message": "Must be a positive number",
      "code": "INVALID_FORMAT"
    }
  ]
}
Notice how it provides:
  • Structured field-level errors - developers know exactly what to fix
  • Unique error type URLs - link to detailed documentation
  • Machine-readable error codes - enable programmatic handling

IETF Rate Limiting Headers

We use the modern standard, not legacy X-RateLimit headers:
RateLimit-Limit: 100
RateLimit-Remaining: 95
RateLimit-Reset: 1640000000

ISO Standard Data Formats

  • ISO 3166-1 alpha-2: Country codes (US, GB, CA)
  • ISO 4217: Currency codes (USD, EUR, GBP)
  • ISO 8601 / RFC 3339: Timestamps (2025-12-17T08:00:00Z)
This ensures international compatibility and eliminates ambiguity.

🎨 Real-World API Patterns

Modern APIs aren’t simple CRUD operations. We demonstrate complex, production-ready patterns:

Polymorphic Payment Sources

Support multiple payment methods with discriminators:
{
  "amount": 150.00,
  "currency": "USD",
  "source": {
    "object": "CARD",
    "name": "Jane Doe",
    "number": "4242424242424242",
    "expMonth": 12,
    "expYear": 2025,
    "cvc": "123"
  }
}

// Or pay with bank account
{
  "amount": 150.00,
  "currency": "USD",
  "source": {
    "object": "BANK_ACCOUNT",
    "accountHolderName": "Jane Doe",
    "routingNumber": "110000000",
    "accountNumber": "000123456789",
    "accountType": "CHECKING"
  }
}
The OpenAPI spec uses discriminators to validate the correct fields based on object type:
discriminator:
  propertyName: object
  mapping:
    CARD: '#/components/schemas/CardPaymentSource'
    BANK_ACCOUNT: '#/components/schemas/BankAccountPaymentSource'

Collection Wrappers & Navigation

Never return bare arrays. Every collection response includes:
{
  "data": [
    {
      "id": "pet_fYrZzCW9E1WIOyGw",
      "species": "CAT",
      "name": "Whiskers",
      "links": {
        "self": "https://api.petstoreapi.com/v1/pets/pet_fYrZzCW9E1WIOyGw",
        "adopt": "https://api.petstoreapi.com/v1/adoptions"
      }
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "totalItems": 45,
    "totalPages": 3
  },
  "links": {
    "self": "https://api.petstoreapi.com/v1/pets?page=1",
    "next": "https://api.petstoreapi.com/v1/pets?page=2",
    "last": "https://api.petstoreapi.com/v1/pets?page=3"
  }
}
Benefits:
  • Pagination metadata - clients know exactly where they are
  • Navigation links - API is self-documenting and discoverable
  • Consistent structure - all collections follow the same pattern

Webhooks for Event-Driven Architecture

OpenAPI 3.x supports webhook definitions. We demonstrate real-world events:
webhooks:
  petAdopted:
    post:
      summary: Pet Adopted Event
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                eventId:
                  type: string
                  format: uuid
                eventType:
                  type: string
                  const: pet.adopted
                timestamp:
                  type: string
                  format: date-time
                data:
                  type: object
                  properties:
                    pet:
                      $ref: '#/components/schemas/Pet'
                    adopter:
                      $ref: '#/components/schemas/User'
Your application receives events when important actions occurβ€”no polling needed.

Server-Sent Events (SSE) for Real-Time Streaming

AI features need streaming responses. We demonstrate with a Pet Adoption Advisor:
const response = await fetch('https://api.petstoreapi.com/v1/chat/completions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_TOKEN'
  },
  body: JSON.stringify({
    messages: [
      { role: 'USER', content: 'What should I know before adopting a cat?' }
    ],
    model: 'PET_ADVISOR_1',
    stream: true
  })
});

// Stream tokens as they arrive
const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  const chunk = decoder.decode(value);
  const lines = chunk.split('\n').filter(line => line.trim());

  for (const line of lines) {
    if (line.startsWith('data: ')) {
      const data = JSON.parse(line.slice(6));
      process.stdout.write(data.choices[0]?.delta?.content || '');
    }
  }
}
The OpenAPI spec documents the SSE format with text/event-stream media type.

πŸ’» Developer Experience

Great APIs are easy to use. We’ve focused heavily on developer experience:

Multi-Language Code Examples

Every major operation includes x-codeSamples with ready-to-use examples: TypeScript:
import { PetStoreAPI } from '@petstoreapi/sdk';

const client = new PetStoreAPI({
  apiKey: process.env.PETSTORE_API_KEY
});

const pet = await client.pets.get('pet_fYrZzCW9E1WIOyGw');
console.log(`Found ${pet.name}, a ${pet.ageMonths}-month-old ${pet.species}`);
Python:
from petstore import PetStoreAPI

client = PetStoreAPI(api_key=os.environ['PETSTORE_API_KEY'])
pet = client.pets.get('pet_fYrZzCW9E1WIOyGw')
print(f"Found {pet.name}, a {pet.age_months}-month-old {pet.species}")
cURL:
curl https://api.petstoreapi.com/v1/pets/pet_fYrZzCW9E1WIOyGw \
  -H "Accept: application/json"

Workflow Descriptions

Every operation includes business context, not just technical details:
description: |
  Add a new pet to the store catalog, making it available for adoption.

  ## Pet Lifecycle Workflow

  When a new pet enters the system:

  1. **Intake**: Staff creates a pet record with this endpoint (status: `AVAILABLE`)
  2. **Profile**: Pet details include species, breed, age, medical info, photos
  3. **Discovery**: Pet appears in search results and listings
  4. **Adoption Application**: Potential adopters can apply
  5. **Adoption**: Once approved, pet status changes to `ADOPTED`

  **Access**: Requires staff permissions (`write:pets` scope or Bearer token).
Complex features link to detailed guides:
externalDocs:
  description: Learn more about webhooks
  url: https://petstoreapi.com/docs/webhooks

Technical Architecture

Built for Scalability

We’ve chosen a modern, performant stack:
  • Node.js: Industry-standard runtime
  • Hono: Fast, lightweight web framework
  • TypeScript: End-to-end type safety
  • Docker: Containerized deployment anywhere
This isn’t a toy exampleβ€”it’s production infrastructure.

Type Safety Everywhere

// Types generated from OpenAPI schema
interface Pet {
  id: string;
  species: 'DOG' | 'CAT' | 'RABBIT' | 'BIRD' | 'REPTILE' | 'OTHER';
  name: string;
  ageMonths: number;
  status: 'AVAILABLE' | 'PENDING' | 'ADOPTED' | 'NOT_AVAILABLE';
  // ... more fields
}

// Request handlers are fully typed
export async function getPet(c: Context): Promise<Pet> {
  const petId = c.req.param('id');
  const pet = await petStore.get(petId);

  if (!pet) {
    throw errors.notFound('Pet not found');
  }

  return pet;
}

Comprehensive Validation

We use unevaluatedProperties: false to catch unexpected fields:
Pet:
  type: object
  required: [id, name, species, ageMonths, status]
  properties:
    id: { type: string }
    name: { type: string }
    # ...
  unevaluatedProperties: false  # Reject unknown fields
This prevents clients from sending invalid data and makes API evolution explicit.

Comparison: Old vs. New

Let’s see how we stack up against the original Swagger Petstore and other modern examples. RESTful compliance is listed first as it’s the foundation:
FeatureOld PetstoreTrain Travel APIModern Petstore
πŸ”΄ RESTful: HTTP Methods❌ GET for login/logoutβœ… POST for mutationsβœ… Correct methods everywhere
πŸ”΄ RESTful: Status Codes❌ 200 for POST/DELETEβœ… Proper codesβœ… 201/204/4xx/5xx properly
πŸ”΄ RESTful: URL Design❌ /findByStatus (verbs)βœ… Resource-orientedβœ… Pure resource nouns
πŸ”΄ RESTful: Plural Resources❌ /pet (singular)βœ… /trips (plural)βœ… /pets, /users, /orders
πŸ”΄ RESTful: Path Parameters❌ /user/ mixedβœ… Consistentβœ… uniformly
πŸ”΄ RESTful: Collections❌ Bare arraysβœ… Wrappedβœ… Wrapped + pagination + links
πŸ”΄ RESTful: Idempotency❌ Not documentedβœ… Documentedβœ… Explicit + safe retries
OpenAPI Version2.03.1.03.2.0 βœ…
Error StandardCustomRFC 9457RFC 9457 + Field Details βœ…
Rate LimitingX-RateLimitRateLimit-*RateLimit-* βœ…
Auth MethodsAPI Key in URLOAuthOAuth + Bearer/JWT βœ…
OAuth FlowsNoneAuthorization CodeAuth Code + Device Flow βœ…
WebhooksNoneBasicComplete with Security βœ…
Real-time (SSE)NoneNoneFull SSE Implementation βœ…
QUERY MethodNoneNoneYes (OpenAPI 3.2) βœ…
Hierarchical TagsNoneFlatFull Hierarchy βœ…
Code SamplesNoneBasicMulti-language x-codeSamples βœ…
Polymorphic TypesNoneBasicDiscriminators with Mapping βœ…
Protocol SupportREST onlyREST onlyREST + SSE + MCP + GraphQL + gRPC + AsyncAPI + WSDL + WADL + RAML βœ…
Production ReadyNoPartialFully Deployable βœ…
Result: We lead in every category, with RESTful compliance being our strongest differentiator. The Modern Petstore follows 100% of RESTful principles plus modern extensions like QUERY method and structured navigation.

Real-World Use Cases

This isn’t just an exampleβ€”it’s a template for building production APIs:

🐾 Pet Adoption Platform

The obvious use case. Organizations can fork this and customize:
  • Add shelter locations with geospatial search
  • Integrate with local regulations and licensing
  • Add foster care management
  • Implement application review workflows

πŸ₯ Healthcare Appointment Systems

The patterns translate perfectly:
  • Pets β†’ Patients
  • Adoption Status β†’ Appointment Status
  • Medical Info β†’ Patient Records
  • Webhooks for appointment reminders

πŸ›’ E-Commerce Platforms

Same structural patterns:
  • Pets β†’ Products
  • Adoption β†’ Purchase
  • Species/Breed β†’ Categories
  • Polymorphic payments already implemented

πŸ“š Resource Booking Systems

Libraries, equipment rentals, room bookings:
  • Pets β†’ Resources
  • Availability Status β†’ Booking Status
  • User accounts and authentication ready
  • Search and filtering patterns established

Getting Started

Quick Start

# Clone the repository
git clone https://github.com/petstoreapi/PetstoreAPI.git
cd petstoreapi.com/packages/api

# Install dependencies
npm install

# Start development server
npm run dev

# API available at http://localhost:8787

Explore the API

# Seed sample data
curl -X POST http://localhost:8787/v1/seed

# List pets
curl http://localhost:8787/v1/pets

# Get specific pet
curl http://localhost:8787/v1/pets/pet_fYrZzCW9E1WIOyGw

# Try AI chat
curl -X POST http://localhost:8787/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{"role": "USER", "content": "Tell me about Golden Retrievers"}],
    "stream": false
  }'

View Documentation


Learning Resources

For API Designers

Study our OpenAPI spec to learn:
  • How to structure complex schemas with discriminators
  • When to use readOnly vs writeOnly
  • How to document workflows with descriptions
  • How to organize tags hierarchically
  • When to use references vs inline schemas

For API Developers

Learn implementation patterns:
  • Structured error handling with RFC 9457
  • Rate limiting middleware
  • OAuth 2.0 implementation
  • Webhook delivery with retries
  • SSE streaming for real-time data

For Technical Writers

See how to document:
  • Complex authentication flows
  • Multi-step business workflows
  • Error scenarios with examples
  • Code samples in multiple languages
  • External resource links

Design Principles

These principles guided every decision:

1. Standards Over Custom

We prefer established standards (RFC 9457, ISO codes, IETF headers) over inventing our own. Standards are:
  • Already documented
  • Widely understood
  • Supported by tools
  • Battle-tested

2. Production-Ready Over Simplified

Examples that are β€œtoo simple” teach bad habits. We include:
  • Proper error handling
  • Rate limiting
  • Security models
  • Validation
  • Pagination

3. Realistic Over Theoretical

We model actual business logic:
  • Payment processing with multiple methods
  • Multi-step workflows (adoption application β†’ approval β†’ completion)
  • Webhook event delivery
  • AI integration

4. Modern Over Compatible

We target the latest specifications:
  • OpenAPI 3.2 (not 3.0 or 2.0)
  • JSON Schema 2020-12
  • Current RFC standards
If you need older versions, this shows what you’re missing.

5. Complete Over Minimal

Every feature is fully implemented:
  • All CRUD operations
  • Search and filtering
  • Pagination
  • Webhooks
  • Streaming responses
No β€œTODO” comments or stub implementations.

What’s Next?

We’re continuously improving the Modern Petstore API:

Coming Soon

  • AsyncAPI 3.0 Specification: Complete async/event documentation
  • Arazzo Workflows: Step-by-step workflow definitions
  • GraphQL Endpoint: Demonstrate REST + GraphQL coexistence
  • More Code Samples: Go, Java, PHP, Ruby
  • Performance Benchmarks: Quantified edge performance metrics
  • Video Tutorials: Walkthrough of key features

Community

This project thrives on community contributions:
  • GitHub Discussions: Share use cases and ask questions
  • Issues: Report bugs or request features
  • Pull Requests: Contribute improvements
  • Blog Posts: Write about how you’re using the API
  • Translations: Help document in other languages

Conclusion

The Modern Petstore API isn’t just an updateβ€”it’s a reimagining of what an API example should be: βœ… Complete OpenAPI 3.2 showcase βœ… Current web standards throughout βœ… Production-ready architecture βœ… Real-world business patterns βœ… Comprehensive documentation βœ… Multi-language code samples βœ… Deployable to Docker/Node.js Whether you’re learning OpenAPI, designing a new API, evaluating API tools, or teaching others, the Modern Petstore API provides a comprehensive, realistic reference. The classic Petstore served us well for over a decade. Now it’s time for a new standard.

Try It Now

Live API: https://api.petstoreapi.com Interactive Docs: https://api.petstoreapi.com/v1/docs GitHub: https://github.com/petstoreapi/PetstoreAPI OpenAPI Spec: https://api.petstoreapi.com/v1/openapi.json Give it a star ⭐ if you find it useful!

About the Project

The Modern Petstore API is an open-source project created to demonstrate best practices in API design. It’s maintained by the community and welcomes contributions from developers worldwide. Built with ❀️ using:
  • OpenAPI 3.2
  • TypeScript
  • Hono
  • Node.js / Docker
  • Modern Web Standards
License: MIT
Last updated: December 2025