Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Go-Swagger в продуктиве
Search
Ilya Kaznacheev
May 30, 2020
Programming
530
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Go-Swagger в продуктиве
Ilya Kaznacheev
May 30, 2020
More Decks by Ilya Kaznacheev
See All by Ilya Kaznacheev
Road to four nines
dreamworm
0
45
Many Layers of Availability
dreamworm
0
120
Stateful Solutions: A Hands-On Guide to FSM in Golang
dreamworm
0
220
CQRS
dreamworm
0
200
Building a Cloud-Native PaaS
dreamworm
0
180
Distributed System State Management: When Transactions Are Long and SLA Is High
dreamworm
0
170
How To Create Saga-Free Distributed Transactions
dreamworm
0
94
Architectural decisions in building distributed systems
dreamworm
0
50
Распределенные транзакции без саг
dreamworm
0
220
Other Decks in Programming
See All in Programming
GraphRAGのKnowledge Graphを 直接!見る/View-GraphRAG's-KnowledgeGraph-directly!
tyumugi1113
1
310
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
4
680
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
470
アクセシビリティから考える情報設計
high_g_engineer
0
370
世界の中心で、AI(App Intents)をさけぶ ー App Intents中心設計の実践ガイド
touyou
0
570
技術的負債の返済は、AI時代の複利で効く投資 — 経営としての意思決定とその遂行
curekoshimizu
0
1.3k
LL言語やWebフレームワークのPostgreSQL対応 〜DBの機能がユーザーに届くまで〜
kentaroutakeda
1
150
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
1.8k
Security issues being discussed on Web Platforms
petamoriken
0
940
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
100
Go のフラットな パッケージに 「ファイル単位の private」を 〜Linter “declscope” を作った話〜
mpyw
0
320
AIを上手に使っていこうとしたら越境せざるを得なくなった話 〜実践1年で見えた境界を越えなければならない理由と進め方〜 / Crossing borders with AI
tomoyakitaura
4
1.2k
Featured
See All Featured
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
240
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
460
New Earth Scene 8
popppiees
4
2.6k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.4k
Darren the Foodie - Storyboard
khoart
PRO
4
3.9k
Building Applications with DynamoDB
mza
96
7.2k
The Invisible Side of Design
smashingmag
301
52k
Navigating Weather and Climate Data
rabernat
0
520
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
280
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
50
10k
How to Think Like a Performance Engineer
csswizardry
28
2.8k
Typedesign – Prime Four
hannesfritz
42
3.2k
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