Commit 308fe1fd authored by robwa's avatar robwa
Browse files

feat: Add api doc example with swaggo/swag

* based on 2dba85db
* build with `make api-docs`
* Swagger UI available at `/api/docs/index.html`
parent f7109bfc
/tank /tank
/tank.yaml
/vendor/ /vendor/
/cover.out /cover.out
/coverage.html /coverage.html
/api/docs/swagger.*
\ No newline at end of file
...@@ -21,6 +21,11 @@ ifdef GOROOT ...@@ -21,6 +21,11 @@ ifdef GOROOT
GOCMD = $(GOROOT)/bin/go GOCMD = $(GOROOT)/bin/go
endif endif
SWAG := swag
ifdef GOPATH
SWAG = $(GOPATH)/bin/swag
endif
EXECUTEABLE := tank EXECUTEABLE := tank
all: build all: build
...@@ -35,6 +40,9 @@ format: ...@@ -35,6 +40,9 @@ format:
ui: ui:
$(GOCMD) generate ./ui $(GOCMD) generate ./ui
api-docs:
$(SWAG) init -d api/v1/,./ -g api.go -o api/docs
build: ui build: ui
$(GOCMD) build -o $(EXECUTEABLE) ./cmd/tank $(GOCMD) build -o $(EXECUTEABLE) ./cmd/tank
......
// Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag
package docs
import "github.com/swaggo/swag"
const docTemplate = `{
"schemes": {{ marshal .Schemes }},
"swagger": "2.0",
"info": {
"description": "{{escape .Description}}",
"title": "{{.Title}}",
"contact": {
"url": "https://gitlab.servus.at/autoradio/tank"
},
"license": {
"name": "GPL 3",
"url": "https://www.gnu.org/licenses/gpl"
},
"version": "{{.Version}}"
},
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/api/v1/shows": {
"get": {
"description": "Lists all existing shows",
"produces": [
"application/json"
],
"summary": "List shows",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/gitlab.servus.at_autoradio_tank_api_v1.ShowsListing"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/gitlab.servus.at_autoradio_tank_api_v1.ErrorResponse"
}
}
}
}
},
"/api/v1/shows/{id}": {
"post": {
"description": "Creates a new show",
"produces": [
"application/json"
],
"summary": "Create show",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/store.Show"
}
},
"403": {
"description": "Forbidden",
"schema": {
"$ref": "#/definitions/gitlab.servus.at_autoradio_tank_api_v1.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/gitlab.servus.at_autoradio_tank_api_v1.ErrorResponse"
}
}
}
},
"delete": {
"description": "Deletes a show",
"produces": [
"application/json"
],
"summary": "Delete show",
"responses": {
"204": {
"description": ""
},
"403": {
"description": "Forbidden",
"schema": {
"$ref": "#/definitions/gitlab.servus.at_autoradio_tank_api_v1.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/gitlab.servus.at_autoradio_tank_api_v1.ErrorResponse"
}
}
}
}
}
},
"definitions": {
"api_v1.ErrorResponse": {
"type": "object",
"properties": {
"detail": {},
"error": {
"type": "string"
}
}
},
"api_v1.ShowsListing": {
"type": "object",
"properties": {
"results": {
"type": "array",
"items": {
"$ref": "#/definitions/store.Show"
}
}
}
},
"gitlab.servus.at_autoradio_tank_api_v1.ErrorResponse": {
"type": "object",
"properties": {
"detail": {},
"error": {
"type": "string"
}
}
},
"gitlab.servus.at_autoradio_tank_api_v1.ShowsListing": {
"type": "object",
"properties": {
"results": {
"type": "array",
"items": {
"$ref": "#/definitions/store.Show"
}
}
}
},
"store.Show": {
"type": "object",
"properties": {
"created": {
"type": "string"
},
"name": {
"type": "string"
},
"updated": {
"type": "string"
}
}
}
},
"securityDefinitions": {
"ApiKeyAuth": {
"type": "apiKey",
"name": "Authorization",
"in": "header"
}
}
}`
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
Version: "1.0",
Host: "",
BasePath: "",
Schemes: []string{},
Title: "AURA Tank API",
Description: "Import & Playlist Daemon",
InfoInstanceName: "swagger",
SwaggerTemplate: docTemplate,
}
func init() {
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
}
...@@ -28,6 +28,18 @@ import ( ...@@ -28,6 +28,18 @@ import (
"gitlab.servus.at/autoradio/tank/store" "gitlab.servus.at/autoradio/tank/store"
) )
// @title AURA Tank API
// @version 1.0
// @description Import & Playlist Daemon
// @contact.url https://gitlab.servus.at/autoradio/tank
// @license.name GPL 3
// @license.url https://www.gnu.org/licenses/gpl
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization
type API struct { type API struct {
store *store.Store store *store.Store
importer *importer.Importer importer *importer.Importer
......
...@@ -26,6 +26,14 @@ import ( ...@@ -26,6 +26,14 @@ import (
"gitlab.servus.at/autoradio/tank/store" "gitlab.servus.at/autoradio/tank/store"
) )
// ListShows returns a list of all shows that are accessible to the current session.
// If authentication is disabled a least of all existing shows is returned.
// @Summary List shows
// @Description Lists all existing shows
// @Produce json
// @Success 200 {object} ShowsListing
// @Failure 500 {object} ErrorResponse
// @Router /api/v1/shows [get]
func (api *API) ListShows(c *gin.Context) { func (api *API) ListShows(c *gin.Context) {
offset, limit, ok := getPaginationParameter(c) offset, limit, ok := getPaginationParameter(c)
if !ok { if !ok {
...@@ -72,6 +80,14 @@ func (api *API) ListShows(c *gin.Context) { ...@@ -72,6 +80,14 @@ func (api *API) ListShows(c *gin.Context) {
c.JSON(http.StatusOK, ShowsListing{Shows: shows}) c.JSON(http.StatusOK, ShowsListing{Shows: shows})
} }
// CreateShow creates a new show.
// @Summary Create show
// @Description Creates a new show
// @Produce json
// @Success 200 {object} store.Show
// @Failure 403 {object} ErrorResponse
// @Failure 500 {object} ErrorResponse
// @Router /api/v1/shows/{id} [post]
func (api *API) CreateShow(c *gin.Context) { func (api *API) CreateShow(c *gin.Context) {
showID := c.Param("show-id") showID := c.Param("show-id")
if authorized, _ := authorizeRequestForShow(c, showID); !authorized { if authorized, _ := authorizeRequestForShow(c, showID); !authorized {
...@@ -97,6 +113,14 @@ func (api *API) CreateShow(c *gin.Context) { ...@@ -97,6 +113,14 @@ func (api *API) CreateShow(c *gin.Context) {
c.JSON(http.StatusCreated, show) c.JSON(http.StatusCreated, show)
} }
// DeleteShow deletes a show.
// @Summary Delete show
// @Description Deletes a show
// @Produce json
// @Success 204
// @Failure 403 {object} ErrorResponse
// @Failure 500 {object} ErrorResponse
// @Router /api/v1/shows/{id} [delete]
func (api *API) DeleteShow(c *gin.Context) { func (api *API) DeleteShow(c *gin.Context) {
showID := c.Param("show-id") showID := c.Param("show-id")
if authorized, s := authorizeRequestForShow(c, showID); !authorized { if authorized, s := authorizeRequestForShow(c, showID); !authorized {
......
...@@ -30,6 +30,9 @@ import ( ...@@ -30,6 +30,9 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
cors "github.com/rs/cors/wrapper/gin" cors "github.com/rs/cors/wrapper/gin"
"github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
_ "gitlab.servus.at/autoradio/tank/api/docs"
apiV1 "gitlab.servus.at/autoradio/tank/api/v1" apiV1 "gitlab.servus.at/autoradio/tank/api/v1"
"gitlab.servus.at/autoradio/tank/auth" "gitlab.servus.at/autoradio/tank/auth"
"gitlab.servus.at/autoradio/tank/importer" "gitlab.servus.at/autoradio/tank/importer"
...@@ -38,10 +41,11 @@ import ( ...@@ -38,10 +41,11 @@ import (
) )
const ( const (
WebUIPathPrefix = "/ui/" WebUIPathPrefix = "/ui/"
WebAuthPrefix = "/auth/" WebAuthPrefix = "/auth/"
WebAPIv1Prefix = "/api/v1/" WebAPIDocsPrefix = "/api/docs/"
HealthzEndpoint = "/healthz" WebAPIv1Prefix = "/api/v1/"
HealthzEndpoint = "/healthz"
) )
func apache2CombinedLogger(param gin.LogFormatterParams) string { func apache2CombinedLogger(param gin.LogFormatterParams) string {
...@@ -161,6 +165,7 @@ func runWeb(ln net.Listener, st *store.Store, im *importer.Importer, conf WebCon ...@@ -161,6 +165,7 @@ func runWeb(ln net.Listener, st *store.Store, im *importer.Importer, conf WebCon
apiV1.InstallHTTPHandler(r.Group(WebAPIv1Prefix), st, im, infoLog, errLog, dbgLog) apiV1.InstallHTTPHandler(r.Group(WebAPIv1Prefix), st, im, infoLog, errLog, dbgLog)
auth.InstallHTTPHandler(r.Group(WebAuthPrefix)) auth.InstallHTTPHandler(r.Group(WebAuthPrefix))
r.GET(HealthzEndpoint, func(c *gin.Context) { healthzHandler(c, st, im) }) r.GET(HealthzEndpoint, func(c *gin.Context) { healthzHandler(c, st, im) })
r.GET(WebAPIDocsPrefix+"*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
srv := &http.Server{ srv := &http.Server{
Handler: r, Handler: r,
......
...@@ -6,15 +6,16 @@ require ( ...@@ -6,15 +6,16 @@ require (
github.com/codegangsta/cli v1.20.0 github.com/codegangsta/cli v1.20.0
github.com/coreos/go-oidc v2.0.0+incompatible github.com/coreos/go-oidc v2.0.0+incompatible
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7
github.com/gin-gonic/gin v1.4.0 github.com/gin-gonic/gin v1.7.7
github.com/jinzhu/gorm v1.9.8 github.com/jinzhu/gorm v1.9.8
github.com/kr/pretty v0.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/rs/cors v1.6.0 github.com/rs/cors v1.6.0
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect github.com/swaggo/gin-swagger v1.4.1
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd // indirect github.com/swaggo/swag v1.8.0
golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914 golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914
gopkg.in/gormigrate.v1 v1.5.0 gopkg.in/gormigrate.v1 v1.5.0
gopkg.in/square/go-jose.v2 v2.3.0 // indirect gopkg.in/square/go-jose.v2 v2.3.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
) )
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment