go-swagify

module
v0.0.0-...-c71d033 Latest Latest
Warning

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

Go to latest
Published: May 25, 2023 License: MIT

README

Go-swagify

This project is designed to create a swagger document based on the specification for OpenApi v3.0. This is done by comments in your Go code.

Note: currently this does not support every option within the specification, if you want a feature ask for it or create a PR. See below what is currently supported.

Object

Adding comments to your code to produce a swagger docs instead of creating the yaml or json file manually? Who wouldn't want that?! The idea would be that on creation or maintenance of you code, make sure the comments match what is desired. Run this code against the project's directory, Done! A swagger document is created for you.

Usage

After compiling this library, add this binary to your path or move into your path.

Args:

inputPath: directory to run the parse against
outputPath: directory with file name to save the swagger doc
outputFormat: yaml | json; output format; if omitted, default of 'yaml'
appOutputFormat: json | yaml; your apps' output format; if omitted, default of 'json'
appFieldFormat:  snakeCase | kebabCase | camelCase | pascalCase | lowerCase | upperCase: schema's name field format; if ommitted, default of 'camelCase'

If this application is ran without any args the current directory is scanned and the output file is called swagger.yaml all other defaults are used.

Specs

If you are familiar with the OpenApi spec you can specify the object's definition in components/schemas and used as a reference for other parts of the spec. This application relies heavily on that pattern. In some cases you can specify the object at the level you want, those will be pointed out for you to use.

comments

Using the block comment like this:

/* go-swagify
*/

is a must. Within the block, will depend on the spec you want to create, read on, examples follow.

Schema

Since a lot of the spec is based on a struct of your code. The parsing of the struct is quite different then the rest, let's start with that.

The struct is vital to golang development so struct tags are leveraged to declare the schema spec. For each field that you want to include in the schema spec.

sw: list of names wanting to associated this field to, delimited by ';'
sw_desc: the description of the field used in the spec
sw_ex: the example to use in the spec

usage:

/* go-swagify
@@struct: User
*/

type User struct {
	Id        int         `db:"id" json:"Id" yaml:"id" sw:"User" sw_desc:"Unique Id for user" sw_ex:"101"`
	FirstName null.String `db:"first_name" json:"FirstName" yaml:"first_name" sw:"User;UserResponse*;UserRequest*" sw_desc:"First name of the user" sw_ex:"John Doe"`
	Age       null.Int    `db:"age" json:"Age" yaml:"age" sw:"User;UserResponse*;UserRequest*" sw_desc:"Age of the user" sw_ex:"42"`
	Active    null.Bool   `db:"active" json:"Active" yaml:"active" sw:"User;UserResponse;UserRequest*" sw_desc:"Is the user's account active" sw_ex:"true | false"`
	CreatedAt null.Time   `db:"created_at" json:"CreatedAt" yaml:"created_at" sw:"User;UserRequest" sw_desc:"Date create for this record" sw_ex:"2020-01-01T00:00:00Z"`
}

The go-swagify block just tells the parser that you want to inspect the struct called User The sw: tag can take list of names (delimited by ;) if you end the name with * then it will make that field for that schema name a required in the spec.

If the sw struct is omitted, the field is skipped.

The name is calculated by

  • taking the struct tag defined for the field for the appOutputFormat (default of json)
  • if that struct tag is not defined then the field name is formatted by the altFieldFormat directive (default lowerCase)

With the following struct with the struct tags defined as so, the following components/schemas objects would be created:

components:
	schemas:
		User:
			type: object
			properties:
				Active:
					type: boolean
					description: Is the user's account active
					example: true | false
				Age:
					type: integer
					description: Age of the user
					example: 42
				CreatedAt:
					type: string
					description: Date create for this record
					example: "2020-01-01T00:00:00Z"
				FirstName:
					type: string
					description: First name of the user
					example: John Doe
				Id:
					type: integer
					description: Unique Id for user
					example: 101
		UserRequest:
			type: object
			required:
			- FirstName
			- Age
			- Active
			properties:
				Active:
					type: boolean
					description: Is the user's account active
					example: true | false
				Age:
					type: integer
					description: Age of the user
					example: 42
				CreatedAt:
					type: string
					description: Date create for this record
					example: "2020-01-01T00:00:00Z"
				FirstName:
					type: string
					description: First name of the user
					example: John Doe
		UserResponse:
			type: object
			required:
			- FirstName
			- Age
			properties:
				Active:
					type: boolean
					description: Is the user's account active
					example: true | false
				Age:
					type: integer
					description: Age of the user
					example: 42
				FirstName:
					type: string
					description: First name of the user
					example: John Doed

