Operations

Define HTTP operations with methods, options, and composable configurations

Learn how to define HTTP operations using method constructors and operation options.

HTTP Method Constructors

The package provides HTTP method constructors for defining operations:

openapi.GET("/users/:id", opts...)
openapi.POST("/users", opts...)
openapi.PUT("/users/:id", opts...)
openapi.PATCH("/users/:id", opts...)
openapi.DELETE("/users/:id", opts...)
openapi.HEAD("/users/:id", opts...)
openapi.OPTIONS("/users", opts...)
openapi.TRACE("/debug", opts...)

Each constructor takes a path and optional operation options.

Operation Options

All operation options follow the With* naming convention:

FunctionDescription
WithSummary(s)Set operation summary
WithDescription(s)Set operation description
WithOperationID(id)Set custom operation ID
WithRequest(type, examples...)Set request body type
WithResponse(status, type, examples...)Set response type for status code
WithTags(tags...)Add tags to operation
WithSecurity(scheme, scopes...)Add security requirement
WithDeprecated()Mark operation as deprecated
WithConsumes(types...)Set accepted content types
WithProduces(types...)Set returned content types
WithOperationExtension(key, value)Add operation extension

Basic Operation Definition

Define a simple GET operation:

result, err := api.Generate(context.Background(),
    openapi.GET("/users/:id",
        openapi.WithSummary("Get user by ID"),
        openapi.WithDescription("Retrieves a user by their unique identifier"),
        openapi.WithResponse(200, User{}),
    ),
)

Request Bodies

Use WithRequest() to specify the request body type:

type CreateUserRequest struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

openapi.POST("/users",
    openapi.WithSummary("Create user"),
    openapi.WithRequest(CreateUserRequest{}),
    openapi.WithResponse(201, User{}),
)

Request with Examples

Provide example request bodies:

exampleUser := CreateUserRequest{
    Name:  "John Doe",
    Email: "john@example.com",
}

openapi.POST("/users",
    openapi.WithSummary("Create user"),
    openapi.WithRequest(CreateUserRequest{}, exampleUser),
    openapi.WithResponse(201, User{}),
)

Response Types

Define multiple response types for different status codes:

type ErrorResponse struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
}

openapi.GET("/users/:id",
    openapi.WithSummary("Get user"),
    openapi.WithResponse(200, User{}),
    openapi.WithResponse(404, ErrorResponse{}),
    openapi.WithResponse(500, ErrorResponse{}),
)

Response with Examples

Provide example responses:

exampleUser := User{
    ID:    123,
    Name:  "John Doe",
    Email: "john@example.com",
}

openapi.GET("/users/:id",
    openapi.WithSummary("Get user"),
    openapi.WithResponse(200, User{}, exampleUser),
)

Tags

Organize operations with tags:

result, err := api.Generate(context.Background(),
    openapi.GET("/users",
        openapi.WithSummary("List users"),
        openapi.WithTags("users"),
        openapi.WithResponse(200, []User{}),
    ),
    openapi.GET("/posts",
        openapi.WithSummary("List posts"),
        openapi.WithTags("posts"),
        openapi.WithResponse(200, []Post{}),
    ),
)

Multiple tags per operation:

openapi.GET("/users/:id/posts",
    openapi.WithSummary("Get user's posts"),
    openapi.WithTags("users", "posts"),
    openapi.WithResponse(200, []Post{}),
)

Security Requirements

Apply security to operations:

// Single security scheme
openapi.GET("/users/:id",
    openapi.WithSummary("Get user"),
    openapi.WithSecurity("bearerAuth"),
    openapi.WithResponse(200, User{}),
)

// OAuth2 with scopes
openapi.POST("/users",
    openapi.WithSummary("Create user"),
    openapi.WithSecurity("oauth2", "read", "write"),
    openapi.WithRequest(CreateUserRequest{}),
    openapi.WithResponse(201, User{}),
)

// Multiple security schemes (OR)
openapi.DELETE("/users/:id",
    openapi.WithSummary("Delete user"),
    openapi.WithSecurity("bearerAuth"),
    openapi.WithSecurity("apiKey"),
    openapi.WithResponse(204, nil),
)

