#2 - add swaggerset #8

Merged
vtolstov merged 3 commits from kgorbunov/servicechecker:#2 into master 2024-12-06 19:01:08 +03:00
4 changed files with 49 additions and 64 deletions
Showing only changes of commit e207117ba4 - Show all commits

View File

@ -7,7 +7,6 @@ import (
"os/signal"
"time"
openapi_v3 "github.com/google/gnostic/openapiv3"
"github.com/google/uuid"
grpccli "go.unistack.org/micro-client-grpc/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/protoset"
"go.unistack.org/servicechecker/pkg/scheduler"
"go.unistack.org/servicechecker/pkg/swaggerset"
)
var (
@ -213,8 +213,10 @@ func newHTTPTask(ctx context.Context, l logger.Logger, m meter.Meter, check stri
var treq client.Request
var opts []client.CallOption
var labels []string
swaggerSet := swaggerset.NewSwaggerSet()
if task.HTTP.OpenAPI != "" {
var svc string
openapiBuf, err := os.ReadFile(task.HTTP.OpenAPI)
if err != nil {
@ -222,12 +224,11 @@ func newHTTPTask(ctx context.Context, l logger.Logger, m meter.Meter, check stri
return nil, nil, err
}
doc, err := openapi_v3.ParseDocument(openapiBuf)
err = swaggerSet.AddSwaggerset(task.HTTP.Addr, svc, openapiBuf)
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
}
_ = doc
errmap := make(map[string]interface{}, 1)
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"),
}
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)}
rsp = &codecpb.Frame{}
if task.HTTP.Data == "" {
req = msg.Request
}
rsp = msg.Response
treq = c.NewRequest(task.Name, task.Name, req)

View File

@ -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 == "" {
return nil, errors.New("addr or service name is empty")
}
messages := newMessages()
p.mu.Lock()
doc := p.files[addr+"|"+svc]
p.mu.Unlock()
pathItem := doc.Paths.Value(mth)
if pathItem.Get != nil {
reqParam, reqBody, rsp := handleOperation("GET", pathItem.Get)
messages.Msgs = append(messages.Msgs, message{
Type: "GET",
RequestParam: reqParam,
RequestBody: reqBody,
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,
})
reqParam, reqBody, rsp := handleOperation(typereq, pathItem.Get)
msg := &Message{
Type: typereq,
Request: httpRequest{
Header: reqParam,
Body: reqBody,
},
Response: rsp,
}
return messages, nil
return msg, nil
}
func (p *SwaggerSet) AddSwaggerset(addr, svc string, data []byte) error {

View File

@ -21,7 +21,7 @@ func TestSwaggerSet_1(t *testing.T) {
"localhost:8080",
"service",
"/domain-service/v1/push_mail/enabled",
"POST")
[]string{"POST", "GET"})
assert.Nil(t, err)
assert.NotNil(t, msgs.Msgs)
for _, msg := range msgs.Msgs {
@ -31,6 +31,7 @@ func TestSwaggerSet_1(t *testing.T) {
assert.Nil(t, err)
rsp, err := json.Marshal(msg.Response)
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)
}
}

View File

@ -1,7 +1,6 @@
package swaggerset
import (
"encoding/json"
"fmt"
"reflect"
"strings"
@ -10,24 +9,17 @@ import (
dynamicstruct "github.com/ompluscator/dynamic-struct"
)
type messages struct {
Msgs []message
type Message struct {
Type string
Request httpRequest
Response interface{}
}
func newMessages() *messages {
return &messages{
Msgs: make([]message, 0),
}
type httpRequest struct {
Header interface{}
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{}) {
fmt.Printf(" Method: %s\n", method)
@ -37,23 +29,21 @@ func handleOperation(method string, operation *openapi3.Operation) (reqParam, re
for _, paramRef := range operation.Parameters {
param := paramRef.Value
fieldName := capitalize(param.Name)
jsonName := strings.ToLower(param.Name[:1]) + param.Name[1:]
goType := getGoType(param.Schema)
// В зависимости от того, где параметр находится (header, query, path, etc.), добавляем соответствующий тег
switch param.In {
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":
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:
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()
fmt.Printf(" Request (Parameters): %+v\n", requestStruct)
buf, _ := json.Marshal(requestStruct)
fmt.Printf(" Request (Parameters) JSON: %s\n", buf)
reqParam = requestStruct
// Получили структуру запроса для методов, где есть параметры в header, query, path, etc., добавили теги
reqParam = paramsStruct.Build().New()
}
// Обработка тела запроса (POST)
@ -62,9 +52,7 @@ func handleOperation(method string, operation *openapi3.Operation) (reqParam, re
bodyFields := buildDynamicStruct(content.Schema)
bodyStruct := reflect.StructOf(bodyFields)
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
}
}
@ -76,9 +64,7 @@ func handleOperation(method string, operation *openapi3.Operation) (reqParam, re
responseFields := buildDynamicStruct(content.Schema)
responseStruct := reflect.StructOf(responseFields)
responseInstance := reflect.New(responseStruct).Interface()
fmt.Printf(" Response: %+v\n", responseInstance)
buf, _ := json.Marshal(responseInstance)
fmt.Printf(" Response JSON: %s\n", buf)
// Получили структуру ответа
rsp = responseInstance
}
}
@ -88,11 +74,10 @@ func handleOperation(method string, operation *openapi3.Operation) (reqParam, re
// Рекурсивное создание структуры из схемы с учетом $ref
func buildDynamicStruct(schema *openapi3.SchemaRef) []reflect.StructField {
var builder []reflect.StructField
fmt.Println("ref: ", schema.Ref)
var sfields []reflect.StructField
if len(schema.Value.Properties) == 0 {
return builder
return sfields
}
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)),
}
builder = append(builder, sfield)
sfields = append(sfields, sfield)
} else {
sfield := reflect.StructField{
Name: fieldName,
@ -114,11 +99,11 @@ func buildDynamicStruct(schema *openapi3.SchemaRef) []reflect.StructField {
Tag: reflect.StructTag(fmt.Sprintf(`json:"%s"`, name)),
}
builder = append(builder, sfield)
sfields = append(sfields, sfield)
}
}
return builder
return sfields
}
// Преобразование типа OpenAPI в тип Go
@ -152,7 +137,7 @@ func capitalize(fieldName string) string {
// Обрабатываем каждый фрагмент
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])
}
// Собираем строку обратно, соединяя части без подчеркиваний