openapigodoc

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 2, 2026 License: MIT Imports: 11 Imported by: 0

README

openapi-godoc

Go Report Card Go Reference Lint and Test

This package generates an OpenAPI document from comments in your code annotated with the @openapi keyword. It currently supports only the openapi 3.x schema and not the older swagger 2 schema.

Goals

openapi-godoc enables you to integrate OpenAPI using comments in your code. Add an @openapi line inside any Go comment and describe the given API part in YAML syntax beneath it. It's also possible to pass JSON snippets directly outside the annotated source code.

openapi-godoc will then parse the comments and output an OpenAPI document describing your API, allowing you to keep your API documentation as close as possible to your code thus maximizing the likelihood it stays up to date when your code changes.

Where @openapi blocks can live

@openapi is matched by line-start, so blocks can appear:

  • on a struct or func declaration, either as the first line of the doc comment or after one or more regular godoc lines (// MyFn does X.\n//\n// @openapi\n// …)

  • in a free-standing comment group not attached to any declaration — useful for documenting routes whose handler lives in another package, or for grouping schema-only definitions. No special anchor is required: the parser scans every comment group in the file, so the block is picked up whether or not it attaches to a following declaration. Just leave a blank line between the block and the next declaration so the YAML doesn't become that declaration's godoc:

    // @openapi
    // paths:
    //   /health:
    //     get: { responses: { '200': { description: ok } } }
    
    // Health reports liveness. The blank line above keeps the @openapi block
    // as its own comment group instead of this function's doc comment.
    func Health() {}
    
  • multiple times in a single comment group — each @openapi line starts a new block, and the body runs until the next @openapi line or the end of the group.

Matching rules and caveats
  • A marker is a comment line whose trimmed text is exactly @openapi. Mid-line occurrences (e.g. // see @openapi for details) are ignored, so prose that mentions the keyword is safe.
  • Every comment group in every .go file under the scanned paths is searched — including _test.go files and comments inside function bodies. Keep stray @openapi lines out of test and example files unless you intend them to land in the generated spec.
  • A block's body runs from the marker line to the next @openapi marker in the same group, or the end of the group. Blank lines inside a body are preserved, so multi-line YAML works.
  • Parsing is fail-fast: a single malformed @openapi block anywhere aborts generation. The error names the offending file:line so you can jump straight to it.

Non-goals

openapi-godoc does not add logic to your specification or generate client code from the OpenAPI document. It is based on code annotations and/or static JSON, not the code logic itself. It works only with what you put around your logic, not the contents of the logic.

Installation

go get github.com/tink3rlabs/openapi-godoc@latest

Usage

Add comments to your strucs and funcs that represent API components. Then define your API by creating an openapigodoc.OpenAPIDefinition object and providing general information about your API and OpenAPI specification components.

package main

import (
 "log"
 "net/http"

 "github.com/go-chi/chi"
 "github.com/go-chi/chi/middleware"
 "github.com/go-chi/cors"
 "github.com/go-chi/render"
 openapigodoc "github.com/tink3rlabs/openapi-godoc"
)

// @openapi
// components:
//
// schemas:
//   Message:
//     type: object
//     properties:
//       content:
//         type: string
//         description: The contents of a message
//         example: Hello world!
type Message struct {
 Content string `json:"content"`
}

// @openapi
// components:
//
// responses:
//   NotFound:
//     description: The specified resource was not found
//     content:
//       application/json:
//         schema:
//           $ref: '#/components/schemas/Error'
//   Unauthorized:
//     description: Unauthorized
//     content:
//       application/json:
//         schema:
//           $ref: '#/components/schemas/Error'
// schemas:
//   Error:
//     type: object
//     properties:
//       status:
//         type: string
//       error:
//         type: string
type ErrorResponse struct {
 Status string `json:"status"`
 Error  string `json:"error"`
}

// @openapi
// paths:
//
// /:
//   get:
//     tags:
//       - hello
//     summary: Say Hello
//     description: Returns a hello message
//     operationId: sayHello
//     responses:
//       '200':
//         description: successful operation
//         content:
//           application/json:
//             schema:
//               $ref: '#/components/schemas/Message'
func SayHello(w http.ResponseWriter, r *http.Request) {
 msg := Message{
  Content: "Hello world!",
 }
 render.JSON(w, r, msg)
}

func main() {
 apiDefinition := openapigodoc.OpenAPIDefinition{
  OpenAPI: "3.0.0",
  Info: openapigodoc.Info{
   Title:       "Hello API",
   Version:     "1.0.0",
   Description: "A hello world API",
  },
  Servers: []openapigodoc.Server{{URL: "http://localhost:8080"}},
  Tags: []openapigodoc.Tag{
   {
    Name:        "hello",
    Description: "hello related apis",
   },
  },
  ExternalDocs: openapigodoc.ExternalDocs{Description: "Find out more", URL: "http://example.com"},
 }

 openApiDoc, err := openapigodoc.GenerateOpenApiDoc(apiDefinition)
 if err != nil {
  log.Panicf("Logging err: %s\n", err.Error())
 }

 r := chi.NewRouter()
 r.Use(
  render.SetContentType(render.ContentTypeJSON),
  middleware.RequestID,
  middleware.Logger,
  middleware.Recoverer,
  cors.Handler(cors.Options{
   AllowedOrigins:   []string{"https://*", "http://*"},
   AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
   AllowedHeaders:   []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
   ExposedHeaders:   []string{"Link"},
   AllowCredentials: false,
   MaxAge:           300, // Maximum value not ignored by any of major browsers
  }),
 )

 r.Get("/", SayHello)
 r.Get("/api-docs", func(w http.ResponseWriter, r *http.Request) {
  w.Write(openApiDoc)
 })
 http.ListenAndServe(":8080", r)
}

Additional API information can also be added directly to the openapigodoc.OpenAPIDefinition object's Components field. This is useful when you want to add general API definitions that don't directly relate to any structures or functions in the code base.

func main() {
 securitySchemasData := []byte(`
 {
  "petstore_auth": {
   "type": "oauth2",
   "flows": {
    "implicit": {
     "authorizationUrl": "https://petstore3.swagger.io/oauth/authorize",
     "scopes": {
      "write:pets": "modify pets in your account",
      "read:pets": "read your pets"
     }
    }
   }
  },
  "api_key": {
   "type": "apiKey",
   "name": "api_key",
   "in": "header"
  }
 }`)

 var securitySchemas map[string]interface{}
 err := json.Unmarshal(securitySchemasData, &securitySchemas)
 if err != nil {
  log.Panicf("Logging err: %s\n", err.Error()) // panic if there is an error
 }

 apiDefinition := openapigodoc.OpenAPIDefinition{
        ...
  Components: openapigodoc.Components{
   SecuritySchemes: securitySchemas,
  },
 }

 openApiDoc, err := openapigodoc.GenerateOpenApiDoc(apiDefinition)
 if err != nil {
  log.Panicf("Logging err: %s\n", err.Error())
 }
    
    ...
}

Contributing

Please see CONTRIBUTING. Thank you, contributors!

License

Released under the MIT License

Credits

This package was inspired by the excellent swagger-jsdoc library.

Documentation

Overview

This package generates an OpenAPI document from comments in your code annotated with the @openapi keyword. It currently supports only the openapi 3.x schema and not the older swagger 2 schema.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenerateOpenApiDoc

func GenerateOpenApiDoc(definition OpenAPIDefinition, validate bool) ([]byte, error)

GenerateOpenApiDoc parses all struct and func comments decorated with the @openapi keyword as well as any static definitions added directly to the OpenAPIDefinition object and generates an OpenAPI document that conforms to the OpenAPI 3 specification

func ValidateOpenApiDoc

func ValidateOpenApiDoc(doc []byte) (bool, error)

ValidateOpenApiDoc validates a document conforms to the OpenAPI 3 specification

Types

type Components

type Components struct {
	Schemas         map[string]interface{} `json:"schemas,omitempty" yaml:"schemas,omitempty"`
	Parameters      map[string]interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
	SecuritySchemes map[string]interface{} `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`
	RequestBodies   map[string]interface{} `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
	Responses       map[string]interface{} `json:"responses,omitempty" yaml:"responses,omitempty"`
	Headers         map[string]interface{} `json:"headers,omitempty" yaml:"headers,omitempty"`
	Examples        map[string]interface{} `json:"examples,omitempty" yaml:"examples,omitempty"`
	Links           map[string]interface{} `json:"links,omitempty" yaml:"links,omitempty"`
	Callbacks       map[string]interface{} `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
}

Components is used to add additional static definitions to the OpenAPIDefinition object which are then combined with structs and funcs decorated with @openapi comments

type ExternalDocs

type ExternalDocs openapi3.ExternalDocs

ExternalDocs is specified by OpenAPI/Swagger standard version 3. See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#external-documentation-object

type Info

type Info openapi3.Info

Info is specified by OpenAPI standard version 3. See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#info-object

type OpenAPIDefinition

type OpenAPIDefinition struct {
	OpenAPI      string       `json:"openapi" yaml:"openapi"`
	Info         Info         `json:"info" yaml:"info"`
	Security     Security     `json:"security,omitempty" yaml:"security,omitempty"`
	Servers      []Server     `json:"servers,omitempty" yaml:"servers,omitempty"`
	Tags         []Tag        `json:"tags,omitempty" yaml:"tags,omitempty"`
	ExternalDocs ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
	Components   Components   `json:"components,omitempty" yaml:"components,omitempty"`
}

OpenAPIDefinition is used to define general properties of an API which is then combined with other definitions to generate an OpenAPI document

type Server

type Server openapi3.Server

Server is specified by OpenAPI/Swagger standard version 3. See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#server-object

type Tag

type Tag openapi3.Tag

Tag is specified by OpenAPI/Swagger 3.0 standard. See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#tag-object

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL