Skip to content

Commit

Permalink
Swagger improvements (#666)
Browse files Browse the repository at this point in the history
* refactor: swagger docs into a folder

* added scripts for the swaggger tasks

* check version and fmt

* CI

* formatted swag comments

* using custom delims

* revert custom delims

* swag 1.16.1

* update swagger docs

* avoid make swagger output

* swagger check

* test

* swag-fmt

* swagger run

* gofmt

* avoid swag-fmt check for now due to inconsistencies with gofmt

* re-enabled by using go fmt afterwards

* use newer swag in CI

* add gopath to path

* using go binary instead of unset env

* alternative

* correct swag version

* formatted

* formatted

* correct go fmt command

* make swagger

* swagger-check -> swag-check

* run swag-check on lint
  • Loading branch information
fmartingr authored Aug 12, 2023
1 parent 2e1016e commit 8b015a3
Show file tree
Hide file tree
Showing 12 changed files with 160 additions and 59 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/_swagger-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: "swagger-check"

on: workflow_call

jobs:
swagger-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0

- name: Setup Go
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
with:
go-version-file: 'go.mod'

- name: Install dependencies
run: go install $(cat go.mod | grep swaggo/swag | cut -d " " -f 1)/cmd/swag@$(cat go.mod | grep swaggo/swag | cut -d " " -f 2)

- name: check
run: make swag-check

4 changes: 3 additions & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ jobs:
uses: ./.github/workflows/_golangci-lint.yml
call-test:
uses: ./.github/workflows/_test.yml
call-swagger-check:
uses: ./.github/workflows/_swagger-check.yml
call-gorelease:
needs: [call-lint, call-test]
needs: [call-lint, call-test, call-swagger-check]
uses: ./.github/workflows/_gorelease.yml
call-buildx:
needs: call-gorelease
Expand Down
23 changes: 20 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ LDFLAGS += -s -w -X main.version=$(BUILD_HASH) -X main.date=$(BUILD_TIME)
GIN_MODE ?= debug
SHIORI_DEVELOPMENT ?= true

# Swagger
SWAG_VERSION := v1.8.12
SWAGGER_DOCS_PATH ?= ./docs/swagger

# Help documentatin à la https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
.PHONY: help
help:
Expand All @@ -42,11 +46,24 @@ run-server:
## Generate swagger docs
.PHONY: swagger
swagger:
swag init
SWAGGER_DOCS_PATH=$(SWAGGER_DOCS_PATH) $(BASH) ./scripts/swagger.sh

.PHONY: swag-check
swag-check:
REQUIRED_SWAG_VERSION=$(SWAG_VERSION) SWAGGER_DOCS_PATH=$(SWAGGER_DOCS_PATH) $(BASH) ./scripts/swagger_check.sh

## Run linter
.PHONY: swag-fmt
swag-fmt:
swag fmt --dir internal/http
go fmt ./internal/http/...

## Run linters
.PHONY: lint
lint:
lint: golangci-lint swag-check

## Run golangci-lint
.PHONY: golangci-lint
golangci-lint:
golangci-lint run

## Run unit tests
Expand Down
2 changes: 1 addition & 1 deletion docs/Contribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ make swagger

## Lint the code

In order to lint the code, you need to have installed [golangci-lint](https://golangci-lint.run).
In order to lint the code, you need to have installed [golangci-lint](https://golangci-lint.run) and [swag](https://github.com/swaggo/swag).

After that, run the following command:

Expand Down
20 changes: 14 additions & 6 deletions docs/docs.go → docs/swagger/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 13 additions & 5 deletions docs/swagger.json → docs/swagger/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@
"name": "payload",
"in": "body",
"schema": {
"$ref": "#/definitions/api.loginRequestPayload"
"$ref": "#/definitions/api_v1.loginRequestPayload"
}
}
],
"responses": {
"200": {
"description": "Login successful",
"schema": {
"$ref": "#/definitions/api.loginResponseMessage"
"$ref": "#/definitions/api_v1.loginResponseMessage"
}
},
"400": {
Expand Down Expand Up @@ -74,7 +74,7 @@
"200": {
"description": "Refresh successful",
"schema": {
"$ref": "#/definitions/api.loginResponseMessage"
"$ref": "#/definitions/api_v1.loginResponseMessage"
}
},
"403": {
Expand Down Expand Up @@ -130,7 +130,7 @@
}
},
"definitions": {
"api.loginRequestPayload": {
"api_v1.loginRequestPayload": {
"type": "object",
"required": [
"password",
Expand All @@ -148,9 +148,17 @@
}
}
},
"api.loginResponseMessage": {
"api_v1.loginResponseMessage": {
"type": "object",
"properties": {
"expires": {
"description": "Deprecated, used only for legacy APIs",
"type": "integer"
},
"session": {
"description": "Deprecated, used only for legacy APIs",
"type": "string"
},
"token": {
"type": "string"
}
Expand Down
16 changes: 11 additions & 5 deletions docs/swagger.yaml → docs/swagger/swagger.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
definitions:
api.loginRequestPayload:
api_v1.loginRequestPayload:
properties:
password:
type: string
Expand All @@ -11,8 +11,14 @@ definitions:
- password
- username
type: object
api.loginResponseMessage:
api_v1.loginResponseMessage:
properties:
expires:
description: Deprecated, used only for legacy APIs
type: integer
session:
description: Deprecated, used only for legacy APIs
type: string
token:
type: string
type: object
Expand Down Expand Up @@ -48,14 +54,14 @@ paths:
in: body
name: payload
schema:
$ref: '#/definitions/api.loginRequestPayload'
$ref: '#/definitions/api_v1.loginRequestPayload'
produces:
- application/json
responses:
"200":
description: Login successful
schema:
$ref: '#/definitions/api.loginResponseMessage'
$ref: '#/definitions/api_v1.loginResponseMessage'
"400":
description: Invalid login data
summary: Login to an account using username and password
Expand Down Expand Up @@ -83,7 +89,7 @@ paths:
"200":
description: Refresh successful
schema:
$ref: '#/definitions/api.loginResponseMessage'
$ref: '#/definitions/api_v1.loginResponseMessage'
"403":
description: Token not provided/invalid
summary: Refresh a token for an account
Expand Down
47 changes: 25 additions & 22 deletions internal/http/routes/api/v1/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,15 @@ type loginResponseMessage struct {
}

// loginHandler godoc
// @Summary Login to an account using username and password
// @Tags Auth
// @Accept json
// @Produce json
// @Param payload body loginRequestPayload false "Login data"
// @Success 200 {object} loginResponseMessage "Login successful"
// @Failure 400 {object} nil "Invalid login data"
// @Router /api/v1/auth/login [post]
//
// @Summary Login to an account using username and password
// @Tags Auth
// @Accept json
// @Produce json
// @Param payload body loginRequestPayload false "Login data"
// @Success 200 {object} loginResponseMessage "Login successful"
// @Failure 400 {object} nil "Invalid login data"
// @Router /api/v1/auth/login [post]
func (r *AuthAPIRoutes) loginHandler(c *gin.Context) {
var payload loginRequestPayload
if err := c.ShouldBindJSON(&payload); err != nil {
Expand Down Expand Up @@ -103,13 +104,14 @@ func (r *AuthAPIRoutes) loginHandler(c *gin.Context) {
}

// refreshHandler godoc
// @Summary Refresh a token for an account
// @Tags Auth
// @securityDefinitions.apikey ApiKeyAuth
// @Produce json
// @Success 200 {object} loginResponseMessage "Refresh successful"
// @Failure 403 {object} nil "Token not provided/invalid"
// @Router /api/v1/auth/refresh [post]
//
// @Summary Refresh a token for an account
// @Tags Auth
// @securityDefinitions.apikey ApiKeyAuth
// @Produce json
// @Success 200 {object} loginResponseMessage "Refresh successful"
// @Failure 403 {object} nil "Token not provided/invalid"
// @Router /api/v1/auth/refresh [post]
func (r *AuthAPIRoutes) refreshHandler(c *gin.Context) {
ctx := context.NewContextFromGin(c)
if !ctx.UserIsLogged() {
Expand All @@ -133,13 +135,14 @@ func (r *AuthAPIRoutes) refreshHandler(c *gin.Context) {
}

// meHandler godoc
// @Summary Get information for the current logged in user
// @Tags Auth
// @securityDefinitions.apikey ApiKeyAuth
// @Produce json
// @Success 200 {object} model.Account
// @Failure 403 {object} nil "Token not provided/invalid"
// @Router /api/v1/auth/me [get]
//
// @Summary Get information for the current logged in user
// @Tags Auth
// @securityDefinitions.apikey ApiKeyAuth
// @Produce json
// @Success 200 {object} model.Account
// @Failure 403 {object} nil "Token not provided/invalid"
// @Router /api/v1/auth/me [get]
func (r *AuthAPIRoutes) meHandler(c *gin.Context) {
ctx := context.NewContextFromGin(c)
if !ctx.UserIsLogged() {
Expand Down
30 changes: 15 additions & 15 deletions internal/http/routes/api/v1/tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ func (r *TagsAPIRoutes) Setup(g *gin.RouterGroup) model.Routes {
return r
}

// @Summary List tags
// @Tags Tags
// @securityDefinitions.apikey ApiKeyAuth
// @Produce json
// @Success 200 {object} model.Tag "List of tags"
// @Failure 403 {object} nil "Token not provided/invalid"
// @Router /api/v1/tags [get]
// @Summary List tags
// @Tags Tags
// @securityDefinitions.apikey ApiKeyAuth
// @Produce json
// @Success 200 {object} model.Tag "List of tags"
// @Failure 403 {object} nil "Token not provided/invalid"
// @Router /api/v1/tags [get]
func (r *TagsAPIRoutes) listHandler(c *gin.Context) {
tags, err := r.deps.Database.GetTags(c)
if err != nil {
Expand All @@ -38,14 +38,14 @@ func (r *TagsAPIRoutes) listHandler(c *gin.Context) {
response.Send(c, http.StatusOK, tags)
}

// @Summary Create tag
// @Tags Tags
// @securityDefinitions.apikey ApiKeyAuth
// @Produce json
// @Success 200 {object} model.Tag "Created tag"
// @Failure 400 {object} nil "Token not provided/invalid"
// @Failure 403 {object} nil "Token not provided/invalid"
// @Router /api/v1/tags [post]
// @Summary Create tag
// @Tags Tags
// @securityDefinitions.apikey ApiKeyAuth
// @Produce json
// @Success 200 {object} model.Tag "Created tag"
// @Failure 400 {object} nil "Token not provided/invalid"
// @Failure 403 {object} nil "Token not provided/invalid"
// @Router /api/v1/tags [post]
func (r *TagsAPIRoutes) createHandler(c *gin.Context) {
var tag model.Tag
if err := c.BindJSON(&tag); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/http/routes/swagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
swaggerfiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"

_ "github.com/go-shiori/shiori/docs" // docs is generated by Swag CLI, you have to import it.
_ "github.com/go-shiori/shiori/docs/swagger"
)

type SwaggerAPIRoutes struct {
Expand Down
4 changes: 4 additions & 0 deletions scripts/swagger.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

# This script is used to generate the swagger files for the API.
swag init --output=$SWAGGER_DOCS_PATH
Loading

0 comments on commit 8b015a3

Please sign in to comment.