add server

This commit is contained in:
Владимир Фёдоров 2024-11-09 18:18:51 +07:00
parent 93e9f98b5b
commit d566529a90
10 changed files with 163 additions and 54 deletions

11
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"configurations": [
{
"name": "Launch eparser",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/cmd/smm_core"
},
]
}

View File

@ -11,7 +11,7 @@ option go_package = "pkg/proto";
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {};
service SmmCore {
rpc GetCatalog(PingReq) returns (PingRsp) {
rpc Ping(PingReq) returns (PingRsp) {
option (google.api.http) = {
get: "/ping"
};

View File

@ -1,7 +1,83 @@
package main
import "fmt"
import (
"context"
"log"
"net"
"net/http"
"os"
"git.3crabs.ru/save_my_money/smm_core/internal/app"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
proto "git.3crabs.ru/save_my_money/smm_core/proto"
)
func main() {
fmt.Println("Hello, World!")
// Create a listener on TCP port
lis, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln("Failed to listen:", err)
}
// Create a gRPC server object
s := grpc.NewServer()
// Attach the Greeter service to the server
proto.RegisterSmmCoreServer(s, app.NewServer())
// Serve gRPC server
log.Println("Serving gRPC on 0.0.0.0:8080")
go func() {
log.Fatalln(s.Serve(lis))
}()
// Create a client connection to the gRPC server we just started
// This is where the gRPC-Gateway proxies the requests
conn, err := grpc.NewClient(
"0.0.0.0:8080",
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
log.Fatalln("Failed to dial server:", err)
}
mux := runtime.NewServeMux()
// Register Greeter
err = proto.RegisterSmmCoreHandler(context.Background(), mux, conn)
if err != nil {
log.Fatalln("Failed to register gateway:", err)
}
err = mux.HandlePath("GET", "/swagger", func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
data, err := os.ReadFile("resources/smm_core.swagger.json")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
_, _ = w.Write(data)
})
if err != nil {
panic(err)
}
log.Println("Serving swagger json on http://0.0.0.0:8090/swagger")
gwServer := &http.Server{
Addr: ":8090",
Handler: cors(mux),
}
log.Println("Serving gRPC-Gateway on http://0.0.0.0:8090")
log.Fatalln(gwServer.ListenAndServe())
}
func cors(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PATCH, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, Authorization, ResponseType")
if r.Method == "OPTIONS" {
return
}
h.ServeHTTP(w, r)
})
}

19
go.mod
View File

@ -3,12 +3,15 @@ module git.3crabs.ru/save_my_money/smm_core
go 1.23.3
require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect
golang.org/x/text v0.19.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/grpc v1.67.1 // indirect
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect
google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38
google.golang.org/grpc v1.67.1
google.golang.org/protobuf v1.35.1
)
require (
golang.org/x/net v0.28.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.19.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
)

11
go.sum
View File

@ -1,5 +1,11 @@
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw=
@ -8,10 +14,5 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

19
internal/app/server.go Normal file
View File

@ -0,0 +1,19 @@
package app
import (
"context"
proto "git.3crabs.ru/save_my_money/smm_core/proto"
)
type Server struct {
proto.UnsafeSmmCoreServer
}
func NewServer() *Server {
return &Server{}
}
func (s *Server) Ping(_ context.Context, _ *proto.PingReq) (*proto.PingRsp, error) {
return &proto.PingRsp{}, nil
}

View File