NOTE: all examples will show the full yaml path to show where the object is related within the yaml structure

You can create the schema manually:

/* go-swagify
@@schema: UserManual
@@type: object
@@prop_name: Id
@@prop_type: number
@@prop_desc: unique identifier for user
@@prop_ex: 1
@@prop_name: FirstName
@@prop_req: true
@@prop_type: string
@@prop_desc: user's first name
@@prop_ex: John
@@prop_name: Age
@@prop_type: number
@@prop_desc: user's age
@@prop_ex: 42
*/

repeating @@prop_name, @@prop_type, @@prop_desc, @@prop_ex for each field

output:

components:
	schemas:
		UserManual:
			type: object
			required:
			- FirstName
			properties:
				Age:
					type: number
					description: user's age
					example: 42
				FirstName:
					type: string
					description: user's first name
					example: John
				Id:
					type: number
					description: unique identifier for user
					example: 1

note: @@prop_type, @@prop_desc, @@prop_ex and @@prop_req will be related to the proceeding @@prop_name, so order is important

You can produce an object of another schema:

/* go-swagify
@@schema: UserRef
@@type: object
@@prop_name: data
@@prop_ref: UserManual
*/

components:
	schemas:
		UserRef:
			type: object
			properties:
				data:
				$ref: '#/components/schemas/UserManual'
Parameter

This will create a spec for the components/parameters spec

/* go-swagify
@@parameter: UserIndentifierParam
@@name: id
@@in: path (required valid values: query | header | path | cookie)
@@description: Unique User Identifier (optional)
@@required: true (optional: true | false (default))
// schema (optional) see schema.go/SchemaProperty
@@schema_type: number
@@schema_description: User Indentifier
@@schema_example: (optional; not used in this example)
*/

components:
	parameters:
		UserIdentifierParam:
			name: id
			in: path
			description: Unique User identifier
			required: true
			schema:
				type: number
				description: User identifier
Response & RequestBody

The format for both of these are very similiar, these will fill in components/responses and components/requestBodies respectfully

/* go-swagify
@@response: UserResponseRef
@@desc: the User record
@@content_name: application/json
@@content_ref: UserResponse
*/

/* go-swagify
@@request: UserRequestRef
@@desc: the User record to be created
@@content_name: application/json
@@content_ref: UserRequest
*/

components:
	responses:
		UserResponseRef:
			description: the User record
			content:
				application/json:
				schema:
					$ref: '#/components/schemas/UserResponse'
  	requestBodies:
		UserRequestRef:
			description: the User record to be created
			content:
				application/json:
				schema:
					$ref: '#/components/schemas/UserRequest'
Path && Operation

Looking at the spec, the path can have multiple operations so defining the path name is the key to using both.

Once you define a path:

/* go-swagify
@@path: /user/{id}
@@parameters.ref: UserIdentifierParam
*/

Then you can define as may operations as that go under that path name, like so:

/* go-swagify
@@operation: /user/{id}
@@method: get
@@summary: Get User
@@description: Get a single User record by identifier
@@tags: User
@@resp_name: 200
@@resp_ref: UserResponseRef
@@resp_name: 400
@@resp_ref: Error
*/

Output would be:

paths:
	/user/{id}:
		parameters:
		- $ref: '#/components/parameters/UserIdentifierParam'
		get:
			summary: Get User
			description: Get a single User record by identifier
			tags:
			- User
			responses:
			"200":
				$ref: '#/components/responses/UserResponseRef'
			"400":
				$ref: '#/components/responses/Error'

note: @@resp_name, @@resp_ref can be repeated as many times as needed but should be the the last lines within the comment block

Jump to

Keyboard shortcuts

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