package server
import (
"database/sql"
"encoding/json"
"html/template"
"net/http"
"github.com/gin-gonic/gin"
"opsxapi/server/internal/store"
)
type sharedDocument struct {
Name string `json:"name"`
Endpoints []struct {
Method string `json:"method"`
Path string `json:"path"`
Name string `json:"name"`
Description string `json:"description"`
Parameters []struct {
Name string `json:"name"`
In string `json:"in"`
Required bool `json:"required"`
Description string `json:"description"`
Example string `json:"example"`
} `json:"parameters"`
RequestBody *struct {
ContentType string `json:"contentType"`
Example string `json:"example"`
} `json:"requestBody"`
Responses []struct {
Status string `json:"status"`
Description string `json:"description"`
ContentType string `json:"contentType"`
Example string `json:"example"`
} `json:"responses"`
MockURL string `json:"mockUrl"`
} `json:"endpoints"`
}
var sharedDocsTemplate = template.Must(template.New("docs").Parse(`
{{.Name}} · API 文档{{.Name}}
自托管 API 文档 · 只读快照{{range $i,$e:=.Endpoints}}{{$e.Name}}
{{$e.Method}} {{$e.Path}}
{{$e.Description}}
{{if $e.Parameters}}请求参数
| 参数 | 位置 | 必填 | 示例 | 说明 |
{{range $e.Parameters}}| {{.Name}} | {{.In}} | {{if .Required}}是{{else}}否{{end}} | {{.Example}} | {{.Description}} |
{{end}}
{{end}}{{with $e.RequestBody}}请求体 · {{.ContentType}}
{{.Example}}{{end}}{{range $e.Responses}}HTTP {{.Status}} · {{.ContentType}}
{{.Description}}
{{.Example}}{{end}}{{if $e.MockURL}}Mock 地址
{{$e.MockURL}}
{{end}}{{end}}`))
func registerSharedDocs(r *gin.Engine, s *store.Store) {
r.GET("/docs/:token", func(c *gin.Context) {
record, err := s.PublishedDocByToken(c.Param("token"))
if err == sql.ErrNoRows {
c.AbortWithStatus(404)
return
}
if err != nil {
c.AbortWithStatus(500)
return
}
var doc sharedDocument
if json.Unmarshal([]byte(record.Content), &doc) != nil {
c.AbortWithStatus(500)
return
}
c.Header("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'")
c.Header("X-Content-Type-Options", "nosniff")
c.Status(http.StatusOK)
c.Header("Content-Type", "text/html; charset=utf-8")
_ = sharedDocsTemplate.Execute(c.Writer, doc)
})
}