في هذه المقالة ، أود أن أخبرك عن كيفية إنشاء خادم ويب بلغة Golang بسرعة وسهولة مع وثائق خاصة به. وحول ما هي الأساليب والأدوات اللازمة لتنفيذها
اليوم سنقوم بتحليل هذه الأدوات الجاهزة:
ترميز اختيال
لنبدأ بـ swagger-api / swagger-codegen التي تقدمها swagger.io . يعمل Swagger Codegen على تبسيط عملية الإنشاء من خلال إنشاء بذرة الخادم وخوادم SDK للعميل لأي API محددة في مواصفات OpenAPI (المعروفة سابقًا باسم Swagger) ، كل ما عليك فعله هو تنفيذ API الخاص بك.
فيما يلي مثال على ملف التبختر ومظهره المرئي في Swagger Editor ، حيث يمكننا إنشاء تطبيقاتنا لشيء واحد.
اختيال{
"swagger" : "2.0",
"info" : {
"version" : "1.0.0",
"title" : "Swagger Petstore"
},
"host" : "localhost",
"basePath" : "/v1",
"tags" : [ {
"name" : "pet"
} ],
"schemes" : [ "https", "http" ],
"paths" : {
"/pet" : {
"post" : {
"tags" : [ "pet" ],
"summary" : "Add a new pet to the store",
"operationId" : "addPet",
"consumes" : [ "application/json" ],
"produces" : [ "application/json" ],
"parameters" : [ {
"in" : "body",
"name" : "body",
"description" : "Pet object that needs to be added to the store",
"required" : true,
"schema" : {
"$ref" : "#/definitions/Pet"
}
} ],
"responses" : {
"405" : {
"description" : "Invalid input"
}
}
}
}
},
"definitions" : {
"Category" : {
"type" : "object",
"properties" : {
"id" : {
"type" : "integer",
"format" : "int64"
},
"name" : {
"type" : "string"
}
}
},
"Tag" : {
"type" : "object",
"properties" : {
"id" : {
"type" : "integer",
"format" : "int64"
},
"name" : {
"type" : "string"
}
}
},
"Pet" : {
"type" : "object",
"required" : [ "name", "photoUrls" ],
"properties" : {
"id" : {
"type" : "integer",
"format" : "int64"
},
"category" : {
"$ref" : "#/definitions/Category"
},
"name" : {
"type" : "string",
"example" : "doggie"
},
"photoUrls" : {
"type" : "array",
"items" : {
"type" : "string"
}
},
"tags" : {
"type" : "array",
"items" : {
"$ref" : "#/definitions/Tag"
}
},
"status" : {
"type" : "string",
"description" : "pet status in the store",
"enum" : [ "available", "pending", "sold" ]
}
}
}
}
}
لدى العميل والخادم كائنات هيكل متطابقة. ملف سبيل المثال go-client-generated/model_pet.go
و go-server-server-generated/go/model_pet.go
.
نموذج هيكل الحيوانات الأليفة في العميل والخادم
package swagger
type Pet struct {
Id int64 `json:"id,omitempty"`
Category *Category `json:"category,omitempty"`
Name string `json:"name"`
PhotoUrls []string `json:"photoUrls"`
Tags []Tag `json:"tags,omitempty"`
Status string `json:"status,omitempty"`
}
يحتوي العميل أيضًا على طرق لإرسال الطلبات ، ويقوم الخادم بإنهاء واجهات معالجة الطلبات.
, . , .
go-swagger
— go-swagger/go-swagger. go API- Swagger API: , .
- Swagger
- Swagger
- , jsonschema swagger,
- swagger go
- swagger
- ,
:
$ swagger generate server -f ./swagger.json
, , . .
— go-swagger-service/restapi/configure_swagger_petstore.go
. : handler', middleware, , , .
package restapi
import (
"crypto/tls"
"net/http"
errors "github.com/go-openapi/errors"
runtime "github.com/go-openapi/runtime"
middleware "github.com/go-openapi/runtime/middleware"
"go-generator/go-swagger-service/restapi/operations"
"go-generator/go-swagger-service/restapi/operations/pet"
)
func configureFlags(api *operations.SwaggerPetstoreAPI) {
}
func configureAPI(api *operations.SwaggerPetstoreAPI) http.Handler {
api.ServeError = errors.ServeError
api.JSONConsumer = runtime.JSONConsumer()
api.JSONProducer = runtime.JSONProducer()
if api.PetAddPetHandler == nil {
api.PetAddPetHandler = pet.AddPetHandlerFunc(func(params pet.AddPetParams) middleware.Responder {
return middleware.NotImplemented("operation pet.AddPet has not yet been implemented")
})
}
api.ServerShutdown = func() {}
return setupGlobalMiddleware(api.Serve(setupMiddlewares))
}
func configureTLS(tlsConfig *tls.Config) {
}
func configureServer(s *http.Server, scheme, addr string) {
}
func setupMiddlewares(handler http.Handler) http.Handler {
return handler
}
func setupGlobalMiddleware(handler http.Handler) http.Handler {
return handler
}
. 422
.
swagger . enum
, required
, type
, maximum
.
Pet
package models
import (
"encoding/json"
"strconv"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
type Pet struct {
Category *Category `json:"category,omitempty"`
ID int64 `json:"id,omitempty"`
Name *string `json:"name"`
PhotoUrls []string `json:"photoUrls"`
Status string `json:"status,omitempty"`
Tags []*Tag `json:"tags"`
}
func (m *Pet) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateCategory(formats); err != nil {
res = append(res, err)
}
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if err := m.validatePhotoUrls(formats); err != nil {
res = append(res, err)
}
if err := m.validateStatus(formats); err != nil {
res = append(res, err)
}
if err := m.validateTags(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *Pet) validateCategory(formats strfmt.Registry) error {
if swag.IsZero(m.Category) {
return nil
}
if m.Category != nil {
if err := m.Category.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("category")
}
return err
}
}
return nil
}
func (m *Pet) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
return err
}
return nil
}
func (m *Pet) validatePhotoUrls(formats strfmt.Registry) error {
if err := validate.Required("photoUrls", "body", m.PhotoUrls); err != nil {
return err
}
return nil
}
var petTypeStatusPropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["available","pending","sold"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
petTypeStatusPropEnum = append(petTypeStatusPropEnum, v)
}
}
const (
PetStatusAvailable string = "available"
PetStatusPending string = "pending"
PetStatusSold string = "sold"
)
func (m *Pet) validateStatusEnum(path, location string, value string) error {
if err := validate.Enum(path, location, value, petTypeStatusPropEnum); err != nil {
return err
}
return nil
}
func (m *Pet) validateStatus(formats strfmt.Registry) error {
if swag.IsZero(m.Status) {
return nil
}
if err := m.validateStatusEnum("status", "body", m.Status); err != nil {
return err
}
return nil
}
func (m *Pet) validateTags(formats strfmt.Registry) error {
if swag.IsZero(m.Tags) {
return nil
}
for i := 0; i < len(m.Tags); i++ {
if swag.IsZero(m.Tags[i]) {
continue
}
if m.Tags[i] != nil {
if err := m.Tags[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("tags" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *Pet) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
func (m *Pet) UnmarshalBinary(b []byte) error {
var res Pet
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
$ run ./go-swagger-service/cmd/swagger-petstore-server/main.go --port 8090
:
$ swagger generate client -f ./swagger.json
, api-sdk. , , .
package pet
import (
"github.com/go-openapi/runtime"
strfmt "github.com/go-openapi/strfmt"
)
func New(transport runtime.ClientTransport, formats strfmt.Registry) *Client {
return &Client{transport: transport, formats: formats}
}
type Client struct {
transport runtime.ClientTransport
formats strfmt.Registry
}
func (a *Client) AddPet(params *AddPetParams) error {
if params == nil {
params = NewAddPetParams()
}
_, err := a.transport.Submit(&runtime.ClientOperation{
ID: "addPet",
Method: "POST",
PathPattern: "/pet",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &AddPetReader{formats: a.formats},
Context: params.Context,
Client: params.HTTPClient,
})
if err != nil {
return err
}
return nil
}
func (a *Client) SetTransport(transport runtime.ClientTransport) {
a.transport = transport
}
. Generate a spec from source code.
. , swagger .
grpc-gateway
swagger . grpc-ecosystem/grpc-gateway — protoc
. gRPC -, RESTful JSON API gRPC. gRPC.
HTTP + JSON gRPC. API gRPC RESTful .
grpc-gateway reverse-proxy swagger.json protoc-gen-swagger.
. .
$ go install \
github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway \
github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger \
github.com/golang/protobuf/protoc-gen-go
.proto
protobufsyntax = "proto3";
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
package pet;
message AddPetRequest {
int64 id = 1;
message Category {
int64 id = 1;
string name = 2;
}
Category category = 2;
string name = 3;
repeated string photo_urls = 4;
message Tag {
int64 id = 1;
string name = 2;
}
repeated Tag tags = 5;
//pet status in the store
enum Status {
available = 0;
pending = 1;
sold = 2;
}
Status status = 6;
}
service PetService {
rpc AddPet (AddPetRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
post: "/pet"
body: "*"
};
}
}
gRPC stub:
$ protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--go_out=plugins=grpc:. \
pet.proto
pet.pb.go
. reverse-proxy protoc-gen-grpc-gateway
:
$ protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--grpc-gateway_out=logtostderr=true:. \
pet.proto
pet.pb.gw.go
. gateway. pet.swagger
.json protoc-gen-swagger
:
$ protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--swagger_out=logtostderr=true:. \
pet.proto
PetServiceServer.
type PetServiceServer interface {
AddPet(context.Context, *AddPetRequest) (*empty.Empty, error)
}
:
main.gopackage pet
import (
"context"
"flag"
"net/http"
"github.com/golang/glog"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
gw "grpc-gateway/pet"
"grpc-gateway/service"
)
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
mux := runtime.NewServeMux()
err := gw.RegisterPetServiceHandlerServer(ctx, mux, &service.PetService{})
if err != nil {
return err
}
return http.ListenAndServe(":8081", mux)
}
func main() {
flag.Parse()
defer glog.Flush()
if err := run(); err != nil {
glog.Fatal(err)
}
}
, . , c grpc-gateway.
Swag
Swag Go Swagger 2.0. - Go. swaggo/swag Go ( Swagger UI).
:
Swagger , endpoint'. .
API-
func (c *ExampleController) ShowAccount(ctx *contex.Context) {
}
github.
, , .
لقد قمنا الآن بتوسيع فهمنا للتفاعلات المحتملة مع وثائق التبجح. لقد درسنا طرق تصميم الكود وتجميع الوثائق له.
وأعتقد أن البعض قد اختار بالفعل الطريقة المناسبة لتنفيذ واجهة برمجة التطبيقات لمشروعهم الجديد ، أو جرب الأمثلة التي تم تحليلها مقابل الأمثلة الحالية.