#2 - add swaggerset #8
@ -7,7 +7,6 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
openapi_v3 "github.com/google/gnostic/openapiv3"
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
grpccli "go.unistack.org/micro-client-grpc/v3"
|
grpccli "go.unistack.org/micro-client-grpc/v3"
|
||||||
httpcli "go.unistack.org/micro-client-http/v3"
|
httpcli "go.unistack.org/micro-client-http/v3"
|
||||||
@ -31,6 +30,7 @@ import (
|
|||||||
"go.unistack.org/servicechecker/pkg/httpconn"
|
"go.unistack.org/servicechecker/pkg/httpconn"
|
||||||
"go.unistack.org/servicechecker/pkg/protoset"
|
"go.unistack.org/servicechecker/pkg/protoset"
|
||||||
"go.unistack.org/servicechecker/pkg/scheduler"
|
"go.unistack.org/servicechecker/pkg/scheduler"
|
||||||
|
"go.unistack.org/servicechecker/pkg/swaggerset"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -213,8 +213,10 @@ func newHTTPTask(ctx context.Context, l logger.Logger, m meter.Meter, check stri
|
|||||||
var treq client.Request
|
var treq client.Request
|
||||||
var opts []client.CallOption
|
var opts []client.CallOption
|
||||||
var labels []string
|
var labels []string
|
||||||
|
swaggerSet := swaggerset.NewSwaggerSet()
|
||||||
|
|
||||||
if task.HTTP.OpenAPI != "" {
|
if task.HTTP.OpenAPI != "" {
|
||||||
|
var svc string
|
||||||
|
|
||||||
openapiBuf, err := os.ReadFile(task.HTTP.OpenAPI)
|
openapiBuf, err := os.ReadFile(task.HTTP.OpenAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -222,12 +224,11 @@ func newHTTPTask(ctx context.Context, l logger.Logger, m meter.Meter, check stri
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
doc, err := openapi_v3.ParseDocument(openapiBuf)
|
err = swaggerSet.AddSwaggerset(task.HTTP.Addr, svc, openapiBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Error(ctx, "failed to unmarshal openapi file", err)
|
l.Error(ctx, "failed to add openApi spec", err)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
_ = doc
|
|
||||||
|
|
||||||
errmap := make(map[string]interface{}, 1)
|
errmap := make(map[string]interface{}, 1)
|
||||||
errmap["default"] = &codecpb.Frame{}
|
errmap["default"] = &codecpb.Frame{}
|
||||||
@ -239,8 +240,17 @@ func newHTTPTask(ctx context.Context, l logger.Logger, m meter.Meter, check stri
|
|||||||
// client.WithContentType("application/json"),
|
// client.WithContentType("application/json"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msg, err := swaggerSet.GetMessage(task.HTTP.Addr, svc, task.HTTP.Method, "POST")
|
||||||
|
if err != nil {
|
||||||
|
l.Error(ctx, "failed to get message from swagger spec", err)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
req = &codecpb.Frame{Data: []byte(task.HTTP.Data)}
|
req = &codecpb.Frame{Data: []byte(task.HTTP.Data)}
|
||||||
rsp = &codecpb.Frame{}
|
if task.HTTP.Data == "" {
|
||||||
|
req = msg.Request
|
||||||
|
}
|
||||||
|
rsp = msg.Response
|
||||||
|
|
||||||
treq = c.NewRequest(task.Name, task.Name, req)
|
treq = c.NewRequest(task.Name, task.Name, req)
|
||||||
|
|
||||||
|
@ -23,38 +23,27 @@ func NewSwaggerSet() *SwaggerSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SwaggerSet) GetMessage(addr, svc, mth, typereq string) (*messages, error) {
|
func (p *SwaggerSet) GetMessage(addr, svc, mth string, typereq string) (*Message, error) {
|
||||||
if svc == "" || mth == "" || addr == "" || typereq == "" {
|
if svc == "" || mth == "" || addr == "" || typereq == "" {
|
||||||
return nil, errors.New("addr or service name is empty")
|
return nil, errors.New("addr or service name is empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
messages := newMessages()
|
|
||||||
|
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
doc := p.files[addr+"|"+svc]
|
doc := p.files[addr+"|"+svc]
|
||||||
p.mu.Unlock()
|
p.mu.Unlock()
|
||||||
|
|
||||||
pathItem := doc.Paths.Value(mth)
|
pathItem := doc.Paths.Value(mth)
|
||||||
if pathItem.Get != nil {
|
reqParam, reqBody, rsp := handleOperation(typereq, pathItem.Get)
|
||||||
reqParam, reqBody, rsp := handleOperation("GET", pathItem.Get)
|
msg := &Message{
|
||||||
messages.Msgs = append(messages.Msgs, message{
|
Type: typereq,
|
||||||
Type: "GET",
|
Request: httpRequest{
|
||||||
RequestParam: reqParam,
|
Header: reqParam,
|
||||||
RequestBody: reqBody,
|
Body: reqBody,
|
||||||
Response: rsp,
|
},
|
||||||
})
|
Response: rsp,
|
||||||
}
|
|
||||||
if pathItem.Post != nil {
|
|
||||||
reqParam, reqBody, rsp := handleOperation("POST", pathItem.Post)
|
|
||||||
messages.Msgs = append(messages.Msgs, message{
|
|
||||||
Type: "POST",
|
|
||||||
RequestParam: reqParam,
|
|
||||||
RequestBody: reqBody,
|
|
||||||
Response: rsp,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return messages, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SwaggerSet) AddSwaggerset(addr, svc string, data []byte) error {
|
func (p *SwaggerSet) AddSwaggerset(addr, svc string, data []byte) error {
|
||||||
|
@ -21,7 +21,7 @@ func TestSwaggerSet_1(t *testing.T) {
|
|||||||
"localhost:8080",
|
"localhost:8080",
|
||||||
"service",
|
"service",
|
||||||
"/domain-service/v1/push_mail/enabled",
|
"/domain-service/v1/push_mail/enabled",
|
||||||
"POST")
|
[]string{"POST", "GET"})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotNil(t, msgs.Msgs)
|
assert.NotNil(t, msgs.Msgs)
|
||||||
for _, msg := range msgs.Msgs {
|
for _, msg := range msgs.Msgs {
|
||||||
@ -31,6 +31,7 @@ func TestSwaggerSet_1(t *testing.T) {
|
|||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
rsp, err := json.Marshal(msg.Response)
|
rsp, err := json.Marshal(msg.Response)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
fmt.Printf("type: %s, reqParam: %s, reqBody: %s, rsp: %s \n", msg.Type, reqParam, reqBody, rsp)
|
fmt.Printf("JSON: type: %s, reqParam: %s, reqBody: %s, rsp: %s \n", msg.Type, reqParam, reqBody, rsp)
|
||||||
|
fmt.Printf("Struct: type: %s, reqParam: %+v, reqBody: %+v, rsp: %+v \n", msg.Type, msg.RequestParam, msg.RequestBody, msg.Response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package swaggerset
|
package swaggerset
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@ -10,24 +9,17 @@ import (
|
|||||||
dynamicstruct "github.com/ompluscator/dynamic-struct"
|
dynamicstruct "github.com/ompluscator/dynamic-struct"
|
||||||
)
|
)
|
||||||
|
|
||||||
type messages struct {
|
type Message struct {
|
||||||
Msgs []message
|
Type string
|
||||||
|
Request httpRequest
|
||||||
|
Response interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMessages() *messages {
|
type httpRequest struct {
|
||||||
return &messages{
|
Header interface{}
|
||||||
Msgs: make([]message, 0),
|
Body interface{}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type message struct {
|
|
||||||
Type string
|
|
||||||
RequestParam interface{}
|
|
||||||
RequestBody interface{}
|
|
||||||
Response interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обработка операции (GET или POST)
|
|
||||||
func handleOperation(method string, operation *openapi3.Operation) (reqParam, reqBody, rsp interface{}) {
|
func handleOperation(method string, operation *openapi3.Operation) (reqParam, reqBody, rsp interface{}) {
|
||||||
fmt.Printf(" Method: %s\n", method)
|
fmt.Printf(" Method: %s\n", method)
|
||||||
|
|
||||||
@ -37,23 +29,21 @@ func handleOperation(method string, operation *openapi3.Operation) (reqParam, re
|
|||||||
for _, paramRef := range operation.Parameters {
|
for _, paramRef := range operation.Parameters {
|
||||||
param := paramRef.Value
|
param := paramRef.Value
|
||||||
fieldName := capitalize(param.Name)
|
fieldName := capitalize(param.Name)
|
||||||
|
jsonName := strings.ToLower(param.Name[:1]) + param.Name[1:]
|
||||||
goType := getGoType(param.Schema)
|
goType := getGoType(param.Schema)
|
||||||
|
|
||||||
// В зависимости от того, где параметр находится (header, query, path, etc.), добавляем соответствующий тег
|
// В зависимости от того, где параметр находится (header, query, path, etc.), добавляем соответствующий тег
|
||||||
switch param.In {
|
switch param.In {
|
||||||
case "query":
|
case "query":
|
||||||
paramsStruct = paramsStruct.AddField(fieldName, goType, fmt.Sprintf(`json:"%s" query:"%s"`, param.Name, param.Name))
|
paramsStruct = paramsStruct.AddField(fieldName, goType, fmt.Sprintf(`json:"%s" query:"%s"`, jsonName, jsonName))
|
||||||
case "header":
|
case "header":
|
||||||
paramsStruct = paramsStruct.AddField(fieldName, goType, fmt.Sprintf(`json:"%s" header:"%s"`, param.Name, param.Name))
|
paramsStruct = paramsStruct.AddField(fieldName, goType, fmt.Sprintf(`json:"%s" header:"%s"`, jsonName, jsonName))
|
||||||
default:
|
default:
|
||||||
paramsStruct = paramsStruct.AddField(fieldName, goType, fmt.Sprintf(`json:"%s"`, param.Name))
|
paramsStruct = paramsStruct.AddField(fieldName, goType, fmt.Sprintf(`json:"%s"`, jsonName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requestStruct := paramsStruct.Build().New()
|
// Получили структуру запроса для методов, где есть параметры в header, query, path, etc., добавили теги
|
||||||
fmt.Printf(" Request (Parameters): %+v\n", requestStruct)
|
reqParam = paramsStruct.Build().New()
|
||||||
buf, _ := json.Marshal(requestStruct)
|
|
||||||
fmt.Printf(" Request (Parameters) JSON: %s\n", buf)
|
|
||||||
reqParam = requestStruct
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обработка тела запроса (POST)
|
// Обработка тела запроса (POST)
|
||||||
@ -62,9 +52,7 @@ func handleOperation(method string, operation *openapi3.Operation) (reqParam, re
|
|||||||
bodyFields := buildDynamicStruct(content.Schema)
|
bodyFields := buildDynamicStruct(content.Schema)
|
||||||
bodyStruct := reflect.StructOf(bodyFields)
|
bodyStruct := reflect.StructOf(bodyFields)
|
||||||
bodyInstance := reflect.New(bodyStruct).Interface()
|
bodyInstance := reflect.New(bodyStruct).Interface()
|
||||||
fmt.Printf(" Request (Body): %+v\n", bodyInstance)
|
// Получили тело запроса
|
||||||
buf, _ := json.Marshal(bodyInstance)
|
|
||||||
fmt.Printf(" Request (Body) JSON: %s\n", buf)
|
|
||||||
reqBody = bodyInstance
|
reqBody = bodyInstance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,9 +64,7 @@ func handleOperation(method string, operation *openapi3.Operation) (reqParam, re
|
|||||||
responseFields := buildDynamicStruct(content.Schema)
|
responseFields := buildDynamicStruct(content.Schema)
|
||||||
responseStruct := reflect.StructOf(responseFields)
|
responseStruct := reflect.StructOf(responseFields)
|
||||||
responseInstance := reflect.New(responseStruct).Interface()
|
responseInstance := reflect.New(responseStruct).Interface()
|
||||||
fmt.Printf(" Response: %+v\n", responseInstance)
|
// Получили структуру ответа
|
||||||
buf, _ := json.Marshal(responseInstance)
|
|
||||||
fmt.Printf(" Response JSON: %s\n", buf)
|
|
||||||
rsp = responseInstance
|
rsp = responseInstance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,11 +74,10 @@ func handleOperation(method string, operation *openapi3.Operation) (reqParam, re
|
|||||||
|
|
||||||
// Рекурсивное создание структуры из схемы с учетом $ref
|
// Рекурсивное создание структуры из схемы с учетом $ref
|
||||||
func buildDynamicStruct(schema *openapi3.SchemaRef) []reflect.StructField {
|
func buildDynamicStruct(schema *openapi3.SchemaRef) []reflect.StructField {
|
||||||
var builder []reflect.StructField
|
var sfields []reflect.StructField
|
||||||
fmt.Println("ref: ", schema.Ref)
|
|
||||||
|
|
||||||
if len(schema.Value.Properties) == 0 {
|
if len(schema.Value.Properties) == 0 {
|
||||||
return builder
|
return sfields
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, prop := range schema.Value.Properties {
|
for name, prop := range schema.Value.Properties {
|
||||||
@ -106,7 +91,7 @@ func buildDynamicStruct(schema *openapi3.SchemaRef) []reflect.StructField {
|
|||||||
Tag: reflect.StructTag(fmt.Sprintf(`json:"%s"`, name)),
|
Tag: reflect.StructTag(fmt.Sprintf(`json:"%s"`, name)),
|
||||||
}
|
}
|
||||||
|
|
||||||
builder = append(builder, sfield)
|
sfields = append(sfields, sfield)
|
||||||
} else {
|
} else {
|
||||||
sfield := reflect.StructField{
|
sfield := reflect.StructField{
|
||||||
Name: fieldName,
|
Name: fieldName,
|
||||||
@ -114,11 +99,11 @@ func buildDynamicStruct(schema *openapi3.SchemaRef) []reflect.StructField {
|
|||||||
Tag: reflect.StructTag(fmt.Sprintf(`json:"%s"`, name)),
|
Tag: reflect.StructTag(fmt.Sprintf(`json:"%s"`, name)),
|
||||||
}
|
}
|
||||||
|
|
||||||
builder = append(builder, sfield)
|
sfields = append(sfields, sfield)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder
|
return sfields
|
||||||
}
|
}
|
||||||
|
|
||||||
// Преобразование типа OpenAPI в тип Go
|
// Преобразование типа OpenAPI в тип Go
|
||||||
@ -152,7 +137,7 @@ func capitalize(fieldName string) string {
|
|||||||
// Обрабатываем каждый фрагмент
|
// Обрабатываем каждый фрагмент
|
||||||
for i := 0; i < len(parts); i++ {
|
for i := 0; i < len(parts); i++ {
|
||||||
// Капитализируем первые буквы всех частей, кроме первой
|
// Капитализируем первые буквы всех частей, кроме первой
|
||||||
parts[i] = strings.Title(parts[i])
|
parts[i] = strings.Title(parts[i]) //cases.Title(language.English).String(parts[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Собираем строку обратно, соединяя части без подчеркиваний
|
// Собираем строку обратно, соединяя части без подчеркиваний
|
||||||
|
Loading…
x
Reference in New Issue
Block a user