# Generated OpenAPI spec for Lap Times endpoint
"/api/v1/lap_times":
  get:
    summary: List all lap times
    tags:
      - Lap Times
    parameters:
      - name: driver_id
        in: query
        required: false
        description: Filter by driver ID
        schema:
          type: integer
      - name: circuit_id
        in: query
        required: false
        description: Filter by circuit ID
        schema:
          type: integer
      - name: lap_min
        in: query
        required: false
        description: Minimum lap number
        schema:
          type: integer
      - name: lap_max
        in: query
        required: false
        description: Maximum lap number
        schema:
          type: integer
    responses:
      "200":
        description: lap times found
        content:
          application/json:
            schema:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: integer
                  driver_id:
                    type: integer
                  circuit_id:
                    type: integer
                  time_ms:
                    type: integer
                  lap_number:
                    type: integer
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
                required:
                  - id
                  - driver_id
                  - circuit_id
                  - time_ms
                  - lap_number
  post:
    summary: Create a lap time
    tags:
      - Lap Times
    parameters: []
    responses:
      "201":
        description: lap time created
      "422":
        description: invalid request
    requestBody:
      content:
        application/json:
          schema:
            type: object
            properties:
              driver_id:
                type: integer
              circuit_id:
                type: integer
              time_ms:
                type: integer
              lap_number:
                type: integer
            required:
              - driver_id
              - circuit_id
              - time_ms
              - lap_number
```

Rswag automatically documents:

- The HTTP methods (`GET` and `POST`)
- Query parameters for filtering
- A request body schema for creating new records
- Response codes and schemas
- The required fields

All of this is generated from Rswag spec files and matches the actual implementation of the API.

## Customizing the OpenAPI document

While the basic Rswag setup provides a solid foundation, OpenAPI documents can be customized and enhanced with additional details to make them more useful to API consumers.

### Documenting authentication

If the API requires authentication, configure security schemes in `spec/swagger_helper.rb` and add security requirements to specs:

```ruby filename="swagger_helper.rb"
components: {
  securitySchemes: {
    bearer_auth: {
      type: :http,
      scheme: :bearer,
      bearerFormat: 'JWT'
    }
  }
}
```

And then in the specs:

```ruby filename="lap_times_spec.rb"
path '/api/v1/protected_resource' do
  get 'Access protected resource' do
    tags 'Protected'
    security [bearer_auth: []]

    # Other documentation
  end
end
```

This tells API consumers that they need to include a bearer token in their requests to access the protected endpoints.

### Documenting file uploads

For endpoints that handle file uploads, use the `multipart/form-data` content type and specify file parameters:

```ruby filename="lap_times_spec.rb"
post 'Upload file' do
  consumes 'multipart/form-data'

  parameter name: :file, in: :formData, type: :file, required: true

  response '200', 'file uploaded' do
    # Test implementation
  end
end
```

### Creating reusable schemas

To keep specs DRY [(Don't Repeat Yourself)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), define reusable schema components in `spec/swagger_helper.rb`:

```ruby filename="swagger_helper.rb"
components: {
  schemas: {
    lap_time: {
      type: :object,
      properties: {
        driver_id: { type: :integer },
        circuit_id: { type: :integer },
        time_ms: { type: :integer },
        lap_number: { type: :integer }
      },
      required: ['driver_id', 'circuit_id', 'time_ms', 'lap_number']
    }
  }
}
```

And then in the specs:

```ruby filename="lap_times_spec.rb"
parameter name: :lap_time, in: :body, schema: { '$ref' => '#/components/schemas/lap_time' }
```

This allows common models to be defined once and referenced throughout the documentation.

## Troubleshooting common issues

Common issues encountered when using Rswag and how to troubleshoot them are outlined below.

### Missing documentation

If endpoints do not appear in the OpenAPI UI:

- Ensure specs include the proper Rswag DSL syntax.
- Verify that spec files are in the correct location.
- Check that controller routes match the paths in the specs.

Ideally, the CLI provides a helpful error message if something is missing.

### Test failures

If Rswag specs fail, the implementation may not match the documentation. To fix this, check the generated OpenAPI document to identify missing elements, then update specs to match the implementation.

Make sure to check the required parameters in both specs and controllers.

### Generation issues

If the OpenAPI document has not been generated correctly, ensure the command is run in the test environment (`RAILS_ENV=test`) and that file permissions are correct in the destination directory.

## Generating SDKs with Speakeasy

Once an OpenAPI document has been created with Rswag, Speakeasy can be used to generate client SDKs for the API. This makes it easier for developers to interact with the API in their preferred programming language.

First, install the Speakeasy CLI:

```bash
curl -fsSL https://go.speakeasy.com/cli-install.sh | sh
```

Next, follow the instructions on the [Getting Started](https://www.speakeasy.com/docs/speakeasy-reference/cli/getting-started) page to set up and authenticate with Speakeasy.

To generate a client SDK, run the following command from the root of the project:

```bash
speakeasy quickstart
```

Follow the prompts to provide the OpenAPI document location (`openapi/v1/openapi.yaml`) and configure SDK options.

Speakeasy then generates a complete SDK based on the API specification, making it easier for developers to integrate with the API.

## Summary

This guide explored how Rswag can be used to generate OpenAPI documents for a Rails API. It covered documenting API endpoints using Rswag's RSpec-based DSL, generating an OpenAPI document with Rswag, customizing the OpenAPI document, and using it to generate client SDKs with Speakeasy.