Your Swagger/OpenAPI definition can be a single source of truth for all your environments, but it needs a little help to know where each one lives.
Let’s say you have a Swagger definition that looks something like this:
swagger: "2.0"
info:
version: 1.0.0
title: My Awesome API
paths:
/users:
get:
summary: Get a list of users
responses:
"200":
description: A list of users
schema:
type: array
items:
$ref: "#/definitions/User"
definitions:
User:
type: object
properties:
id:
type: string
name:
type: string
This definition is great for describing your API, but it doesn’t tell tools where to find it. That’s where the host, basePath, and schemes fields come in.
The host is the domain name or IP address where your API is served. basePath is the prefix for all API paths (e.g., /v1). schemes specifies the protocol (e.g., http or https).
To manage different environments, you’ll typically define these fields for each environment.
Dev Environment
For local development, you might be running your API on localhost:3000.
swagger: "2.0"
info:
version: 1.0.0
title: My Awesome API
host: localhost:3000
basePath: /
schemes:
- http
paths:
/users:
get:
summary: Get a list of users
responses:
"200":
description: A list of users
schema:
type: array
items:
$ref: "#/definitions/User"
definitions:
User:
type: object
properties:
id:
type: string
name:
type: string
This tells tools that when they refer to My Awesome API, they should look at http://localhost:3000.
Staging Environment
Your staging environment might be hosted on a subdomain like staging.myapi.com.
swagger: "2.0"
info:
version: 1.0.0
title: My Awesome API
host: staging.myapi.com
basePath: /api/v1
schemes:
- https
paths:
/users:
get:
summary: Get a list of users
responses:
"200":
description: A list of users
schema:
type: array
items:
$ref: "#/definitions/User"
definitions:
User:
type: object
properties:
id:
type: string
name:
type: string
Now, tools know that My Awesome API on staging is reachable at https://staging.myapi.com/api/v1.
Production Environment
Your production environment could be api.myapi.com.
swagger: "2.0"
info:
version: 1.0.0
title: My Awesome API
host: api.myapi.com
basePath: /v1
schemes:
- https
paths:
/users:
get:
summary: Get a list of users
responses:
"200":
description: A list of users
schema:
type: array
items:
$ref: "#/definitions/User"
definitions:
User:
type: object
properties:
id:
type: string
name:
type: string
This configures tools to target https://api.myapi.com/v1 for production.
How to Manage Multiple Definitions
You have a few options for managing these environment-specific configurations:
-
Separate Files: Maintain entirely separate
swagger.yamlfiles for each environment (e.g.,swagger-dev.yaml,swagger-staging.yaml,swagger-prod.yaml). This is simple but can lead to duplication. -
Templating: Use a templating engine (like Jinja2, Handlebars, or even simple shell scripts) to generate your final Swagger file from a base template and environment variables. This reduces duplication.
For example, a Jinja2 template might look like:
swagger: "2.0" info: version: 1.0.0 title: My Awesome API host: {{ host }} basePath: {{ basePath }} schemes: - {{ scheme }} paths: # ... rest of your paths ... definitions: # ... your definitions ...And you’d render it like:
export HOST="api.myapi.com" export BASE_PATH="/v1" export SCHEME="https" # Use your templating tool to render swagger.yaml.j2 into swagger.yaml -
External References (less common for host/basePath): While not ideal for
hostandbasePaththemselves, you can use$refto pull in common parts of your definition from other files. This is more useful for reusable data models.
The "Single Source of Truth" Illusion
The idea is to have one definition that accurately describes your API, but the endpoints it refers to change. Tools like Swagger UI, Swagger Codegen, and API gateways use the host, basePath, and schemes to know where to send requests. By changing these fields, you’re effectively telling these tools to talk to a different instance of your API.
When you generate client SDKs using Swagger Codegen, the generated code will be configured to hit the host specified in your definition. If you generate for production, it uses the production host.
This approach is crucial for ensuring that your documentation, code generation, and API testing tools are always pointing to the correct environment.
The next hurdle is often managing API keys or authentication tokens for each environment.