# ...
components:
  requestBodies:
    UserCredentials:
      required: true
      content:
        application/json:
          schema:
            type: object
            properties:
              username:
                type: string
              password:
                type: string
```

### Referencing Error Types in OpenAPI

All operations in the Bar schema already use references for error types:

```yaml filename="openapi.yaml"
      responses:
        "200":
          description: The api key to use for authenticated endpoints.
          content:
            application/json:
              schema:
                type: object
                properties:
                  token:
                    type: string
        "401":
          description: Invalid credentials provided.
        "5XX":
          $ref: "#/components/responses/APIError"
        default:
          $ref: "#/components/responses/UnknownError"
...
components:
  responses:
    APIError:
      description: An error occurred interacting with the API.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/APIError"
    UnknownError:
      description: An unknown error occurred interacting with the API.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
```

### Referencing Security Schemes in OpenAPI

Security schemes automatically reference `components` and do not need `$ref`:

```yaml filename="openapi.yaml"
paths
  /drinks:
    post:
      operationId: createDrink
      summary: Create a drink.
      description: Create a drink. Only available when authenticated.
      security:
        - apiKey: []
...
components:
  securitySchemes:
    apiKey:
      type: apiKey
      name: Authorization
      in: header
```

Referencing schemes in a separate file:

```yaml
components:
  securitySchemes:
    $ref: 'securitySchemes.yaml'
```

### Referencing Schema Examples in OpenAPI

In the `responses` section of the `listDrinks` operation, `examples` use `$ref`:

```yaml
      responses:
        "200":
          description: A list of drinks.
          content:
            application/json:
              schema:
                type: array
                items:
                  oneOf:
                    - $ref: "#/components/schemas/Drink"
                    - $ref: "#/components/schemas/PublicDrink"
                  discriminator:
                    propertyName: dataLevel
                    mapping:
                      unauthenticated: "#/components/schemas/PublicDrink"
                      authenticated: "#/components/schemas/Drink"
              examples:
                unauthenticated_drinks:
                  $ref: "#/components/examples/unauthenticated_drinks"
...
components:
  examples:
    unauthenticated_drinks:
      summary: A list of drinks for unauthenticated users
      value:
        [
          {
            "name": "Old Fashioned",
            "type": "cocktail",
            "price": 1000,
            "photo": "https://speakeasy.bar/drinks/old_fashioned.jpg",
            "dataLevel": "unauthenticated",
          },
          ...
        ]
```

The schemes in a separate file can be referenced like this:

```yaml
components:
  examples:
    $ref: 'examples.yaml'
```

### Discriminators in OpenAPI

[Discriminators](/openapi/schemas/objects/polymorphism#discriminator-object-in-openapi) can be used to differentiate between different schemas in a `oneOf` array.

The `mapping` object in a discriminator maps values to schemas. The references in these mappings are similar to the values used in `$ref`.

In the example below, the drinks returned by the `listDrinks` operation can be either `Cocktail` or `Beer`:

```yaml filename="openapi.yaml" mark=14:16
      responses:
        "200":
          description: A list of drinks.
          content:
            application/json:
              schema:
                type: array
                items:
                  oneOf:
                    - $ref: "#/components/schemas/Cocktail"
                    - $ref: "#/components/schemas/Beer"
                  discriminator:
                    propertyName: category
                    mapping:
                      cocktail: "#/components/schemas/Cocktail"
                      beer: "#/components/schemas/Beer"
