Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test and README + rebase #1

Open
wants to merge 11 commits into
base: add-package-and-struct-name-to-OperationInfo
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: CI

on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
test:
name: Tests
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
go:
- "1.15.x"
- "1.16.x"
- "1.17.x"
os:
- ubuntu-latest
- macos-latest
- windows-latest
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Checkout repository
uses: actions/checkout@v2
- name: Run tests
run: ./ci/test.sh
- name: Upload coverage
uses: codecov/codecov-action@v1
with:
file: coverage.txt
30 changes: 30 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: release

on:
push:
tags:
- 'v*'

permissions:
contents: write

jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
distribution: goreleaser
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ coverage.txt

# GoLand
.idea

# VSCode
.history
11 changes: 11 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
project_name: fizz
builds:
- skip: true
release:
github:
owner: wI2L
name: fizz
draft: true
prerelease: auto
env_files:
github_token: ~/.goreleaser_github_token
22 changes: 0 additions & 22 deletions .travis.yml

This file was deleted.

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018 William Poussier
Copyright (c) 2018-2021 William Poussier <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
99 changes: 68 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@

<h1 align="center">Fizz</h1>
<p align="center"><img src="images/lemon.png" height="200px" width="auto" alt="Gin Fizz"></p><p align="center">Fizz is a wrapper for <strong>Gin</strong> based on <i>gadgeto/tonic</i>.</p>
<p align="center">It generates wrapping gin-compatible handlers that do all the repetitive work and wrap the call to your handlers. It can also generates an *almost* complete <strong>OpenAPI 3</strong> specification of your API.</p>
<p align="center"><img src="images/lemon.png" height="200px" width="auto" alt="Gin Fizz"></p><p align="center">Fizz is a wrapper for <strong>Gin</strong> based on <strong><a href="https://github.com/loopfz/gadgeto/tree/master/tonic">gadgeto/tonic</a></strong>.</p>
<p align="center">It generates wrapping gin-compatible handlers that do all the repetitive work and wrap the call to your handlers. It can also generates an <i>almost</i> complete <strong>OpenAPI 3</strong> specification of your API.</p>
<p align="center">
<a href="https://godoc.org/github.com/wI2L/fizz"><img src="https://img.shields.io/badge/godoc-reference-blue.svg"></a>
<a href="https://pkg.go.dev/github.com/wI2L/fizz?tab=doc"><img src="https://img.shields.io/static/v1?label=godev&message=reference&color=00add8&logo=go"></a>
<a href="https://goreportcard.com/report/wI2L/fizz"><img src="https://goreportcard.com/badge/github.com/wI2L/fizz"></a>
<a href="https://travis-ci.org/wI2L/fizz"><img src="https://travis-ci.org/wI2L/fizz.svg?branch=master"></a>
<a href="https://github.com/wI2L/fizz/actions"><img src="https://github.com/wI2L/fizz/workflows/CI/badge.svg"></a>
<a href="https://codecov.io/gh/wI2L/fizz"><img src="https://codecov.io/gh/wI2L/fizz/branch/master/graph/badge.svg"/></a>
<a href="https://github.com/wI2L/fizz/releases"><img src="https://img.shields.io/github/v/tag/wI2L/fizz?color=blueviolet&label=version&sort=semver"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
<a href="https://github.com/avelino/awesome-go"><img src="https://awesome.re/mentioned-badge.svg"></a>
<br>
</p>

Expand Down Expand Up @@ -96,25 +98,40 @@ fizz.Header(name, desc string, model interface{})
// Override the binding model of the operation.
fizz.InputModel(model interface{})

// Overrides the top-level security requirement of an operation.
// Note that this function can be used more than once to add several requirements.
fizz.Security(security *openapi.SecurityRequirement)

// Add an empty security requirement to this operation to make other security requirements optional.
fizz.WithOptionalSecurity()

// Remove any top-level security requirements for this operation.
fizz.WithoutSecurity()

// Add a Code Sample to the operation.
fizz.XCodeSample(codeSample *XCodeSample)

// Mark the operation as internal. The x-internal flag is interpreted by third-party tools and it only impacts the visual documentation rendering.
fizz.XInternal()
```

**NOTES:**
* `fizz.InputModel` allows to override the operation input regardless of how the handler implementation really binds the request parameters. It is the developer responsibility to ensure that the binding matches the OpenAPI specification.
* The fist argument of the `fizz.Reponse` method which represents an HTTP status code is of type *string* because the spec accept the value `default`. See the [Responses Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responsesObject) documentation for more informations.
* The first argument of the `fizz.Reponse` method which represents an HTTP status code is of type *string* because the spec accept the value `default`. See the [Responses Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responsesObject) documentation for more informations.

To help you declare additional headers, predefined variables for Go primitives types that you can use as the third argument of the `fizz.Header` method are available.
To help you declare additional headers, predefined variables for Go primitives types that you can use as the third argument of the `fizz.Header` method are available:
```go
Integer int32
Long int64
Float float32
Double float64
String string
Byte []byte
Binary []byte
Boolean bool
DateTime time.Time
var (
Integer int32
Long int64
Float float32
Double float64
String string
Byte []byte
Binary []byte
Boolean bool
DateTime time.Time
)
```

### Groups
Expand Down Expand Up @@ -178,8 +195,8 @@ fizz.GET("/foo", []fizz.OperationOption{

*tonic* uses three struct tags to recognize the parameters it should bind to the input object of your tonic-wrapped handlers:
- `path`: bind from the request path
- `query`: bind from the query string
- `header`: bind from the request header
- `query`: bind from the request query string
- `header`: bind from the request headers

The fields that doesn't use one of these tags will be considered as part of the request body.

Expand All @@ -199,14 +216,17 @@ type MyHandlerParams struct {
### Additional tags

You can use additional tags. Some will be interpreted by *tonic*, others will be exclusively used to enrich the *OpenAPI* specification.
- `default`: *tonic* will bind this value if none was passed with the request. This should not be used if a field is also required. Read the [documentation](https://swagger.io/docs/specification/describing-parameters/) (section _Common Mistakes_) for more informations about this behaviour.
- `description`: Add a description of the field in the spec.
- `deprecated`: Indicates if the field is deprecated. Accepted values are _1_, _t_, _T_, _TRUE_, _true_, _True_, _0_, _f_, _F_, _FALSE_. Invalid value are considered to be false.
- `enum`: A coma separated list of acceptable values for the parameter.
- `example`: An example value to be used in OpenAPI specification.
- `format`: Override the format of the field in the specification. Read the [documentation](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#dataTypeFormat) for more informations.
- `validate`: Field validation rules. Read the [documentation](https://godoc.org/gopkg.in/go-playground/validator.v8) for more informations.
- `explode`: Specifies whether arrays should generate separate parameters for each array item or object property (limited to query parameters with *form* style). Accepted values are _1_, _t_, _T_, _TRUE_, _true_, _True_, _0_, _f_, _F_, _FALSE_. Invalid value are considered to be false.

| name | description |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `default` | *tonic* will bind this value if none was passed with the request. This should not be used if a field is also required. Read the [documentation](https://swagger.io/docs/specification/describing-parameters/) (section _Common Mistakes_) for more informations about this behaviour. |
| `description` | Add a description of the field in the spec. |
| `deprecated` | Indicates if the field is deprecated. Accepted values are `1`, `t`, `T`, `TRUE`, `true`, `True`, `0`, `f`, `F`, `FALSE`. Invalid value are considered to be false. |
| `enum` | A coma separated list of acceptable values for the parameter. |
| `example` | An example value to be used in OpenAPI specification. |
| `format` | Override the format of the field in the specification. Read the [documentation](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#dataTypeFormat) for more informations. |
| `validate` | Field validation rules. Read the [documentation](https://godoc.org/gopkg.in/go-playground/validator.v8) for more informations. |
| `explode` | Specifies whether arrays should generate separate parameters for each array item or object property (limited to query parameters with *form* style). Accepted values are `1`, `t`, `T`, `TRUE`, `true`, `True`, `0`, `f`, `F`, `FALSE`. Invalid value are considered to be false. |

### JSON/XML

Expand Down Expand Up @@ -243,7 +263,7 @@ Based on the type of the field that carry the tag, the fields `maximum`, `minimu

To serve the generated OpenAPI specification in either `JSON` or `YAML` format, use the handler returned by the `fizz.OpenAPI` method.

To enrich the specification, you can provide additional informations. Head to the [OpenAPI 3 spec](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#infoObject) for more informations about the API informations that you can specify, or take a look at the type `openapi.Info` in the file [_openapi/spec.go_](openapi/spec.go#L25).
To enrich the specification, you can provide additional informations. Head to the [OpenAPI 3 spec](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#infoObject) for more informations about the API informations that you can specify, or take a look at the type `openapi.Info` in the file [`openapi/spec.go`](openapi/spec.go#L25).

```go
infos := &openapi.Info{
Expand All @@ -255,6 +275,22 @@ f.GET("/openapi.json", nil, fizz.OpenAPI(infos, "json"))
```
**NOTE**: The generator will never panic. However, it is strongly recommended to call `fizz.Errors` to retrieve and handle the errors that may have occured during the generation of the specification before starting your API.

#### Handlers

##### Custom Namer

You can custom how your handlers are named when no ID is rovided.
```go
// This namer use the package name so you can have multiple handlers with the same name if they are in different packages.
f.Generator().SetHandlerNamer(func(handler *tonic.Route) string {
id := handler.HandlerNameWithPackage()
id = strings.ReplaceAll(id, "*", "")
id = strings.ReplaceAll(id, "(", "")
id = strings.ReplaceAll(id, ")", "")
return id
})
```

#### Components

The output types of your handlers are registered as components within the generated specification. By default, the name used for each component is composed of the package and type name concatenated using _CamelCase_ style, and does not contain the full import path. As such, please ensure that you don't use the same type name in two eponym package in your application.
Expand Down Expand Up @@ -308,12 +344,13 @@ fizz.Generator().OverrideDataType(reflect.TypeOf(&UUIDv4{}), "string", "uuid")

Fizz supports some native and imported types. A schema with a proper type and format will be generated automatically, removing the need for creating your own custom schema.

* [time.Time](https://golang.org/pkg/time/#Time)
* [time.Duration](https://golang.org/pkg/time/#Duration)
* [net.URL](https://golang.org/pkg/net/url/#URL)
* [net.IP](https://golang.org/pkg/net/#IP)
* [`time.Time`](https://golang.org/pkg/time/#Time)
* [`time.Duration`](https://golang.org/pkg/time/#Duration)
* [`net.URL`](https://golang.org/pkg/net/url/#URL)
* [`net.IP`](https://golang.org/pkg/net/#IP)

Note that, according to the doc, the inherent version of the address is a semantic property, and thus cannot be determined by Fizz. Therefore, the format returned is simply `ip`. If you want to specify the version, you can use the tags `format:"ipv4"` or `format:"ipv6"`.
* [uuid.UUID](https://godoc.org/github.com/gofrs/uuid#UUID)
* [`uuid.UUID`](https://godoc.org/github.com/gofrs/uuid#UUID)

#### Markdown

Expand Down
2 changes: 1 addition & 1 deletion test.sh → ci/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -e
echo "" > coverage.txt

for d in $(go list ./... | grep -v vendor); do
go test -race -coverprofile=profile.out -covermode=atomic $d
go test -v -race -coverprofile=profile.out -covermode=atomic "$d"
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
Expand Down
30 changes: 30 additions & 0 deletions fizz.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,36 @@ func XCodeSample(cs *openapi.XCodeSample) func(*openapi.OperationInfo) {
}
}

// Overrides top-level security requirement for this operation.
// Note that this function can be used more than once to add several requirements.
func Security(security *openapi.SecurityRequirement) func(*openapi.OperationInfo) {
return func(o *openapi.OperationInfo) {
o.Security = append(o.Security, security)
}
}

// Add an empty security requirement to this operation to make other security requirements optional.
func WithOptionalSecurity() func(*openapi.OperationInfo) {
return func(o *openapi.OperationInfo) {
var emptyRequirement openapi.SecurityRequirement = make(openapi.SecurityRequirement)
o.Security = append(o.Security, &emptyRequirement)
}
}

// Remove any top-level security requirements for this operation.
func WithoutSecurity() func(*openapi.OperationInfo) {
return func(o *openapi.OperationInfo) {
o.Security = []*openapi.SecurityRequirement{}
}
}

// XInternal marks the operation as internal.
func XInternal() func(*openapi.OperationInfo) {
return func(o *openapi.OperationInfo) {
o.XInternal = true
}
}

// OperationFromContext returns the OpenAPI operation from
// the givent Gin context or an error if none is found.
func OperationFromContext(c *gin.Context) (*openapi.Operation, error) {
Expand Down
Loading