MVP
This commit is contained in:
35
swagger/index.html
Normal file
35
swagger/index.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>API Documentation</title>
|
||||
<link rel="stylesheet" href="swagger-ui.css" />
|
||||
<!-- <link rel="stylesheet" href="themes/theme-feeling-blue.css" /> -->
|
||||
<!-- <link rel="stylesheet" href="themes/theme-flattop.css" /> -->
|
||||
<!-- <link rel="stylesheet" href="themes/theme-material.css" /> -->
|
||||
<!-- <link rel="stylesheet" href="themes/theme-monokai.css" /> -->
|
||||
<!-- <link rel="stylesheet" href="themes/theme-muted.css" /> -->
|
||||
<!-- <link rel="stylesheet" href="themes/theme-newspaper.css" /> -->
|
||||
<!-- <link rel="stylesheet" href="themes/theme-outline.css" /> -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="swagger-ui-bundle.js" crossorigin></script>
|
||||
<script src="swagger-ui-standalone-preset.js" crossorigin></script>
|
||||
<script>
|
||||
window.onload = () => {
|
||||
window.ui = SwaggerUIBundle({
|
||||
url: './swagger.json',
|
||||
dom_id: '#swagger-ui',
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
defaultModelsExpandDepth: 0,
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
3
swagger/swagger-ui-bundle.js
Normal file
3
swagger/swagger-ui-bundle.js
Normal file
File diff suppressed because one or more lines are too long
3
swagger/swagger-ui-standalone-preset.js
Normal file
3
swagger/swagger-ui-standalone-preset.js
Normal file
File diff suppressed because one or more lines are too long
4
swagger/swagger-ui.css
Normal file
4
swagger/swagger-ui.css
Normal file
File diff suppressed because one or more lines are too long
73
swagger/swagger.go
Normal file
73
swagger/swagger.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package swagger
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/ginext"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:embed *.html
|
||||
//go:embed *.json
|
||||
//go:embed *.yaml
|
||||
//go:embed *.js
|
||||
//go:embed *.css
|
||||
//go:embed themes/*
|
||||
var assets embed.FS
|
||||
|
||||
func getAsset(fn string) ([]byte, string, bool) {
|
||||
data, err := assets.ReadFile(fn)
|
||||
if err != nil {
|
||||
return nil, "", false
|
||||
}
|
||||
|
||||
mime := "text/plain"
|
||||
|
||||
lowerFN := strings.ToLower(fn)
|
||||
if strings.HasSuffix(lowerFN, ".html") || strings.HasSuffix(lowerFN, ".htm") {
|
||||
mime = "text/html"
|
||||
} else if strings.HasSuffix(lowerFN, ".css") {
|
||||
mime = "text/css"
|
||||
} else if strings.HasSuffix(lowerFN, ".js") {
|
||||
mime = "text/javascript"
|
||||
} else if strings.HasSuffix(lowerFN, ".json") {
|
||||
mime = "application/json"
|
||||
} else if strings.HasSuffix(lowerFN, ".jpeg") || strings.HasSuffix(lowerFN, ".jpg") {
|
||||
mime = "image/jpeg"
|
||||
} else if strings.HasSuffix(lowerFN, ".png") {
|
||||
mime = "image/png"
|
||||
} else if strings.HasSuffix(lowerFN, ".svg") {
|
||||
mime = "image/svg+xml"
|
||||
}
|
||||
|
||||
return data, mime, true
|
||||
}
|
||||
|
||||
func Handle(pctx ginext.PreContext) ginext.HTTPResponse {
|
||||
type uri struct {
|
||||
Filename string `uri:"sub"`
|
||||
}
|
||||
|
||||
var u uri
|
||||
|
||||
ctx, _, errResp := pctx.URI(&u).Start()
|
||||
if errResp != nil {
|
||||
return *errResp
|
||||
}
|
||||
defer ctx.Cancel()
|
||||
|
||||
u.Filename = strings.TrimLeft(u.Filename, "/")
|
||||
|
||||
if u.Filename == "" {
|
||||
index, _, _ := getAsset("index.html")
|
||||
return ginext.Data(http.StatusOK, "text/html", index)
|
||||
}
|
||||
|
||||
if data, mime, ok := getAsset(u.Filename); ok {
|
||||
return ginext.Data(http.StatusOK, mime, data)
|
||||
}
|
||||
|
||||
return ginext.JSON(http.StatusNotFound, gin.H{"error": "AssetNotFound", "filename": u.Filename})
|
||||
}
|
292
swagger/swagger.json
Normal file
292
swagger/swagger.json
Normal file
@@ -0,0 +1,292 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "LocalHostBunny",
|
||||
"contact": {},
|
||||
"version": "1.0"
|
||||
},
|
||||
"host": "localhost",
|
||||
"basePath": "/api/v1/",
|
||||
"paths": {
|
||||
"/api/health": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Common"
|
||||
],
|
||||
"summary": "Server Health-checks",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Health.response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.APIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/ping": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Common"
|
||||
],
|
||||
"summary": "Simple endpoint to test connection (any http method)",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.pingResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.APIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"tags": [
|
||||
"Common"
|
||||
],
|
||||
"summary": "Simple endpoint to test connection (any http method)",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.pingResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.APIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"Common"
|
||||
],
|
||||
"summary": "Simple endpoint to test connection (any http method)",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.pingResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.APIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Common"
|
||||
],
|
||||
"summary": "Simple endpoint to test connection (any http method)",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.pingResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.APIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"tags": [
|
||||
"Common"
|
||||
],
|
||||
"summary": "Simple endpoint to test connection (any http method)",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.pingResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.APIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/sleep/:secs": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Common"
|
||||
],
|
||||
"summary": "Return 200 after x seconds",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "number",
|
||||
"description": "sleep delay (in seconds)",
|
||||
"name": "secs",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Sleep.response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.APIError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.APIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/server": {
|
||||
"get": {
|
||||
"summary": "List running server",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.ListServer.response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.APIError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.APIError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"handler.Health.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.ListServer.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"server": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/models.Server"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Sleep.response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"duration": {
|
||||
"type": "number"
|
||||
},
|
||||
"end": {
|
||||
"type": "string"
|
||||
},
|
||||
"start": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.pingResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"info": {
|
||||
"$ref": "#/definitions/handler.pingResponseInfo"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.pingResponseInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"addr": {
|
||||
"type": "string"
|
||||
},
|
||||
"headers": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"method": {
|
||||
"type": "string"
|
||||
},
|
||||
"request": {
|
||||
"type": "string"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.APIError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"errorcode": {
|
||||
"type": "string"
|
||||
},
|
||||
"fapiMessage": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.Server": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"port": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
188
swagger/swagger.yaml
Normal file
188
swagger/swagger.yaml
Normal file
@@ -0,0 +1,188 @@
|
||||
basePath: /api/v1/
|
||||
definitions:
|
||||
handler.Health.response:
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
handler.ListServer.response:
|
||||
properties:
|
||||
server:
|
||||
items:
|
||||
$ref: '#/definitions/models.Server'
|
||||
type: array
|
||||
type: object
|
||||
handler.Sleep.response:
|
||||
properties:
|
||||
duration:
|
||||
type: number
|
||||
end:
|
||||
type: string
|
||||
start:
|
||||
type: string
|
||||
type: object
|
||||
handler.pingResponse:
|
||||
properties:
|
||||
info:
|
||||
$ref: '#/definitions/handler.pingResponseInfo'
|
||||
message:
|
||||
type: string
|
||||
type: object
|
||||
handler.pingResponseInfo:
|
||||
properties:
|
||||
addr:
|
||||
type: string
|
||||
headers:
|
||||
additionalProperties:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
method:
|
||||
type: string
|
||||
request:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
type: object
|
||||
models.APIError:
|
||||
properties:
|
||||
errorcode:
|
||||
type: string
|
||||
fapiMessage:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
type: object
|
||||
models.Server:
|
||||
properties:
|
||||
port:
|
||||
type: integer
|
||||
type: object
|
||||
host: localhost
|
||||
info:
|
||||
contact: {}
|
||||
title: LocalHostBunny
|
||||
version: "1.0"
|
||||
paths:
|
||||
/api/health:
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Health.response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/models.APIError'
|
||||
summary: Server Health-checks
|
||||
tags:
|
||||
- Common
|
||||
/api/ping:
|
||||
delete:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.pingResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/models.APIError'
|
||||
summary: Simple endpoint to test connection (any http method)
|
||||
tags:
|
||||
- Common
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.pingResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/models.APIError'
|
||||
summary: Simple endpoint to test connection (any http method)
|
||||
tags:
|
||||
- Common
|
||||
patch:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.pingResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/models.APIError'
|
||||
summary: Simple endpoint to test connection (any http method)
|
||||
tags:
|
||||
- Common
|
||||
post:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.pingResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/models.APIError'
|
||||
summary: Simple endpoint to test connection (any http method)
|
||||
tags:
|
||||
- Common
|
||||
put:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.pingResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/models.APIError'
|
||||
summary: Simple endpoint to test connection (any http method)
|
||||
tags:
|
||||
- Common
|
||||
/api/sleep/:secs:
|
||||
post:
|
||||
parameters:
|
||||
- description: sleep delay (in seconds)
|
||||
in: path
|
||||
name: secs
|
||||
required: true
|
||||
type: number
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Sleep.response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/models.APIError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/models.APIError'
|
||||
summary: Return 200 after x seconds
|
||||
tags:
|
||||
- Common
|
||||
/server:
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.ListServer.response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/models.APIError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/models.APIError'
|
||||
summary: List running server
|
||||
swagger: "2.0"
|
1672
swagger/themes/theme-feeling-blue.css
Normal file
1672
swagger/themes/theme-feeling-blue.css
Normal file
File diff suppressed because it is too large
Load Diff
1672
swagger/themes/theme-flattop.css
Normal file
1672
swagger/themes/theme-flattop.css
Normal file
File diff suppressed because it is too large
Load Diff
1719
swagger/themes/theme-material.css
Normal file
1719
swagger/themes/theme-material.css
Normal file
File diff suppressed because it is too large
Load Diff
1792
swagger/themes/theme-monokai.css
Normal file
1792
swagger/themes/theme-monokai.css
Normal file
File diff suppressed because it is too large
Load Diff
1673
swagger/themes/theme-muted.css
Normal file
1673
swagger/themes/theme-muted.css
Normal file
File diff suppressed because it is too large
Load Diff
1671
swagger/themes/theme-newspaper.css
Normal file
1671
swagger/themes/theme-newspaper.css
Normal file
File diff suppressed because it is too large
Load Diff
1652
swagger/themes/theme-outline.css
Normal file
1652
swagger/themes/theme-outline.css
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user