openapigodoc

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 5, 2024 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. Just add the @openapi keyword at the top of a struct or func declaration and describe the given API part in YAML syntax. 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.

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