Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Go-Swagger in production
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Ilya Kaznacheev
June 25, 2020
Programming
570
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Go-Swagger in production
Ilya Kaznacheev
June 25, 2020
More Decks by Ilya Kaznacheev
See All by Ilya Kaznacheev
Road to four nines
dreamworm
0
37
Many Layers of Availability
dreamworm
0
110
Stateful Solutions: A Hands-On Guide to FSM in Golang
dreamworm
0
220
CQRS
dreamworm
0
190
Building a Cloud-Native PaaS
dreamworm
0
170
Distributed System State Management: When Transactions Are Long and SLA Is High
dreamworm
0
170
How To Create Saga-Free Distributed Transactions
dreamworm
0
90
Architectural decisions in building distributed systems
dreamworm
0
46
Распределенные транзакции без саг
dreamworm
0
220
Other Decks in Programming
See All in Programming
レビュー履歴をAIに食わせて、 Compose移行を加速するs
shihochan
0
210
自動化したのに回らない テスト運用の壁―AI時代の品質責任と生産性
mfunaki
0
500
S3 を使うアプリケーションをローカル完結で動かすことに全力を注いでみた / Running S3 Apps Offline
contour_gara
0
620
Japan Community Day at Kubecon + CloudNativeCon Japan 2026: Learning Container Privilege Control by Building My Own Low-Level Container Runtime
ternbusty
1
170
PyConJP2026_wat_Python × Signal Processing: How to Draw Pictures with Sound Using Spectrogram Art
wat
0
390
freeeにおけるEvalsの実践例の紹介
freee
PRO
0
150
MySQLとPostgreSQLって何が違うの?
akagami
0
140
AIの中の人になってみる
htkym
0
120
AI時代に学ぶ 好きなルール 嫌いなルール Linter編
shorty5121
0
150
不幸な GC
chencmd
0
740
バグを直したら useEffect が消えた
colorful12
3
700
AI Readyの正体はデータマネジメントだ メダリオン2.0の最前線
freee
PRO
0
390
Featured
See All Featured
Producing Creativity
orderedlist
PRO
348
40k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
420
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.1k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
550
Done Done
chrislema
186
16k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
410
The Limits of Empathy - UXLibs8
cassininazir
1
610
Heart Work Chapter 1 - Part 1
lfama
PRO
8
36k
A Soul's Torment
seathinner
6
3.5k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Designing for Performance
lara
611
70k
Believing is Seeing
oripsolob
1
200
Transcript
Go-Swagger in production wins and pitfalls
Ilya Kaznacheev Remote Backend SWE Founder of Golang Voronezh Host
of Z-Namespace podcast Organizer of conference and meetups Coffee geek
what swagger is?
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
why do we use swagger?
my team trying to sync API changes...
None
go-swagger
code generation swagger generate server -t internal/api --exclude-main
generated code structure internal/api ├ models │ └ ... └
restapi ├ operations │ └ ... ├ configure_<your_service_name>.go ├ doc.go ├ embedded_spec.go └ server.go
our code generation rm -rf internal/api && mkdir -p internal/api
swagger generate server -t internal/api --exclude-main go mod tidy
? and we're all set
NO
there are some problems - go-swagger is a framework, not
a library - plenty of generated types for everything - incompatible with popular http-libraries
let’s fix ’em all!
serving net/http handlers 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) }) }
simple middleware api := operations.NewSwaggerPetstoreAPI(swaggerSpec) api.InstrumentsGetMetricsHandler = instruments.GetMetricsHandlerFunc(MetricsHandler) api.AddMiddlewareFor("GET", "/metrics",
SomeMiddleware) srv := restapi.NewServer(api) srv.Serve()
middleware with custom handler 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()
setup outside of 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
custom method names /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) }
custom method names /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) }
validity checks 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
validity check cheat sheet 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
extensions (tricks) 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
Shortcuts Error: type: object required: - code - message properties:
code: type: integer message: type: string type APIError struct { code int Payload *models.Error `json:"body,omitempty"` } func (e *APIError) WriteResponse( rw http.ResponseWriter, producer runtime.Producer) { rw.WriteHeader(e.code) producer.Produce(rw, e.Payload) } func RespondError(code int, err error) *APIError { return &APIError{ code: code, Payload: &models.Error{code, err.Error()}, } }
unit tests 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) }
unit tests 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}`, }, }
unit tests 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
helpful links json-schema.org/specification.html swagger.io/docs/specification/2-0 goswagger.io bit.ly/go-swagger-in-production
ilyakaznacheev