openapi-go

repository·master·Indexed 43 days ago

https://github.com/swaggest/openapi-go

A Go library providing structures to marshal, unmarshal, and reflect OpenAPI Schema documents. It enables type-safe mapping between Go code and OpenAPI 3.0/3.1 specifications, allowing developers to generate schemas from Go structures using struct tags for request bodies, query parameters, path parameters, and headers via the openapi3.Reflector.

Tokens
3.9K
Snippets
12
Records
15
Agent score
56%

What's inside openapi-go

  1. Use openapi-go to reflect Go structures to OpenAPI schemas

    master

    The openapi-go library allows you to generate OpenAPI 3.0 or 3.1 schemas by reflecting on Go structures. It uses struct tags to control how fields are mapped to OpenAPI components like request bodies, query parameters, path parameters, and headers. This enables type-safe mapping and automated documentation generation.

    reflector := openapi3.Reflector{}
    reflector.Spec = &openapi3.Spec{Openapi: "3.0.3"}
    // ... configure Spec and add operations ...
    schema, err := reflector.Spec.MarshalYAML()
  2. Generate an OpenAPI specification using openapi3.Reflector

    master

    To generate a full OpenAPI specification, follow these steps:

    1. Initialize an openapi3.Reflector.
    2. Configure the Spec (e.g., set Openapi version, Info.Title, Info.Version).
    3. Create operations using reflector.NewOperationContext(method, path).
    4. Attach request and response structures to the operation using AddReqStructure and AddRespStructure.
    5. Register the operation with reflector.AddOperation(op).
    6. Marshal the resulting spec to YAML or JSON.
    reflector := openapi3.Reflector{}
    reflector.Spec = &openapi3.Spec{Openapi: "3.0.3"}
    reflector.Spec.Info.WithTitle("API").WithVersion("1.0.0")
    
    // Define an operation
    op, _ := reflector.NewOperationContext(http.MethodGet, "/items/{id}")
    type Req struct {
        ID string `path:"id" example:"123"` 
    }
    type Resp struct {
        Name string `json:"name"` 
    }
    
    op.AddReqStructure(new(Req))
    op.AddRespStructure(new(Resp), func(cu *openapi.ContentUnit) { cu.HTTPStatus = http.StatusOK })
    
    reflector.AddOperation(op)
    
    schema, _ := reflector.Spec.MarshalYAML()
    fmt.Println(string(schema))
  3. Control OpenAPI schema generation with struct tags

    master

    You can control how Go struct fields are represented in the OpenAPI schema using specific tags. Supported tags include:

    • json: For request bodies and responses in JSON format.
    • query: For URL query parameters.
    • path: For URL path parameters.
    • header: For HTTP headers.
    • cookie: For cookie parameters.
    • formData: For form data parameters.
    • file: For file upload parameters.
    • form: Acts as both query and formData.
    • contentType: Indicates the content type of the body.
    • collectionFormat: Defines how slices are unpacked from strings (e.g., csv, ssv, pipes, multi, json).
    • JSON Schema constraints: You can use field tags named after JSON Schema/OpenAPI 3 Schema constraints (e.g., pattern, example, minimum, maximum).
  4. Sanitize HTTP methods and path patterns

    master

    The SanitizeMethodPath function validates an HTTP method and cleans up path patterns. It is particularly useful for converting router-style paths (like those in gorilla/mux) into standard OpenAPI path templates.

    It performs the following:

    1. Converts the method to lowercase.
    2. Validates the method against standard HTTP verbs (get, put, post, delete, options, head, patch, trace).
    3. Extracts path parameters (e.g., {id}) and removes regex-style constraints (e.g., {id:[0-9]+} becomes {id}).

    Returns:

    • cleanMethod: The lowercase HTTP method.
    • cleanPath: The sanitized path pattern.
    • pathParams: A slice of the extracted parameter names.
    • err: An error if the method is invalid.
    method := "GET"
    path := "/users/{id:[0-9]+}"
    
    cleanMethod, cleanPath, pathParams, err := openapi.SanitizeMethodPath(method, path)
    // cleanMethod: "get"
    // cleanPath: "/users/{id}"
    // pathParams: []string{"id"}
  5. Use OperationContext to manage OpenAPI operations

    master

    The OperationContext interface is the central hub for defining and managing an OpenAPI operation. It combines information about the operation (tags, summary, description), the request/response structures, and the current processing state.

    Key Capabilities:

    • Metadata: Set tags, summary, description, and operation ID via OperationInfo methods.
    • Structure Definition: Use AddReqStructure(i interface{}, options ...ContentOption) to define request bodies and AddRespStructure(o interface{}, options ...ContentOption) for responses.
    • Security: Use AddSecurity(securityName string, scopes ...string) to define security requirements.
    • State Tracking: Use OperationState methods to track if the system is currently processing a request or a response, and which part of the HTTP message (In) is being processed.
    // Conceptual usage of OperationContext
    func DefineOperation(ctx openapi.OperationContext) {
        ctx.SetSummary("Get User")
        ctx.SetTags("Users")
        
        // Define a request body
        ctx.AddReqStructure(UserRequest{}, openapi.WithContentType("application/json"))
        
        // Define a successful response
        ctx.AddRespStructure(UserResponse{}, openapi.WithHTTPStatus(200))
    }
  6. Define HTTP content with ContentUnit

    master

    The ContentUnit struct is used to define HTTP content (request bodies, responses, headers, etc.) within an OpenAPI operation. It allows you to specify the data structure, content type, format, and associated HTTP status.

    Key fields:

    • Structure: The Go interface/struct representing the data.
    • ContentType: The MIME type (e.g., application/json).
    • HTTPStatus: The status code (e.g., 200) or status family (e.g., 2 for 2XX).
    • IsDefault: Indicates if this is the default response.
    • Customize: A callback to perform fine-grained control over the underlying OpenAPI object (e.g., setting references).

    You can configure ContentUnit using ContentOption functions.

    cu := &openapi.ContentUnit{
        Structure:   MyStruct{},
        ContentType: "application/json",
        HTTPStatus:  200,
    }
  7. Use the SpecSchema interface to define OpenAPI specifications

    master

    The SpecSchema interface is the primary abstraction for defining OpenAPI specifications in this library. It is designed to generalize across different OpenAPI revisions. It provides methods to manage basic metadata (Title, Description, Version) and to configure various security schemes.

    To use it, you interact with the following methods:

    Metadata Management

    • Title() string: Retrieves the specification title.
    • SetTitle(t string): Sets the specification title.
    • Description() string: Retrieves the specification description.
    • SetDescription(d string): Sets the specification description.
    • Version() string: Retrieves the specification version.
    • SetVersion(v string): Sets the specification version.

    Security Configuration

    • SetHTTPBasicSecurity(securityName string, description string): Configures HTTP Basic authentication.
    • SetAPIKeySecurity(securityName string, fieldName string, fieldIn In, description string): Configures API Key authentication. Requires a fieldName and a fieldIn (of type In).
    • SetHTTPBearerTokenSecurity(securityName string, format string, description string): Configures HTTP Bearer Token authentication.
    // Example usage of SpecSchema methods
    func configureSpec(spec SpecSchema) {
    	spec.SetTitle("My API")
    	spec.SetDescription("An example API specification")
    	spec.SetVersion("1.0.0")
    
    	// Configure security
    	spec.SetHTTPBearerTokenSecurity("bearerAuth", "JWT", "Use a JWT token")
    }
  8. Map field names to parameter names with SetFieldMapping

    master

    If your Go struct field names differ from the expected OpenAPI parameter names, you can use SetFieldMapping on a ContentUnit. This allows you to map specific field names to parameter names for a given location (In).

    Supported In values:

    • InPath (path)
    • InQuery (query)
    • InHeader (header)
    • InCookie (cookie)
    • InFormData (formData)
    • InBody (body)
    cu := &openapi.ContentUnit{}
    // Map the Go field 'UserID' to the OpenAPI parameter 'id'
    cu.SetFieldMapping(openapi.InPath, map[string]string{
        "UserID": "id",
    })
  9. Walk JSON schemas using JSONSchemaWalker

    master

    The JSONSchemaWalker interface allows you to traverse the JSON schemas extracted from a ContentUnit (which represents the body/content of an OpenAPI request or response). This is useful for custom validation or schema inspection.

    Methods:

    • WalkRequestJSONSchemas(method string, cu ContentUnit, cb JSONSchemaCallback, done func(oc OperationContext)) error: Iterates through schemas associated with a specific HTTP method in a request content unit.
    • WalkResponseJSONSchemas(cu ContentUnit, cb JSONSchemaCallback, done func(oc OperationContext)) error: Iterates through schemas associated with a response content unit.
    • ResolveJSONSchemaRef(ref string) (s jsonschema.SchemaOrBool, found bool): Resolves a specific JSON schema reference string to its schema object.
    // Example of walking schemas with a callback
    err := walker.WalkRequestJSONSchemas("POST", contentUnit, func(in openapi.In, paramName string, schema *jsonschema.SchemaOrBool, required bool) error {
        // Perform custom logic on each schema found
        fmt.Printf("Found parameter: %s, required: %v\n", paramName, required)
        return nil
    }, func(oc openapi.OperationContext) {
        // Finalize operation
    })
  10. Use the Reflector interface to convert Go structures to OpenAPI schemas

    master

    The Reflector interface is the primary entry point for converting Go structures into OpenAPI/JSON schemas. It extends JSONSchemaWalker, allowing you to not only extract schemas but also walk through request and response schemas for validation or inspection.

    Key capabilities include:

    • SpecSchema(): Returns the schema for the OpenAPI specification itself.
    • JSONSchemaReflector(): Provides access to the underlying *jsonschema.Reflector for direct JSON Schema operations.
    • AddOperation(oc OperationContext): Registers an operation context (method and path) to the reflector.
    // Example of how a Reflector might be used (conceptual based on interface)
    var reflector openapi.Reflector
    
    // Register an operation
    oc, _ := openapi.NewOperationContext("GET", "/users/{id}")
    err := reflector.AddOperation(oc)
    
    // Access the underlying JSON Schema reflector
    jsReflector := reflector.JSONSchemaReflector()
  11. Configure ContentUnit using options

    master

    Use ContentOption functions to configure a ContentUnit during setup. Common options include:

    • WithReference(ref string): Sets the content entity as a reference to a specific schema path.
    • WithCustomize(func(cor ContentOrReference)): Provides a hook to manually manipulate the generated OpenAPI object.
    • WithContentType(contentType string): Sets the MIME type.
    • WithHTTPStatus(httpStatus int): Sets the HTTP status code.
    // Example using options
    options := []openapi.ContentOption{
        openapi.WithReference("#/components/schemas/MySchema"),
        openapi.WithContentType("application/json"),
    }
    
    // Note: In practice, these are passed to methods that accept ContentOption
  12. Reference the In enumeration

    master

    The In type defines where a parameter or content is located in an HTTP request. Use these constants to ensure type safety:

    const (
        openapi.InPath     = In("path")     // Path parameters
        openapi.InQuery    = In("query")    // Query string parameters
        openapi.InHeader   = In("header")   // HTTP Headers
        openapi.InCookie   = In("cookie")   // Cookies
        openapi.InFormData = In("formData") // Form data
        openapi.InBody     = In("body")     // Request body
    )