Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swagger spec gen #159

Merged
merged 16 commits into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions cmd/swaggergen/content.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import "net/http"

// Content represents a content in the spec
type Content struct {
Schema *Schema `json:"schema,omitempty" yaml:"schema,omitempty"`
}

// NewContent creates a new content
func NewContent(res *http.Response) *Content {
var content *Content
if res.Body != nil {
content = &Content{
Schema: NewSchema(res.Body),
}
}
return content
}

// UpdateContent updates a content
func (c *Content) UpdateContent(res *http.Response) {
if res.Body != nil {
c.Schema = NewSchema(res.Body)
}
}
15 changes: 15 additions & 0 deletions cmd/swaggergen/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

type Info struct {
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Version string `json:"version,omitempty" yaml:"version,omitempty"`
}

// NewInfo creates a new info
func NewInfo(title string) *Info {
return &Info{
Title: title,
Version: "1.0.0",
}
}
34 changes: 34 additions & 0 deletions cmd/swaggergen/method.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

// Operation represents an operation in the spec
type Method struct {
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
Responses map[int]*Response `json:"responses,omitempty" yaml:"responses,omitempty"`
Parameters []*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
}

// NewMethod creates a new method
func NewMethod(reqRes RequestResponse) *Method {
method := &Method{
Responses: map[int]*Response{},
Parameters: NewParameters(reqRes.Request),
}
if reqRes.Response != nil {
method.Responses = map[int]*Response{
reqRes.Response.StatusCode: NewResponse(reqRes.Response),
}
}
return method
}

// UpdateMethod updates a method
func (m *Method) UpdateMethod(reqRes RequestResponse) {
if reqRes.Response != nil {
if _, ok := m.Responses[reqRes.Response.StatusCode]; !ok {
m.Responses[reqRes.Response.StatusCode] = NewResponse(reqRes.Response)
} else {
m.Responses[reqRes.Response.StatusCode].UpdateResponse(reqRes.Response)
}
}
m.Parameters = NewParameters(reqRes.Request)
}
42 changes: 42 additions & 0 deletions cmd/swaggergen/parameter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package main

import "net/http"

// Parameter represents a parameter in the spec
type Parameter struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
In string `json:"in,omitempty" yaml:"in,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
Schema *Schema `json:"schema,omitempty" yaml:"schema,omitempty"`
}

// NewParameters creates a new parameters
func NewParameters(req *http.Request) []*Parameter {
var params []*Parameter
if req.Body != nil {
// add body parameter
Schema := NewSchema(req.Body)
if Schema != nil {
params = append(params, &Parameter{
Name: "body",
In: "body",
Required: true,
Schema: Schema,
})
}
}
// get request query parameters
reqParams := req.URL.Query()
// add query parameters
for key, value := range reqParams {
params = append(params, &Parameter{
Name: key,
In: "query",
Schema: &Schema{Type: "string"},
Description: value[0],
Required: true,
})
}
return params
}
24 changes: 24 additions & 0 deletions cmd/swaggergen/path.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"strings"
)

// Path represents a path in the spec
type Path map[string]*Method

// NewPath creates a new path
func NewPath(reqRes RequestResponse) Path {
return map[string]*Method{
strings.ToLower(reqRes.Request.Method): NewMethod(reqRes),
}
}

// UpdatePath updates a path
func (p Path) UpdatePath(reqRes RequestResponse) {
if _, ok := p[strings.ToLower(reqRes.Request.Method)]; !ok {
p[strings.ToLower(reqRes.Request.Method)] = NewMethod(reqRes)
} else {
p[strings.ToLower(reqRes.Request.Method)].UpdateMethod(reqRes)
}
}
33 changes: 33 additions & 0 deletions cmd/swaggergen/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import "net/http"

// Response represents a response in the spec
type Response struct {
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Content map[string]*Content `json:"content,omitempty" yaml:"content,omitempty"`
}

// NewResponse creates a new response
func NewResponse(res *http.Response) *Response {
var response *Response
if res.Header != nil {
response = &Response{
Content: map[string]*Content{
res.Header.Get("Content-Type"): NewContent(res),
},
}
}
return response
}

// UpdateResponse updates a response
func (r *Response) UpdateResponse(res *http.Response) {
if res.Header != nil {
if _, ok := r.Content[res.Header.Get("Content-Type")]; !ok {
r.Content[res.Header.Get("Content-Type")] = NewContent(res)
} else {
r.Content[res.Header.Get("Content-Type")].UpdateContent(res)
}
}
}
57 changes: 57 additions & 0 deletions cmd/swaggergen/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package main

import (
"encoding/json"
"io"
"io/ioutil"
)

// Schema represents a schema in the spec
type Schema struct {
Type string `json:"type" yaml:"type"`
Properties map[string]*Schema `json:"properties,omitempty" yaml:"properties,omitempty"`
Description string `json:"description" yaml:"description,omitempty"`
}

func NewSchema(reader io.Reader) *Schema {
body, err := ioutil.ReadAll(reader)
if err != nil {
return nil
}
var data interface{}
if err := json.Unmarshal(body, &data); err != nil {
return nil
}

dataType := InterfaceToType(data)
// generate shema from data map
schema := &Schema{
Type: dataType,
}
if dataType == "object" {
schema.Properties = make(map[string]*Schema)
for key, value := range data.(map[string]interface{}) {
schema.Properties[key] = &Schema{
Type: InterfaceToType(value),
}
}
}
return schema
}

func InterfaceToType(data interface{}) string {
switch data.(type) {
case map[string]interface{}:
return "object"
case []interface{}:
return "array"
case string:
return "string"
case float64:
return "number"
case bool:
return "boolean"
default:
return "notfound"
}
}
14 changes: 14 additions & 0 deletions cmd/swaggergen/servers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

type Server struct {
URL string `json:"url,omitempty" yaml:"url,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
}

// NewServer creates a new server
func NewServer(url, description string) *Server {
return &Server{
URL: url,
Description: description,
}
}
31 changes: 31 additions & 0 deletions cmd/swaggergen/spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

const OpenApiVersion = "3.0.0"

// Spec represents openapi 3 specification
type Spec struct {
OpenApi string `json:"openapi"`
Info *Info `json:"info"`
Servers []*Server `json:"servers"`
Paths map[string]Path `json:"paths"`
}

// NewSpec creates a new spec
func NewSpec(logDir, api string) *Spec {
return &Spec{
OpenApi: OpenApiVersion,
Info: NewInfo(logDir),
Servers: []*Server{NewServer(api, "")},
Paths: map[string]Path{},
}
}

// AddRequest adds a request to the spec
func (s *Spec) AddPath(reqRes RequestResponse) {
path := reqRes.Request.URL.Path
if _, ok := s.Paths[path]; !ok {
s.Paths[path] = NewPath(reqRes)
} else {
s.Paths[path].UpdatePath(reqRes)
}
}
Loading