# ...
Source: https://speakeasy.com/blog/openapi-servers

import { Callout } from "@/mdx/components";

<Callout title="Announcing: OpenAPI Reference" type="default">
Hi! These blog posts have been popular, so we've built an entire [OpenAPI Reference Guide](/openapi/) to answer any question you have.

It includes detailed information on [**servers**](/openapi/servers).

Happy Spec Writing!

</Callout>

In this post, we'll take a detailed look at how the OpenAPI Specification (OAS) allows us to define servers in our OpenAPI documents (OADs), then at a few tips to help you provide the best developer experience for your users.

This aspect of API design is often overlooked, but specifying servers in a flexible and robust way can ensure your users know exactly where to send API calls, allows users the flexibility to pick a specific server based on their preference or data-privacy requirements, and allows your developers to switch between development and production environments while testing without editing code.

## A Brief History of Base URLs in Swagger (OAS 2.0)

If you have some experience with Swagger 2.0, the predecessor to OpenAPI 3.0, you may recall that specifying servers for your API was somewhat rigid. We're including this to show you how to convert your Swagger 2.0 base URL definition to OpenAPI 3.x later on. If you don't have a Swagger 2.0 document, you can safely skip this section.

In Swagger 2.0, we could define three fields to tell API users where to send requests: `host`, `basePath`, and `schemes`. The `host` specified the domain name or IP, the `basePath` defined the base path for the API, and `schemes` determined the protocols (HTTP or HTTPS) as an array.

Here's an example of the relevant Swagger 2.0 fields:

```yaml filename="swagger-2.0.yaml"
swagger: "2.0"
host: api.example.com
basePath: /v1
schemes:
  - https
  - http

```

To construct the base URL for requests, the API user should select a scheme, then concatenate the strings to form the URL: `schemes[n] + host + basepath`.

![Screenshot of Swagger 2.0 editor showing the scheme selector as the only URL-related option](/assets/blog/openapi-servers/scheme.png)

The screenshot above illustrates the scheme selector in the Swagger 2.0 editor. The scheme selector is the only option for building a base URL in Swagger 2.0.

## Servers in OAS 3.x - Controlled Flexibility

In response to the need for more flexibility, OAS 3.0 introduces the optional `servers` schema. The `servers` schema allows API users to select a base URL from an array of servers, some of which can include variables - allowing for the construction of more complex base URLs.

Each server in the `servers` array consists of an object with at least one field, `url`. Each server object can also contain an optional `description` field, as well as an optional array of `variables`.

Let's look at three different server objects to illustrate the available options, and how they influence the Swagger UI server selector.

```yaml
openapi: 3.1.0
servers:
- url: https://speakeasy.bar
```

The first server object is the simplest. It contains only a `url` field, which is a string containing the base URL for the API: `https://speakeasy.bar`.

```yaml
servers:
- description: The staging server.
  url: https://staging.speakeasy.bar
```

The second server object contains a `url` field and a `description` field. The `description` field is a string that can be used to describe the server. This is useful for providing additional information about the server, such as its location or purpose. In our example, the `description` field is used to describe the server as the staging server.

```yaml
openapi: 3.1.0
servers:
- description: A per-organization and per-environment API.
  url: https://{organization}.{environment}.speakeasy.bar
  variables:
    environment:
      default: prod
      description: The environment name. Defaults to the production environment.
      enum:
      - prod
      - staging
      - dev
    organization:
      default: api
      description: The organization name. Defaults to a generic organization.
```

The third server object contains a `url` field, a `description` field, and a `variables` field. The `variables` field is an array of objects that define variables that can be used to construct the base URL.

In this example, the URL is a template string that contains two variables: `organization` and `environment`. Each variable's name is defined by the object's key. The `default` field is a string that defines the default value for the variable.

The `enum` field is an array of strings that define the possible values for the variable.

The `description` field is a string that can be used to describe the variable. This is useful for providing additional information about the variable, such as its purpose.

This field is not used by the OpenAPI documentation generator, but it can be used by other tools to provide additional information to API users.

## Steps to Adapt Swagger 2.0 URL Definitions to OpenAPI 3.x

1. Identify Swagger 2.0 URL Components: Extract the `host`, `basePath`, and `schemes` values from your Swagger 2.0 document.

2. Create the servers array: Initiate a `servers` array in your OpenAPI 3.x document.

3. Translate URL Components: For each scheme in your Swagger 2.0 document, create a `server` object in the OpenAPI 3.x `servers` array. Combine the `scheme`, `host`, and `basePath` to form the `url` field of each server object.

For example, if your Swagger 2.0 document contains the following URL components:

```yaml filename="swagger-2.0.yaml"
swagger: "2.0"
host: api.example.com
basePath: /v1
schemes:
  - https
  - http
```

You would create the following `servers` array in your OpenAPI 3.x document:

```yaml filename="openapi.yaml"
openapi: 3.1.0
servers:
  - url: https://api.example.com/v1
  - url: http://api.example.com/v1
```

## Best Practices for Defining Servers in OpenAPI

When defining servers in an OpenAPI document, it's crucial to strike a balance between flexibility and clarity. The goal is to provide enough information for users to understand and use the API effectively while allowing for various deployment scenarios.

Here are some best practices to keep in mind:

1. **Provide clear and concise descriptions:** When using the `description` field, ensure it clearly indicates the purpose or specific use case of each server. This is particularly helpful in multiserver setups where different servers serve different roles, such as development, staging, and production.

2. **Use variables judiciously:** Variables offer great flexibility but can also introduce complexity. Use them sparingly and only when necessary, such as when users have unique base URLs or need to select a specific environment.

3. **Document server variables thoroughly:** If you use variables in your server URLs, provide clear documentation on what each variable represents and the valid values (`enum`) it can take. This documentation is crucial for users who need to understand how to construct the URLs correctly.

4. **Consider including common environment URLs:** While variables offer flexibility, sometimes it's easier for users if you explicitly list common environments (like `production`, `staging`, `development`) as separate server entries. This approach reduces the need for users to understand and manipulate variables.

5. **Validate server URLs regularly:** Use automated tools to validate that the URLs in the `servers` section are up to date and operational. This check is particularly important for APIs that undergo frequent changes or have multiple deployment environments.

6. **Stay consistent across documents:** If you manage multiple OpenAPI documents, maintain consistency in how servers are defined across them. This consistency helps users who work with multiple APIs in your suite, making it easier to understand and switch between them.

By following these best practices, you can ensure that your OpenAPI server definitions are both functional and user-friendly, enhancing the overall usability and accessibility of your API.

## Advanced Server Definitions: Using Variables

Server variables offer significant flexibility and adaptability when defining servers. This approach is especially useful in scenarios where the base URL of an API might change based on different environments (like production, staging, or development) or other factors (like user-specific or regional settings). Here's how to leverage variables effectively in your OpenAPI server definitions.

### Understanding Variables in Server URLs

1. **Defining variables:** Variables in OpenAPI are defined within the `servers` array. Each server object can have a `variables` field, which is an object itself. This object contains keys representing variable names, each with its set of properties.

2. **Properties of variables:** The properties of a variable can include:

   - `default`: A mandatory field that specifies the default value of the variable.
   - `enum`: An optional array of possible values the variable can take.
   - `description`: An optional field to describe the variable's purpose or usage.

3. **Using variables in URLs:** Variables are used within the `url` field of a server object, enclosed in curly braces `{}`. For example, `https://{environment}.api.example.com`.

### Best Practices for Using Variables

1. **Name variables clearly:** Choose clear and descriptive names for your variables. Names like `environment`, `region`, or `version` can be more intuitive for users to understand and use.

2. **Use sensible defaults:** Always provide sensible default values that point to the most common or recommended server configuration. This approach ensures that the API can be used out of the box without requiring users to modify the server URL.

3. **Restrict values with enums:** When appropriate, use `enum` to restrict the values that a variable can take. This is particularly useful for environment variables where only specific values like `production`, `staging`, and `development` are valid.

4. **Descriptive documentation:** Each variable should be accompanied by a description that explains its purpose and how it should be used. This is crucial for users who are unfamiliar with your API or its configuration options.

5. **Test variable-driven URLs:** Ensure that all combinations of variables and their values lead to valid and accessible API endpoints. This testing is critical to avoid configuration errors that could make the API unusable.

### Example of a Variable-Driven Server Definition

```yaml filename="openapi.yaml"
openapi: 3.1.0
servers:
  - url: https://{environment}.api.example.com/v1
    description: API server - selectable environment
    variables:
      environment:
        default: production
        enum:
          - production
          - staging
          - development
        description: Deployment environment of the API
```

In this example, the `environment` variable allows users to switch between different deployment environments without the need for separate server entries for each one.

Use variables in server definitions to enhance the flexibility and scalability of your API configurations, catering to a wide range of deployment scenarios and user needs.

## Servers at the Path or Operation Level

While it's common to define servers at the global level in OpenAPI documents, there are cases where specifying servers at the path or operation level is essential. This approach allows for more granular control, enabling different parts of the API to interact with different servers. It's particularly useful in microservices architectures, where different services may reside on different servers, or when specific operations require a unique endpoint.

### Overriding Servers at Path or Operation Level

1. **Path-level servers:** You can specify servers for individual paths. This is useful when different paths in your API are hosted on different servers. For instance, if your API handles file uploads and general data requests separately, you might have different servers handling each.

2. **Operation-level servers:** Similarly, servers can be specified for individual operations (GET, POST, PUT, DELETE, etc.). This granularity is beneficial when a specific operation, like a data submission (POST request), needs to be directed to a distinct server, like a secure data processing server.

### Best Practices

