oapi

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Feb 1, 2021 License: MIT Imports: 17 Imported by: 0

README

OAPI GO

Make your go application (partial) source of truth for your OpenAPI spec.

This library acts as if go packages, yaml files, or json files were just json documents, giving you ability to use pointers to reference and convert go types into schemes.

Example

Given such a struct:

package mypkg
// This package is located at github.com/org/repo/mypkg

type Item {
    Kind string `json:"kind"`
    Name string `json:"name"`
}

and such a definition:

openapi: 3.0.3
info:
    title: "MyAwsomeApp"
    version: "-"
paths:
  /v1/items:
    get:
      responses:
        "200":
          content:
            application/json:
            schema:
              $ref: 'go://#/Item' # shorthand for 'go://github.com/org/repo/mypkg#/Item'
          description: Returns items

will produce OpenAPI specs:

openapi: 3.0.3
info:
    title: "MyAwsomeApp"
    version: "-"
paths:
  /v1/items:
    get:
      responses:
        "200":
          content:
            application/json:
            schema:
              type: object
              properties:
                kind:
                  type: string
                name:
                  type: string
          description: Returns items

Of course this is very simple example just for illustration on how powerful pointers can be.

go://github.com/path/to/pkg#/Struct/Field
[1--][2--------------------][3----------]

For go pointers:

1) Is scheme, designating what resolver we are using in this case it is go.
2) Is full package path with authority.
3) Is path in go pkg to given struct field or any type.

Similary any protocol can be resolved this way (go://, file://, http://, etc).

Motivation:

This library is trying to challange way how currently many openapi / swag libraries work. Traditionally if you want to make your go application being source of truth of your swagger / openapi specification, you have to use "magic" comments which will be parsed and specification will be generated.

Golang depends heavily on comments, tools like godoc, go generate, build flags would not work well without them. My personal believe is that screwing up docs or managing yaml being pasted in comments is not worth it.

I had following requirements:

  • OpenAPI specs should be valid and used on go package basis
  • magic comments should be use but very lightly, rather as decoration
  • go types should be source of truth and you should be able to reference them from any angle
  • you should be able to merge multiple OpenAPI specs into one
  • you should be able to support multiple specs in one repository
  • ability to decorate structs with oapi tag to allow specifiying schema specific attributes
  • ability to also have runtime validator based on oapi tag

Usage:

usage: oapi [<flags>]

Flags:
  --help               Show context-sensitive help (also try --help-long and --help-man).
  --loglevel=LOGLEVEL  will set log level
  --config=CONFIG      config to be used
  --dir=DIR            execution directory usually dir of main pkg
  --format=FORMAT      will set output format
  --output=OUTPUT      will set output destination

Simpliest way to start is to define yaml definition:

# in .examples/config/items/

openapi: "3.0.3"
info:
  title: "test"
  version: "-"
paths: 
  /v1/items:
    get:
      responses:
        "200":
          description: "Returns items"
          content:
            application/json:
              schema:
                $ref: 'go://#/Response'

And now you can run:

oapi --dir .examples/config/items/

output will be printed to stdout.

Note directory in this example needs to be pacakge importing all dependencies otherwise those will not be resolved.

We recommend to place config and //go:generate in your main package.

Inspiration:

https://github.com/wzshiming/openapi

https://github.com/santhosh-tekuri/jsonschema

Documentation

Overview

Package oapi will convert your go types to schemes allowing to make go code parital source of truth.

With many openapi libraries around there is common patter to keep your documentation in comments. It is usually done with some 'magic' syntax which can be utilized to make your program to be source of truth for openapi specifications.

Problem with this approach is that if you want to do specification well and allow more complicated use cases you are forced to use yaml embedded in comments.

I would argue that we are better off with using just good ol' plain yaml files. Defining small openapi spec in yaml files is easy, tooling works well, and its flexible up to the point where you have to manage large amount of data structures.

This package is aming to provide tools which helps to manage situation where simple yaml files are burden rather then simple solution.

This is done by making use of json pointers, which are in core of json schema and openapi. More about json pointers: https://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-04

Go source and its structure can be navigated with json pointers same way yaml or json can be. Syntax of json pointer is bit altered but it is still compliant with RFC.

Go Pointer resolution

Given go structure:

type Object struct { Field string `json:"field"` }

And defined specification:

{"$ref": "go://github.com/buypal/oapi-go#/Object" }

Following json scheme will be produced:

{"schema": {"properties": {"field": {"type": "string"}}}}

Pointer go://github.com/buypal/oapi-go#/Object uri refers to package and fragment (pointer) is referring to exact location of data structure in that package.

Following pointers will be resolved as json schema:

• go://github.com/buypal/oapi-go#/Object

• go://github.com/buypal/oapi-go#/Object/Field

• go://#/Object (local resolution)

With this approach we can tackle problem of having resistance against changes in go source code. For example if you change data type of Field from `string` to `int` json schema will become:

{"schema": {"properties": {"field": {"type": "number", "format": "int32"}}}}

By default all schemes are resolved locally. If you want export scheme globally you can use magic comments in your go source code.

//oapi:schema <schema name> <source of schema>
//oapi:schema <source of schema>

Examples (works same):

//oapi:schema Object
//oapi:schema go://github.com/buypal/oapi-go#/Object

Merging specifications

One of the goals of this package was also to provide way how to merge multiple specifications together. Every package can have file oapi.yaml or oapi.json which will be merged to "global" document. This is happening out of the box just by running oapi command. This allows to mantain per package openapi specifications.

Additional RFC documents

https://tools.ietf.org/html/rfc3986

https://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-04

https://tools.ietf.org/id/draft-pbryan-zyp-json-ref-03.html#RFC3986

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Format

func Format(f string, oapi OAPI) (data []byte, err error)

Format will format given specs into given format.

Types

type OAPI

type OAPI struct {
	// contains filtered or unexported fields
}

OAPI specification holds valid openapi specification.

func Scan

func Scan(ctx context.Context, options ...Option) (s OAPI, err error)

Scan will scan all types in given directory (by deault cwd), and merge all openapi files into single document returned as OAPI.

type Option

type Option func(*Options) error

Option for .Scan() method

func WithDefOps

func WithDefOps(defops map[string]spec.Operation) Option

WithDefOps is shorthant for with default operations.

func WithDir

func WithDir(dir string) Option

WithDir sets the directory for scanning.

func WithLog

func WithLog(l logging.Printer) Option

WithLog will set new logger.

func WithOverride

func WithOverride(or map[string]spec.Schema) Option

WithOverride will add sets of overrides. These can be used to override pointers which already exists.

func WithRootSchema

func WithRootSchema(oapi spec.OpenAPI) Option

WithRootSchema is option to provide root schema. This is useful if you have global components.

type Options

type Options struct {
	// contains filtered or unexported fields
}

Options represents options of scan.

Directories

Path Synopsis
cmd
internal
oapi/scan/cmds
Package cmds is sort of like ast for oapenapi commands.
Package cmds is sort of like ast for oapenapi commands.
pointer
Package pointer implements IETF rfc6901 JSON Pointers are a string syntax for identifying a specific value within a JavaScript Object Notation (JSON) document [RFC4627].
Package pointer implements IETF rfc6901 JSON Pointers are a string syntax for identifying a specific value within a JavaScript Object Notation (JSON) document [RFC4627].

Jump to

Keyboard shortcuts

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