Files
lingniu-vehicle-ingest/go/vehicle-gateway/internal/realtime/openapi.go
2026-07-02 18:41:23 +08:00

176 lines
6.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package realtime
import (
"encoding/json"
"net/http"
"strings"
)
func NewOpenAPIHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
writeError(w, http.StatusMethodNotAllowed, "method not allowed")
return
}
if strings.Trim(r.URL.Path, "/") != "openapi.json" {
writeError(w, http.StatusNotFound, "route not found")
return
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(realtimeOpenAPISpec())
})
}
func NewSwaggerUIHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
writeError(w, http.StatusMethodNotAllowed, "method not allowed")
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
_, _ = w.Write([]byte(swaggerHTML))
})
}
func realtimeOpenAPISpec() map[string]any {
return map[string]any{
"openapi": "3.0.3",
"info": map[string]any{
"title": "Lingniu Vehicle Realtime API",
"version": "1.0.0",
"description": "MySQL realtime query APIs for vehicle_realtime_snapshot and vehicle_realtime_location.",
},
"paths": map[string]any{
"/api/realtime/snapshots": map[string]any{
"get": map[string]any{
"summary": "查询车辆实时快照",
"description": "从 vehicle_realtime_snapshot 查询各协议最新在线快照支持协议、VIN、车牌过滤和分页。",
"tags": []string{"Realtime Snapshot API"},
"x-table": "vehicle_realtime_snapshot",
"parameters": commonRealtimeParameters(),
"responses": map[string]any{
"200": map[string]any{
"description": "Snapshot page",
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{"$ref": "#/components/schemas/SnapshotPage"},
},
},
},
},
},
},
"/api/realtime/locations": map[string]any{
"get": map[string]any{
"summary": "查询车辆实时位置",
"description": "从 vehicle_realtime_location 查询各协议最新位置支持协议、VIN、车牌过滤和分页。",
"tags": []string{"Realtime Location API"},
"x-table": "vehicle_realtime_location",
"parameters": commonRealtimeParameters(),
"responses": map[string]any{
"200": map[string]any{
"description": "Location page",
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{"$ref": "#/components/schemas/LocationPage"},
},
},
},
},
},
},
},
"components": map[string]any{
"schemas": map[string]any{
"SnapshotPage": pageSchema("#/components/schemas/SnapshotRow"),
"LocationPage": pageSchema("#/components/schemas/LocationRow"),
"SnapshotRow": map[string]any{
"type": "object",
"properties": map[string]any{
"protocol": stringSchema("GB32960"),
"vin": stringSchema("LB9A32A21R0LS1707"),
"plate": stringSchema("浙A12345"),
"event_time": stringSchema("2026-07-02 16:01:02.123"),
"received_at": stringSchema("2026-07-02 16:01:03.456"),
"event_id": stringSchema("event id"),
"created_at": stringSchema("2026-07-02 16:01:03"),
"updated_at": stringSchema("2026-07-02 16:01:04"),
},
},
"LocationRow": map[string]any{
"type": "object",
"properties": map[string]any{
"protocol": stringSchema("JT808"),
"vin": stringSchema("LKLG7C4E3NA774736"),
"plate": stringSchema("粤B98765"),
"event_time": stringSchema("2026-07-02 16:11:02.000"),
"latitude": numberSchema(30.123456),
"longitude": numberSchema(120.654321),
"speed_kmh": numberSchema(54.3),
"total_mileage_km": numberSchema(48798.9),
"soc_percent": numberSchema(81.5),
"altitude_m": numberSchema(19.0),
"direction_deg": numberSchema(88.0),
"alarm_flag": integerSchema(0),
"status_flag": integerSchema(3),
"received_at": stringSchema("2026-07-02 16:11:03.000"),
"event_id": stringSchema("event id"),
"created_at": stringSchema("2026-07-02 16:11:03"),
"updated_at": stringSchema("2026-07-02 16:11:04"),
},
},
},
},
}
}
func commonRealtimeParameters() []map[string]any {
return []map[string]any{
{"name": "protocol", "in": "query", "schema": map[string]any{"type": "string", "enum": []string{"GB32960", "JT808", "YUTONG_MQTT"}}, "required": false},
{"name": "vin", "in": "query", "schema": map[string]any{"type": "string"}, "required": false},
{"name": "plate", "in": "query", "schema": map[string]any{"type": "string"}, "required": false},
{"name": "limit", "in": "query", "schema": map[string]any{"type": "integer", "minimum": 1, "maximum": 1000, "default": 50}, "required": false},
{"name": "offset", "in": "query", "schema": map[string]any{"type": "integer", "minimum": 0, "maximum": 1000000, "default": 0}, "required": false},
}
}
func pageSchema(itemRef string) map[string]any {
return map[string]any{
"type": "object",
"properties": map[string]any{
"items": map[string]any{"type": "array", "items": map[string]any{"$ref": itemRef}},
"total": integerSchema(1),
"limit": integerSchema(50),
"offset": integerSchema(0),
},
}
}
func stringSchema(example string) map[string]any {
return map[string]any{"type": "string", "example": example}
}
func numberSchema(example float64) map[string]any {
return map[string]any{"type": "number", "example": example}
}
func integerSchema(example int64) map[string]any {
return map[string]any{"type": "integer", "example": example}
}
const swaggerHTML = `<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>Lingniu Vehicle Realtime API</title>
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css">
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
<script>
window.ui = SwaggerUIBundle({ url: "/openapi.json", dom_id: "#swagger-ui" });
</script>
</body>
</html>`