Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
Go-Swagger в продуктиве
Ilya Kaznacheev
May 30, 2020
Programming
0
130
Go-Swagger в продуктиве
Ilya Kaznacheev
May 30, 2020
Tweet
Share
More Decks by Ilya Kaznacheev
See All by Ilya Kaznacheev
Golang: прошлое и будущее
dreamworm
0
80
Godoc: хороший, плохой, злой
dreamworm
0
19
Godoc: the Good, the Bad and the Ugly
dreamworm
0
120
Go-Swagger in production
dreamworm
0
220
Организация локальных сообществ: как, зачем и почему
dreamworm
0
31
Go-Swagger in production
dreamworm
1
220
Что OpenTelemetry нам готовит?
dreamworm
0
110
Поворот на 90°
dreamworm
1
160
Данилин Андрей - Построение offline приложения в SAP UI5
dreamworm
1
110
Other Decks in Programming
See All in Programming
Babylon.jsで作ったsceneをレイトレーシングで映えさせる
turamy
1
210
YATA: collaborative documents and how to make them fast
horusiath
1
160
How GitHub Supports Vim License Detection, The Five Years Journey
othree
1
370
More Than Micro Frontends: 3 Further Use Cases for Module Federation @DWX 2022
manfredsteyer
PRO
0
380
企業内スモールデータでのデータ解析
hamage9
0
890
Git操作編
smt7174
2
250
Pythonで鉄道指向プログラミング
usabarashi
0
130
Dagger, la CI, autrement
guikingone
1
110
ちょっとつよい足トラ
logilabo
0
400
SGGとは
inoue2002
0
440
20220706_Google Apps Scriptを実演で学ぶ~ GAS × Slack ~
apachan
2
620
Amazon Lookout for Visionで 筆跡鑑定してみた
cmnakamurashogo
0
170
Featured
See All Featured
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_i
25
15k
Rails Girls Zürich Keynote
gr2m
87
12k
Navigating Team Friction
lara
175
11k
The MySQL Ecosystem @ GitHub 2015
samlambert
239
11k
Producing Creativity
orderedlist
PRO
334
37k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
181
15k
Ruby is Unlike a Banana
tanoku
91
9.3k
StorybookのUI Testing Handbookを読んだ
zakiyama
6
2.5k
Mobile First: as difficult as doing things right
swwweet
213
7.6k
Building Adaptive Systems
keathley
25
1.2k
The World Runs on Bad Software
bkeepers
PRO
57
5.4k
Keith and Marios Guide to Fast Websites
keithpitt
404
21k
Transcript
Go-Swagger в продуктиве взлеты и падения
Илья Казначеев Remote Backend SWE Основатель Golang Voronezh Ведущий подкаста
Z-Namespace Организатор конференций и митапов Любитель кофе
Golang Voronezh - ~30 активных участников - митапы - мероприятия
для новичков - открыто и дружелюбно t.me/golang_vrn meetup.com/Golang-Voronezh
что такое swagger?
None
SOAP JSON-PRC GraphQL gRPC OData REST
Representational state transfer (REST) is a software architectural style that
defines a set of constraints to be used for creating Web services Wikipedia
None
swagger: "2.0" info: title: Pet API version: "1.0.0" basePath: /api
schemes: - http paths: /pets: get: summary: List all pets parameters: - name: limit in: query description: "How many items to return at one time" required: true type: integer responses: 200: description: an paged array of pets 400: description: unexpected error
None
None
почему мы используем swagger?
команда синхронизирует изменения в API...
None
библиотеки go-swagger/go-swagger ✭ 5.2 K swaggo/swag ✭ 2.7 K deepmap/oapi-codegen
✭ 440 … grpc-ecosystem/grpc-gateway ✭ 8.5 K
go-swagger
генерация кода swagger generate server -t internal/api --exclude-main
структура сгенерированных файлов internal/api ├ models │ └ ... └
restapi ├ operations │ └ ... ├ configure_<your_service_name>.go ├ doc.go ├ embedded_spec.go └ server.go
как мы генерируем код rm -rf internal/api && mkdir -p
internal/api swagger generate server -t internal/api --exclude-main go mod tidy
? вроде все просто
НЕТ
есть некоторые проблемы - go-swagger - это фреймворк, а не
библиотека - куча сгенерированных типов на каждый чих - несовместим с популярными http библиотеками
давайте фиксить!
net/http хендлеры type CustomResponder func(http.ResponseWriter, runtime.Producer) func (c CustomResponder) WriteResponse(w
http.ResponseWriter, p runtime.Producer) { c(w, p) } func MetricsHandler(p instruments.GetMetricsParams) middleware.Responder { return CustomResponder(func(w http.ResponseWriter, _ runtime.Producer) { promhttp.Handler().ServeHTTP(w, p.HTTPRequest) }) }
простые middleware api := operations.NewSwaggerPetstoreAPI(swaggerSpec) api.InstrumentsGetMetricsHandler = instruments.GetMetricsHandlerFunc(MetricsHandler) api.AddMiddlewareFor("GET", "/metrics",
SomeMiddleware) srv := restapi.NewServer(api) srv.Serve()
middleware с кастомным хендлером h := api.Serve(nil) r := chi.NewRouter()
r.Use( middleware.Recoverer, ) r.With(AuthMiddleware).Group(func(r chi.Router) { r.Handle("/user/*", h) }) r.Mount("/", h) srv.ConfigureAPI() srv.SetHandler(r) srv.Serve()
настройки вне configure_<your_service_name>.go api.Logger = log.Printf api.HTMLProducer = runtime.TextProducer() srv
:= restapi.NewServer(api) srv.EnabledListeners = []string{"http"} srv.Port = conf.HTTPPort srv.Host = conf.HTTPAddr
кастомные имена методов /store/order/{orderId}/items: get: tags: - store summary: Find
purchase order items parameters: - name: orderId in: path required: true type: integer func GetOrderItems( param store.GetStoreOrderOrderIDItemsParams, ) middleware.Responder { items, err := getOrderItems(param.OrderID) if err != nil { return store.NewGetStoreOrderOrderIDItemsNotFound() } res := &models.OrderItems{} // // fill resopnse // return store.NewGetStoreOrderOrderIDItemsOK(). WithPayload(res) }
кастомные имена методов /store/order/{orderId}/items: get: tags: - store summary: Find
purchase order items operationId: getOrderItems parameters: - name: orderId in: path required: true type: integer func GetOrderItems( param store.GetOrderItemsParams, ) middleware.Responder { items, err := getOrderItems(param.OrderID) if err != nil { return store.NewGetOrderItemsNotFound() } res := &models.OrderItems{} // // fill resopnse // return store.NewGetOrderItemsOK(). WithPayload(res) }
встроенная валидация OrderItems: type: object properties: message: type: string maximum:
3 # swg/internal/api/models internal/api/models/order_items.go:45:55: cannot convert m.Message (type string) to type float64
шпаргалка по валидации numbers and integers - multipleOf - maximum
- minimum - exclusiveMaximum - exclusiveMinimum strings - maxLength - minLength - pattern arrays - maxItems - minItems - uniqueItems - maxContains - minContains objects - maxProperties - minProperties - required - dependentRequired any type - type - enum - const
расширения (костыли) x-omitempty x-nullable x-isnullable x-order x-go-custom-tag x-schemes x-go-name x-go-type
x-go-json-string x-go-enum-ci
юнит-тесты func GetOrderByID(param store.GetOrderByIDParams) middleware.Responder { order := models.Order{ ID:
123, PetID: 456, Quantity: 20, Status: "approved", } if param.OrderID != order.ID { return store.NewGetOrderByIDNotFound().WithPayload(&models.ErrorMessage{ Code: http.StatusNotFound, Message: http.StatusText(http.StatusNotFound), }) } return store.NewGetOrderByIDOK().WithPayload(&order) }
юнит-тесты tests := []struct { name string req store.GetOrderByIDParams code
int want string }{ { name: "good test", req: store.GetOrderByIDParams{OrderID: 123}, code: 200, want: `{"id":123,"petId":456,"quantity":20,"status":"approved"}`, }, { name: "bad test", req: store.GetOrderByIDParams{OrderID: 456}, code: 404, want: `{"message":"Not Found", "code":404}`, }, }
юнит-тесты for _, tt := range tests { t.Run(tt.name, func(t
*testing.T) { rr := httptest.NewRecorder() GetOrderByID(tt.req).WriteResponse(rr, runtime.JSONProducer()) assert.JSONEq(t, tt.want, rr.Body.String(), "wrong response body") assert.Equal(t, tt.code, rr.Code, "wrong response code") }) }
None
полезные ссылки json-schema.org/specification.html swagger.io/docs/specification/2-0 goswagger.io bit.ly/go-swagger-in-production
бонус A pluggable go-swagger (in development) github.com/ilyakaznacheev/go-plugger
бонус 2 Insomnia Designer insomnia.rest/products/designer
None
ilyakaznacheev