Deprecated Operations

Mark operations as deprecated:

openapi.GET("/users/legacy",
    openapi.WithSummary("Legacy user list"),
    openapi.WithDescription("This endpoint is deprecated. Use /users instead."),
    openapi.WithDeprecated(),
    openapi.WithResponse(200, []User{}),
)

Content Types

Specify content types for requests and responses:

openapi.POST("/users",
    openapi.WithSummary("Create user"),
    openapi.WithRequest(CreateUserRequest{}),
    openapi.WithConsumes("application/json", "application/xml"),
    openapi.WithProduces("application/json", "application/xml"),
    openapi.WithResponse(201, User{}),
)

Operation Extensions

Add custom x-* extensions to operations:

openapi.GET("/users",
    openapi.WithSummary("List users"),
    openapi.WithOperationExtension("x-rate-limit", 100),
    openapi.WithOperationExtension("x-internal-only", false),
    openapi.WithResponse(200, []User{}),
)

Complete Operation Example

Here’s a complete example with all options:

openapi.PUT("/users/:id",
    openapi.WithSummary("Update user"),
    openapi.WithDescription("Updates an existing user's information"),
    openapi.WithOperationID("updateUser"),
    openapi.WithRequest(UpdateUserRequest{}),
    openapi.WithResponse(200, User{}),
    openapi.WithResponse(400, ErrorResponse{}),
    openapi.WithResponse(404, ErrorResponse{}),
    openapi.WithResponse(500, ErrorResponse{}),
    openapi.WithTags("users"),
    openapi.WithSecurity("bearerAuth"),
    openapi.WithConsumes("application/json"),
    openapi.WithProduces("application/json"),
    openapi.WithOperationExtension("x-rate-limit", 50),
)

Composable Operation Options

Use WithOptions() to create reusable option sets:

// Define reusable option sets
var (
    CommonErrors = openapi.WithOptions(
        openapi.WithResponse(400, ErrorResponse{}),
        openapi.WithResponse(401, ErrorResponse{}),
        openapi.WithResponse(500, ErrorResponse{}),
    )
    
    UserEndpoint = openapi.WithOptions(
        openapi.WithTags("users"),
        openapi.WithSecurity("bearerAuth"),
        CommonErrors,
    )
    
    JSONContent = openapi.WithOptions(
        openapi.WithConsumes("application/json"),
        openapi.WithProduces("application/json"),
    )
)

// Apply to operations
result, err := api.Generate(context.Background(),
    openapi.GET("/users/:id",
        UserEndpoint,
        JSONContent,
        openapi.WithSummary("Get user"),
        openapi.WithResponse(200, User{}),
    ),
    
    openapi.POST("/users",
        UserEndpoint,
        JSONContent,
        openapi.WithSummary("Create user"),
        openapi.WithRequest(CreateUserRequest{}),
        openapi.WithResponse(201, User{}),
    ),
    
    openapi.PUT("/users/:id",
        UserEndpoint,
        JSONContent,
        openapi.WithSummary("Update user"),
        openapi.WithRequest(UpdateUserRequest{}),
        openapi.WithResponse(200, User{}),
    ),
)

Nested Composable Options

Option sets can be nested:

var (
    ErrorResponses = openapi.WithOptions(
        openapi.WithResponse(400, ErrorResponse{}),
        openapi.WithResponse(500, ErrorResponse{}),
    )
    
    AuthRequired = openapi.WithOptions(
        openapi.WithSecurity("bearerAuth"),
        openapi.WithResponse(401, ErrorResponse{}),
        ErrorResponses,
    )
    
    UserAPI = openapi.WithOptions(
        openapi.WithTags("users"),
        AuthRequired,
    )
)

Custom Operation IDs

By default, operation IDs are auto-generated from the HTTP method and path. Override with WithOperationID():

openapi.GET("/users/:id",
    openapi.WithOperationID("getUserById"),
    openapi.WithSummary("Get user"),
    openapi.WithResponse(200, User{}),
)

Without WithOperationID(), the operation ID would be auto-generated as getUsers_id.

Next Steps