```

## References Best Practices in OpenAPI

There are no syntactical or functional differences between a schema in one file or split into multiple files using `$ref`. But splitting a large schema into separate files implements the principle of modularity, which holds several advantages for users:

- Readability: Multiple shorter files with appropriate names are easier to navigate and understand than one massive file.
- Reusability: Multiple top-level schemas that are unrelated can reuse lower-level schemas stored in shared external files.
- Collaboration: Programmers can more easily edit smaller files in their area of focus in an API without version control conflicts.

A minor disadvantage of using multiple files is increased administration. Deployments need to carefully validate and distribute multiple files with interdependencies instead of just one file. The separate files may be stored in different locations on a network and have complicated URI resolutions, though this is usually unnecessary.

Given that splitting a schema into several files is beneficial, let's consider how to do it. Here are some principles to consider:

### Use External Files Sparingly

A potential downside of separating your OpenAPI documents into multiple files with references is that online validators can't validate multiple files at once. When using multiple documents, you can validate your OpenAPI schema using local validators. For example:

```sh
npx swagger-cli validate openapi.yaml
```

If both files are present and valid, the validator will return `openapi.yaml is valid`.

### Use Components When Necessary

Don't waste time on premature optimization or modularization. If you're using a type only once, don't bother moving it into components. But as soon as you use a type twice, use two `$ref` keywords in your main schema, and move the type definition down into `components`. Now if you want to split your file into multiple files, your types are already modules.

When should you break your `components` section into multiple files? Either when the file becomes too large to be easily readable, or when you start writing another API that reuses the same components as your original one.

### Design Versioning Carefully

It is important to specify the version number of your schemas so that customers can be certain they are calling the correct API for the code they have written. As well as having a version number in your YAML, you should also number your schema filenames or use Git release numbers:

```txt
├── schema-v1.yaml
├── schema-v2.yaml
```

When you split your schema into multiple files, it's easier to do versioning at the folder level:

```txt
├── api
    ├── v1
    |   ├── openapi.yaml
    |   └── person.yaml
    └── v2
        ├── openapi.yaml
        └── person.yaml
```

Even if only `openapi.yaml` changes when releasing a new version, and `person.yaml` remains the same, it is simpler to copy all files into the new version folder rather than referencing the old `person.yaml` from both `openapi.yaml` files. There is too much risk of making a change in one version of a file that breaks other files depending on it.

If multiple APIs share common components, versioning becomes more complex. Consider the example below.

```txt
├── api
|   ├── v1
|   |   ├── bar-schema.yaml
|   |   └── employee-schema.yaml
|   └── v2
|       ├── bar-schema.yaml
|       └── employee-schema.yaml
|
└── shared
    ├── v1
    |   └── person.yaml
    └── v2
        └── person.yaml
```

Two APIs, Bar and Employee, use the person schema kept in a shared folder. When version 1 of the person schema is updated for the Bar API, you need to either:
- The Employee API must be updated and a new version released. Since there have been no functional changes to the API, there is no benefit to customers updating their code that uses the API. This is a poor solution.
- The file should no longer be shared. Different versions of the `person.yaml` file should be moved into the Bar and Employee folders and deleted from the `shared` folder. This solution discards the modularity and reusability of shared files.
- The Bar API version 2 should point to the person schema version 2, and the Employee API version 1 should point to the person schema version 1.

The final solution makes the most sense, but is dangerous. You'll need to keep track of which versions of the APIs point to which version of the shared schema, and further changes to `person.yaml` version 1 could cause it to diverge from version 2, and you'll need to implement one of the three solutions above again.

Note that `$ref` has no version checking. You need to create your own scripts to validate the versioning system and folder structure your company decides to use.

### How To Structure Your Files

In general, choose filenames that match the file contents, such as `parameters.yaml`, `responses.yaml`, or `securitySchemes.yaml`. Group each type of object into a single file, such as `schemas`, `examples`, and so on.

A simple folder structure might look like this:

```txt
/api
  openapi.yaml
  /components
    schemas.yaml
    responses.yaml
    parameters.yaml
    examples.yaml
    security.yaml
  /paths
    users.yaml
    products.yaml
```

When referencing external files, use clear and relative paths that make it easy to understand where the referenced file is located relative to the current file. Don't chain references more than two levels. Deep nesting is difficult to understand.

Each file should be alphabetically structured to make finding elements easy.