@ -108,14 +108,13 @@ var file_smm_core_proto_rawDesc = []byte{
0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x09, 0x0a, 0x07, 0x50, 0x69, 0x6e,
0x67, 0x52, 0x65, 0x71, 0x22, 0x09, 0x0a, 0x07, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x73, 0x70, 0x32,
0x58, 0x0a, 0x07, 0x53, 0x6d, 0x6d, 0x43, 0x6f, 0x72, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x47, 0x65,
0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x17, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73,
0x2e, 0x73, 0x6d, 0x6d, 0x5f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65,
0x71, 0x1a, 0x17, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x73, 0x6d, 0x6d, 0x5f, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x73, 0x70, 0x22, 0x0d, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x07, 0x12, 0x05, 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x42, 0x0e, 0x92, 0x41, 0x00, 0x5a, 0x09,
0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
0x52, 0x0a, 0x07, 0x53, 0x6d, 0x6d, 0x43, 0x6f, 0x72, 0x65, 0x12, 0x47, 0x0a, 0x04, 0x50, 0x69,
0x6e, 0x67, 0x12, 0x17, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x73, 0x6d, 0x6d, 0x5f, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x63, 0x72,
0x61, 0x62, 0x73, 0x2e, 0x73, 0x6d, 0x6d, 0x5f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x69, 0x6e,
0x67, 0x52, 0x73, 0x70, 0x22, 0x0d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x07, 0x12, 0x05, 0x2f, 0x70,
0x69, 0x6e, 0x67, 0x42, 0x0e, 0x92, 0x41, 0x00, 0x5a, 0x09, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -136,8 +135,8 @@ var file_smm_core_proto_goTypes = []any{
(*PingRsp)(nil), // 1: crabs.smm_core.PingRsp
}
var file_smm_core_proto_depIdxs = []int32{
0, // 0: crabs.smm_core.SmmCore.GetCatalog:input_type -> crabs.smm_core.PingReq
1, // 1: crabs.smm_core.SmmCore.GetCatalog:output_type -> crabs.smm_core.PingRsp
0, // 0: crabs.smm_core.SmmCore.Ping:input_type -> crabs.smm_core.PingReq
1, // 1: crabs.smm_core.SmmCore.Ping:output_type -> crabs.smm_core.PingRsp
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name

View File

@ -31,20 +31,20 @@ var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = metadata.Join
func request_SmmCore_GetCatalog_0(ctx context.Context, marshaler runtime.Marshaler, client SmmCoreClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
func request_SmmCore_Ping_0(ctx context.Context, marshaler runtime.Marshaler, client SmmCoreClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq PingReq
var metadata runtime.ServerMetadata
msg, err := client.GetCatalog(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
msg, err := client.Ping(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_SmmCore_GetCatalog_0(ctx context.Context, marshaler runtime.Marshaler, server SmmCoreServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
func local_request_SmmCore_Ping_0(ctx context.Context, marshaler runtime.Marshaler, server SmmCoreServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq PingReq
var metadata runtime.ServerMetadata
msg, err := server.GetCatalog(ctx, &protoReq)
msg, err := server.Ping(ctx, &protoReq)
return msg, metadata, err
}
@ -56,7 +56,7 @@ func local_request_SmmCore_GetCatalog_0(ctx context.Context, marshaler runtime.M
// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call.
func RegisterSmmCoreHandlerServer(ctx context.Context, mux *runtime.ServeMux, server SmmCoreServer) error {
mux.Handle("GET", pattern_SmmCore_GetCatalog_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle("GET", pattern_SmmCore_Ping_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
@ -64,12 +64,12 @@ func RegisterSmmCoreHandlerServer(ctx context.Context, mux *runtime.ServeMux, se
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/crabs.smm_core.SmmCore/GetCatalog", runtime.WithHTTPPathPattern("/ping"))
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/crabs.smm_core.SmmCore/Ping", runtime.WithHTTPPathPattern("/ping"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_SmmCore_GetCatalog_0(annotatedContext, inboundMarshaler, server, req, pathParams)
resp, md, err := local_request_SmmCore_Ping_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
@ -77,7 +77,7 @@ func RegisterSmmCoreHandlerServer(ctx context.Context, mux *runtime.ServeMux, se
return
}
forward_SmmCore_GetCatalog_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_SmmCore_Ping_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
@ -122,25 +122,25 @@ func RegisterSmmCoreHandler(ctx context.Context, mux *runtime.ServeMux, conn *gr
// "SmmCoreClient" to call the correct interceptors. This client ignores the HTTP middlewares.
func RegisterSmmCoreHandlerClient(ctx context.Context, mux *runtime.ServeMux, client SmmCoreClient) error {
mux.Handle("GET", pattern_SmmCore_GetCatalog_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle("GET", pattern_SmmCore_Ping_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/crabs.smm_core.SmmCore/GetCatalog", runtime.WithHTTPPathPattern("/ping"))
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/crabs.smm_core.SmmCore/Ping", runtime.WithHTTPPathPattern("/ping"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_SmmCore_GetCatalog_0(annotatedContext, inboundMarshaler, client, req, pathParams)
resp, md, err := request_SmmCore_Ping_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_SmmCore_GetCatalog_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_SmmCore_Ping_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
@ -148,9 +148,9 @@ func RegisterSmmCoreHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl
}
var (
pattern_SmmCore_GetCatalog_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ping"}, ""))
pattern_SmmCore_Ping_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ping"}, ""))
)
var (
forward_SmmCore_GetCatalog_0 = runtime.ForwardResponseMessage
forward_SmmCore_Ping_0 = runtime.ForwardResponseMessage
)

View File

@ -19,14 +19,14 @@ import (
const _ = grpc.SupportPackageIsVersion9
const (
SmmCore_GetCatalog_FullMethodName = "/crabs.smm_core.SmmCore/GetCatalog"
SmmCore_Ping_FullMethodName = "/crabs.smm_core.SmmCore/Ping"
)
// SmmCoreClient is the client API for SmmCore service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type SmmCoreClient interface {
GetCatalog(ctx context.Context, in *PingReq, opts ...grpc.CallOption) (*PingRsp, error)
Ping(ctx context.Context, in *PingReq, opts ...grpc.CallOption) (*PingRsp, error)
}
type smmCoreClient struct {
@ -37,10 +37,10 @@ func NewSmmCoreClient(cc grpc.ClientConnInterface) SmmCoreClient {
return &smmCoreClient{cc}
}
func (c *smmCoreClient) GetCatalog(ctx context.Context, in *PingReq, opts ...grpc.CallOption) (*PingRsp, error) {
func (c *smmCoreClient) Ping(ctx context.Context, in *PingReq, opts ...grpc.CallOption) (*PingRsp, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(PingRsp)
err := c.cc.Invoke(ctx, SmmCore_GetCatalog_FullMethodName, in, out, cOpts...)
err := c.cc.Invoke(ctx, SmmCore_Ping_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -51,7 +51,7 @@ func (c *smmCoreClient) GetCatalog(ctx context.Context, in *PingReq, opts ...grp
// All implementations must embed UnimplementedSmmCoreServer
// for forward compatibility.
type SmmCoreServer interface {
GetCatalog(context.Context, *PingReq) (*PingRsp, error)
Ping(context.Context, *PingReq) (*PingRsp, error)
mustEmbedUnimplementedSmmCoreServer()
}
@ -62,8 +62,8 @@ type SmmCoreServer interface {
// pointer dereference when methods are called.
type UnimplementedSmmCoreServer struct{}
func (UnimplementedSmmCoreServer) GetCatalog(context.Context, *PingReq) (*PingRsp, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetCatalog not implemented")
func (UnimplementedSmmCoreServer) Ping(context.Context, *PingReq) (*PingRsp, error) {
return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented")
}
func (UnimplementedSmmCoreServer) mustEmbedUnimplementedSmmCoreServer() {}
func (UnimplementedSmmCoreServer) testEmbeddedByValue() {}
@ -86,20 +86,20 @@ func RegisterSmmCoreServer(s grpc.ServiceRegistrar, srv SmmCoreServer) {
s.RegisterService(&SmmCore_ServiceDesc, srv)
}
func _SmmCore_GetCatalog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _SmmCore_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PingReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).GetCatalog(ctx, in)
return srv.(SmmCoreServer).Ping(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_GetCatalog_FullMethodName,
FullMethod: SmmCore_Ping_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).GetCatalog(ctx, req.(*PingReq))
return srv.(SmmCoreServer).Ping(ctx, req.(*PingReq))
}
return interceptor(ctx, in, info, handler)
}
@ -112,8 +112,8 @@ var SmmCore_ServiceDesc = grpc.ServiceDesc{
HandlerType: (*SmmCoreServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetCatalog",
Handler: _SmmCore_GetCatalog_Handler,
MethodName: "Ping",
Handler: _SmmCore_Ping_Handler,
},
},
Streams: []grpc.StreamDesc{},

View File

@ -18,7 +18,7 @@
"paths": {
"/ping": {
"get": {
"operationId": "SmmCore_GetCatalog",
"operationId": "SmmCore_Ping",
"responses": {
"200": {
"description": "A successful response.",