feat(db): add swagger doc
Assisted-by: Junie:gemini-3-flash Signed-off-by: Klagarge <remi@heredero.ch>
This commit is contained in:
@@ -18,5 +18,13 @@ cp .env.template .env
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Swagger Documentation
|
||||
|
||||
```bash
|
||||
swag init
|
||||
```
|
||||
|
||||
## Traefik
|
||||
A traefik config file is available on [traefik.yml](./traefik.yml). It can be used with an OIDC provider ([Authentik](https://github.com/goauthentik/authentik) in our case) to control access to the database explorer.
|
||||
|
||||
159
db/src/docs/docs.go
Normal file
159
db/src/docs/docs.go
Normal file
@@ -0,0 +1,159 @@
|
||||
// Package docs Code generated by swaggo/swag. DO NOT EDIT
|
||||
package docs
|
||||
|
||||
import "github.com/swaggo/swag"
|
||||
|
||||
const docTemplate = `{
|
||||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "{{escape .Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"contact": {},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/rooms": {
|
||||
"get": {
|
||||
"description": "Get a list of all unique rooms from the measurement",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"rooms"
|
||||
],
|
||||
"summary": "Get all unique rooms",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/rooms/{room-id}/current": {
|
||||
"get": {
|
||||
"description": "Get the latest record for a specific room",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"rooms"
|
||||
],
|
||||
"summary": "Get current data for a room",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Room ID",
|
||||
"name": "room-id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/rooms/{room-id}/history": {
|
||||
"get": {
|
||||
"description": "Get history for a specific room",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"rooms"
|
||||
],
|
||||
"summary": "Get history for a room",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Room ID",
|
||||
"name": "room-id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = &swag.Spec{
|
||||
Version: "1.0",
|
||||
Host: "doc.db.e.kb28.ch",
|
||||
BasePath: "/api/v1",
|
||||
Schemes: []string{},
|
||||
Title: "Gateway API",
|
||||
Description: "This is a gateway API for IoT data.",
|
||||
InfoInstanceName: "swagger",
|
||||
SwaggerTemplate: docTemplate,
|
||||
LeftDelim: "{{",
|
||||
RightDelim: "}}",
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
||||
}
|
||||
135
db/src/docs/swagger.json
Normal file
135
db/src/docs/swagger.json
Normal file
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "This is a gateway API for IoT data.",
|
||||
"title": "Gateway API",
|
||||
"contact": {},
|
||||
"version": "1.0"
|
||||
},
|
||||
"host": "doc.db.e.kb28.ch",
|
||||
"basePath": "/api/v1",
|
||||
"paths": {
|
||||
"/rooms": {
|
||||
"get": {
|
||||
"description": "Get a list of all unique rooms from the measurement",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"rooms"
|
||||
],
|
||||
"summary": "Get all unique rooms",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/rooms/{room-id}/current": {
|
||||
"get": {
|
||||
"description": "Get the latest record for a specific room",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"rooms"
|
||||
],
|
||||
"summary": "Get current data for a room",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Room ID",
|
||||
"name": "room-id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/rooms/{room-id}/history": {
|
||||
"get": {
|
||||
"description": "Get history for a specific room",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"rooms"
|
||||
],
|
||||
"summary": "Get history for a room",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Room ID",
|
||||
"name": "room-id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
90
db/src/docs/swagger.yaml
Normal file
90
db/src/docs/swagger.yaml
Normal file
@@ -0,0 +1,90 @@
|
||||
basePath: /api/v1
|
||||
host: doc.db.e.kb28.ch
|
||||
info:
|
||||
contact: {}
|
||||
description: This is a gateway API for IoT data.
|
||||
title: Gateway API
|
||||
version: "1.0"
|
||||
paths:
|
||||
/rooms:
|
||||
get:
|
||||
description: Get a list of all unique rooms from the measurement
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: Get all unique rooms
|
||||
tags:
|
||||
- rooms
|
||||
/rooms/{room-id}/current:
|
||||
get:
|
||||
description: Get the latest record for a specific room
|
||||
parameters:
|
||||
- description: Room ID
|
||||
in: path
|
||||
name: room-id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: Get current data for a room
|
||||
tags:
|
||||
- rooms
|
||||
/rooms/{room-id}/history:
|
||||
get:
|
||||
description: Get history for a specific room
|
||||
parameters:
|
||||
- description: Room ID
|
||||
in: path
|
||||
name: room-id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
type: array
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: Get history for a room
|
||||
tags:
|
||||
- rooms
|
||||
swagger: "2.0"
|
||||
@@ -11,6 +11,9 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/apache/arrow-go/v18 v18.5.1 // indirect
|
||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||
github.com/bytedance/sonic v1.15.0 // indirect
|
||||
@@ -19,6 +22,10 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.30.1 // indirect
|
||||
@@ -27,10 +34,12 @@ require (
|
||||
github.com/google/flatbuffers v25.12.19+incompatible // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/influxdata/line-protocol/v2 v2.2.1 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.18.2 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
@@ -40,6 +49,9 @@ require (
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
github.com/quic-go/quic-go v0.59.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/swaggo/files v1.0.1 // indirect
|
||||
github.com/swaggo/gin-swagger v1.6.1 // indirect
|
||||
github.com/swaggo/swag v1.16.4 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.3.1 // indirect
|
||||
github.com/zeebo/xxh3 v1.0.2 // indirect
|
||||
@@ -58,5 +70,6 @@ require (
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||
google.golang.org/grpc v1.79.1 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -93,6 +93,11 @@ func influxConnection() *influx.InfluxGateway {
|
||||
return gateway
|
||||
}
|
||||
|
||||
// @title Gateway API
|
||||
// @version 1.0
|
||||
// @description This is a gateway API for IoT data.
|
||||
// @host doc.db.e.kb28.ch
|
||||
// @BasePath /api/v1
|
||||
func main() {
|
||||
// Load mapping configuration
|
||||
mappingPath := os.Getenv("MAPPING_CONFIG_PATH")
|
||||
|
||||
@@ -6,7 +6,11 @@ import (
|
||||
"gateway/influx"
|
||||
"net/http"
|
||||
|
||||
_ "gateway/docs"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
)
|
||||
|
||||
type RestGateway struct {
|
||||
@@ -33,6 +37,8 @@ func (g *RestGateway) setupRoutes() {
|
||||
v1.GET("/rooms/:room-id/current", g.getRoomCurrent)
|
||||
v1.GET("/rooms/:room-id/history", g.getRoomHistory)
|
||||
}
|
||||
|
||||
g.engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
}
|
||||
|
||||
func (g *RestGateway) Run(addr string) error {
|
||||
@@ -40,6 +46,14 @@ func (g *RestGateway) Run(addr string) error {
|
||||
}
|
||||
|
||||
// GET /api/v1/rooms
|
||||
// getRooms godoc
|
||||
// @Summary Get all unique rooms
|
||||
// @Description Get a list of all unique rooms from the measurement
|
||||
// @Tags rooms
|
||||
// @Produce json
|
||||
// @Success 200 {array} string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /rooms [get]
|
||||
func (g *RestGateway) getRooms(c *gin.Context) {
|
||||
// Query unique rooms from the measurement
|
||||
query := fmt.Sprintf(`SELECT DISTINCT("room") FROM "%s"`, g.measurementName)
|
||||
@@ -68,6 +82,16 @@ func (g *RestGateway) getRooms(c *gin.Context) {
|
||||
}
|
||||
|
||||
// GET /api/v1/rooms/{room-id}/current
|
||||
// getRoomCurrent godoc
|
||||
// @Summary Get current data for a room
|
||||
// @Description Get the latest record for a specific room
|
||||
// @Tags rooms
|
||||
// @Produce json
|
||||
// @Param room-id path string true "Room ID"
|
||||
// @Success 200 {object} map[string]any
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /rooms/{room-id}/current [get]
|
||||
func (g *RestGateway) getRoomCurrent(c *gin.Context) {
|
||||
roomID := c.Param("room-id")
|
||||
|
||||
@@ -95,6 +119,15 @@ func (g *RestGateway) getRoomCurrent(c *gin.Context) {
|
||||
}
|
||||
|
||||
// GET /api/v1/rooms/{room-id}/history
|
||||
// getRoomHistory godoc
|
||||
// @Summary Get history for a room
|
||||
// @Description Get history for a specific room
|
||||
// @Tags rooms
|
||||
// @Produce json
|
||||
// @Param room-id path string true "Room ID"
|
||||
// @Success 200 {array} map[string]any
|
||||
// @Failure 500 {object} map[string]string
|
||||
// @Router /rooms/{room-id}/history [get]
|
||||
func (g *RestGateway) getRoomHistory(c *gin.Context) {
|
||||
roomID := c.Param("room-id")
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
http:
|
||||
middlewares:
|
||||
pi-db-doc-redirect:
|
||||
redirectRegex:
|
||||
regex: "^https://doc.db.e.kb28.ch/$"
|
||||
replacement: "https://doc.db.e.kb28.ch/swagger/index.html"
|
||||
# middlewares:
|
||||
# oidc-auth-pi-db:
|
||||
# plugin:
|
||||
@@ -33,6 +38,15 @@ http:
|
||||
service: pi-mqtt-management
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
pi-db-doc:
|
||||
rule: "Host(`doc.db.e.kb28.ch`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: pi-db-doc
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- pi-db-doc-redirect
|
||||
|
||||
services:
|
||||
pi-db-ui:
|
||||
@@ -50,6 +64,11 @@ http:
|
||||
servers:
|
||||
- url: "http://192.168.42.211:15672"
|
||||
passHostHeader: true
|
||||
pi-db-doc:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://192.168.42.211:8080"
|
||||
passHostHeader: true
|
||||
|
||||
tcp:
|
||||
routers:
|
||||
|
||||
Reference in New Issue
Block a user