-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from Trendyol/feature/swagger
Feature/swagger
- Loading branch information
Showing
33 changed files
with
217,216 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package swagger | ||
|
||
import ( | ||
"reflect" | ||
"strings" | ||
|
||
"github.com/Trendyol/chaki/internal/typlect" | ||
"github.com/Trendyol/chaki/util/slc" | ||
) | ||
|
||
func buildDefinitions(eds []EndpointDef) m { | ||
defs := make(m) | ||
for _, ed := range eds { | ||
buildModelDefinition(defs, ed.RequestType, true) | ||
buildModelDefinition(defs, ed.ResponseType, false) | ||
} | ||
|
||
return defs | ||
|
||
} | ||
|
||
func buildModelDefinition(defs m, t reflect.Type, isReq bool) { | ||
if t == typlect.TypeNoParam { | ||
return | ||
} | ||
|
||
if t.Kind() == reflect.Slice { | ||
t = t.Elem() | ||
} | ||
|
||
if t.Kind() == reflect.Pointer { | ||
t = t.Elem() | ||
} | ||
|
||
if t.Kind() != reflect.Struct { | ||
return | ||
} | ||
|
||
var smr []string | ||
smp := m{} | ||
for i := 0; i < t.NumField(); i++ { | ||
var ( | ||
f = t.Field(i) | ||
ft = f.Type | ||
) | ||
|
||
// build subtype definitions | ||
if ft != typlect.TypeTime && ft.Kind() == reflect.Struct { | ||
buildModelDefinition(defs, ft, isReq) | ||
} | ||
|
||
if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Struct { | ||
buildModelDefinition(defs, ft.Elem(), isReq) | ||
} | ||
|
||
if !isReq || f.Tag.Get("json") != "" { | ||
smp[getFieldName(f)] = getPropertyField(f.Type) | ||
|
||
if vts, ok := f.Tag.Lookup("validate"); isReq && ok { | ||
if slc.Contains(strings.Split(vts, ","), "required") { | ||
smr = append(smr, getFieldName(f)) | ||
} | ||
} | ||
} | ||
} | ||
|
||
if len(smp) > 0 { | ||
mi := m{ | ||
"type": "object", | ||
"properties": smp, | ||
} | ||
|
||
if len(smr) > 0 { | ||
mi["required"] = smr | ||
} | ||
|
||
defs[getNameFromType(t)] = mi | ||
} | ||
|
||
} | ||
|
||
func getFieldName(f reflect.StructField) string { | ||
if tag := f.Tag.Get("json"); tag != "" { | ||
return strings.Split(tag, ",")[0] // ignore ',omitempty' | ||
} | ||
|
||
return f.Name | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
package swagger | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/Trendyol/chaki/internal/typlect" | ||
) | ||
|
||
type testStruct struct { | ||
Field1 string `json:"field1" validate:"required"` | ||
Field2 int `json:"field2"` | ||
Field3 anotherStruct `json:"field3"` | ||
Field4 []anotherStruct `json:"field4"` | ||
Field5 *string `json:"field5"` | ||
Field6 map[string]int `json:"field6" validate:"required"` | ||
} | ||
|
||
type anotherStruct struct { | ||
Field1 string `json:"field1"` | ||
Field2 []int `json:"field2"` | ||
} | ||
|
||
func TestBuildDefinitions(t *testing.T) { | ||
eds := []EndpointDef{ | ||
{ | ||
RequestType: reflect.TypeOf(testStruct{}), | ||
ResponseType: reflect.TypeOf(anotherStruct{}), | ||
}, | ||
{ | ||
RequestType: reflect.TypeOf(&testStruct{}), | ||
ResponseType: reflect.TypeOf(&anotherStruct{}), | ||
}, | ||
} | ||
|
||
defs := buildDefinitions(eds) | ||
|
||
if len(defs) != 2 { | ||
t.Errorf("Expected 2 definitions, got %d", len(defs)) | ||
} | ||
|
||
if _, ok := defs["testStruct"]; !ok { | ||
t.Errorf("Expected testStruct in definitions, not found") | ||
} | ||
|
||
if _, ok := defs["anotherStruct"]; !ok { | ||
t.Errorf("Expected anotherStruct in definitions, not found") | ||
} | ||
} | ||
|
||
func TestBuildModelDefinition(t *testing.T) { | ||
mockType := reflect.TypeOf(testStruct{}) | ||
defs := make(m) | ||
|
||
buildModelDefinition(defs, mockType, true) | ||
|
||
if len(defs) == 0 { | ||
t.Errorf("Expected definitions to be populated, got empty map") | ||
} | ||
|
||
if _, ok := defs["testStruct"]; !ok { | ||
t.Errorf("Expected testStruct in definitions, not found") | ||
} | ||
|
||
requiredFields := defs["testStruct"].(m)["required"].([]string) | ||
if !reflect.DeepEqual(requiredFields, []string{"field1", "field6"}) { | ||
t.Errorf("Expected required fields to be populated, got %+v", requiredFields) | ||
} | ||
|
||
if props, ok := defs["testStruct"].(m)["properties"]; ok { | ||
if p, ok := props.(m)["field1"]; !ok { | ||
t.Errorf("Expected field1 in properties, not found") | ||
} else { | ||
if fieldType, ok := p.(m)["type"]; !ok || fieldType != "string" { | ||
t.Errorf("Expected field1 to be of type string") | ||
} | ||
} | ||
if p, ok := props.(m)["field2"]; !ok { | ||
t.Errorf("Expected field2 in properties, not found") | ||
} else { | ||
if fieldType, ok := p.(m)["type"]; !ok || fieldType != "integer" { | ||
t.Errorf("Expected field2 to be of type integer") | ||
} | ||
} | ||
|
||
if p, ok := props.(m)["field3"]; !ok { | ||
t.Errorf("Expected Field3 in properties, not found") | ||
} else { | ||
if fieldType, ok := p.(m)["$ref"]; !ok || fieldType != "#/definitions/anotherStruct" { | ||
t.Errorf("Expected field3 to be of type ref") | ||
} | ||
} | ||
|
||
if p, ok := props.(m)["field4"]; !ok { | ||
t.Errorf("Expected field4 in properties, not found") | ||
} else { | ||
if fieldType, ok := p.(m)["type"]; !ok || fieldType != "array" { | ||
t.Errorf("Expected field4 to be of type array") | ||
} | ||
} | ||
|
||
if p, ok := props.(m)["field5"]; !ok { | ||
t.Errorf("Expected field5 in properties, not found") | ||
} else { | ||
if fieldType, ok := p.(m)["type"]; !ok || fieldType != "string" { | ||
t.Errorf("Expected field5 to be of type string") | ||
} | ||
} | ||
|
||
if p, ok := props.(m)["field6"]; !ok { | ||
t.Errorf("Expected field6 in properties, not found") | ||
} else { | ||
if fieldType, ok := p.(m)["type"]; !ok || fieldType != "map" { | ||
t.Errorf("Expected field6 to be of type map") | ||
} | ||
} | ||
} else { | ||
t.Errorf("Expected properties to be a map, got %T", defs["testStruct"].(m)["properties"]) | ||
} | ||
} | ||
|
||
func TestBuildModelDefinitions(t *testing.T) { | ||
|
||
tests := []struct { | ||
field reflect.Type | ||
len int | ||
name string | ||
}{ | ||
{typlect.TypeNoParam, 0, "no param"}, | ||
{reflect.TypeOf([]string{}), 0, "slice"}, | ||
|
||
// As test struct contains one inner struct, there should be 2 different definitions | ||
{reflect.TypeOf(&testStruct{}), 2, "pointer"}, | ||
{reflect.TypeOf(testStruct{}), 2, "struct"}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
|
||
defs := make(m) | ||
buildModelDefinition(defs, tt.field, true) | ||
|
||
if len(defs) != tt.len { | ||
t.Errorf("Expected %d definitions, got %d", tt.len, len(defs)) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestGetFieldName(t *testing.T) { | ||
tests := []struct { | ||
field reflect.StructField | ||
expected string | ||
}{ | ||
{reflect.StructField{Name: "Field1", Tag: `json:"field1"`}, "field1"}, | ||
{reflect.StructField{Name: "Field2", Tag: `json:"field2,omitempty"`}, "field2"}, | ||
{reflect.StructField{Name: "Field3"}, "Field3"}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.expected, func(t *testing.T) { | ||
if got := getFieldName(tt.field); got != tt.expected { | ||
t.Errorf("getFieldName() = %v, want %v", got, tt.expected) | ||
} | ||
}) | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package files | ||
|
||
import "embed" | ||
|
||
//go:embed * | ||
var Files embed.FS |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
html { | ||
box-sizing: border-box; | ||
overflow: -moz-scrollbars-vertical; | ||
overflow-y: scroll; | ||
} | ||
|
||
*, | ||
*:before, | ||
*:after { | ||
box-sizing: inherit; | ||
} | ||
|
||
body { | ||
margin: 0; | ||
background: #fafafa; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<!-- HTML for static distribution bundle build --> | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Swagger UI</title> | ||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" /> | ||
<link rel="stylesheet" type="text/css" href="./index.css" /> | ||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" /> | ||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" /> | ||
</head> | ||
|
||
<body> | ||
<div id="swagger-ui"></div> | ||
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script> | ||
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script> | ||
<script src="./swagger-initializer.js" charset="UTF-8"> </script> | ||
</body> | ||
</html> |
Oops, something went wrong.