- **Clear documentation:** Clearly document why certain paths or operations use different servers. This clarity helps developers understand the API's architecture and its interaction with various servers.
- **Consistency in structure:** If you have different servers for different paths or operations, maintain a consistent structure in how these are defined to avoid confusion.

- **Fallback to global servers:** Ensure that there is always a fallback server defined at the global level. This fallback acts as a default in cases where a path or operation doesn't explicitly specify a server.

### Example of a Server Definition at the Path Level

Consider an API where file uploads are handled by a dedicated server. Here's how you might define this at the path level:

```yaml
paths:
  /upload:
    servers:
      - url: https://upload.api.example.com
        description: Dedicated server for file uploads
    post:
      summary: Upload a file
      # ... other operation details ...
```

In this example, any POST requests to the `/upload` path would be directed to the specified upload server, differentiating it from other operations in the API that use the default global server.

By strategically using servers at the path or operation levels, you can effectively manage different aspects of your API's functionality, ensuring that each part interacts with the most appropriate server.

## Case Studies: Effective Server Definitions in OpenAPI

We'll now look at a few examples of how different companies have used OpenAPI server definitions to enhance their APIs' usability and functionality.

### Stripe: Path-Level Servers for File Uploads

Stripe's OpenAPI documentation offers an excellent example of using path-level servers. In the Stripe API, the endpoint for file uploads is directed to the `https://files.stripe.com/` server, optimized for handling large data transfers. This separation ensures that the file upload process does not interfere with the regular API traffic and provides a more efficient way to handle resource-intensive operations.

The following excerpt from [Stripe's OpenAPI document](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.yaml) illustrates this setup:

```yaml filename="stripe.yaml"
openapi: 3.0.0
paths:
  /v1/files:
    post:
      operationId: PostFiles
      servers:
        - url: "https://files.stripe.com"
      # ... other operation details ...
servers:
  - url: "https://api.stripe.com"
```

This setup demonstrates a clear understanding of operational requirements and a commitment to providing a seamless user experience.

Stripe's OpenAPI document could be further enhanced by providing a fallback global server in case the file server is unavailable and documenting the reason for using a separate server for file uploads.

### Datadog: Dynamic Server Selection with Variables

Datadog's API, known for its scalability and flexibility, leverages variables in server definitions to allow users to select their preferred region. This feature is particularly useful for global services where latency and data residency are critical considerations.

The following setup allows users to dynamically choose the region closest to them, enhancing the performance and reliability of the AP:.

```yaml filename="datadog.yaml"
openapi: 3.0.0
servers:
  - url: https://{subdomain}.{site}
    variables:
      site:
        default: datadoghq.com
        description: The regional site for Datadog customers.
        enum:
          - datadoghq.com
          - us3.datadoghq.com
          - us5.datadoghq.com
          - ap1.datadoghq.com
          - datadoghq.eu
          - ddog-gov.com
      subdomain:
        default: api
        description: The subdomain where the API is deployed.
  - url: "{protocol}://{name}"
    variables:
      name:
        default: api.datadoghq.com
        description: Full site DNS name.
      protocol:
        default: https
        description: The protocol for accessing the API.
  - url: https://{subdomain}.{site}
    variables:
      site:
        default: datadoghq.com
        description: Any Datadog deployment.
      subdomain:
        default: api
        description: The subdomain where the API is deployed.
...
```

## Conclusion: The Impact of Well-Defined Servers in API Usability

The way servers are defined in OpenAPI documents can significantly impact the usability and effectiveness of an API. Well-defined servers provide clear, accessible endpoints for different operational needs, improve the developer experience, and foster trust in the API's reliability and efficiency. Key benefits include:

- **Enhanced clarity:** Clear server definitions help developers understand where and how to interact with the API.
- **Operational flexibility:** Using variables and specifying servers at different levels (global, path, and operation) allows for greater operational flexibility and efficiency.
- **Improved performance:** Strategic server allocation, such as dedicated endpoints for resource-intensive tasks, optimizes API performance.
- **Global scalability:** Variables that allow for regional server selection make the API more adaptable to global users, addressing concerns like latency and data residency.

## Additional Resources and Tools for OpenAPI Server Definition

If you're interested in deepening your understanding of OpenAPI server definitions, we recommend the following resources and tools:

1. **OpenAPI Specification:** The official [OpenAPI Specification](https://spec.openapis.org/oas/v3.1.0#server-object) documentation provides comprehensive guidance on server definitions and other aspects of OpenAPI.
2. **Swagger Editor:** An online tool that helps visualize and [edit OpenAPI documents](https://editor-next.swagger.io/), making it easier to define and review server configurations.
3. **The OpenAPI Specification Explained: API Servers:** A detailed [guide to the OpenAPI Servers](https://learn.openapis.org/specification/servers.html) that explains the different aspects of server definitions and how to use them effectively.
4. **Speakeasy documentation:** Our documentation on how to [configure your servers](/docs/customize-sdks/servers) in OpenAPI while creating SDKs with Speakeasy.