ã¹ã¿ãã£ãµããªå°ä¸é«ã§ã¨ã³ã¸ãã¢ãªã³ã°ããã¼ã¸ã£ã¼ãã½ããã¦ã§ã¢ã¨ã³ã¸ãã¢ããã¦ãã @pankona ã§ãã
æ¬ç¨¿ã§ã¯ oapi-codegen ã® strict-server ãªãã·ã§ã³ã使ã£ãéçºäºä¾ãç´¹ä»ãã¾ãã
OpenAPI 㨠oapi-codegen
OpenAPI ã¨ã¯ãWeb API ã®ä»æ§ãè¨è¿°ããããã®è¦æ ¼ã®ã²ã¨ã¤ã§ããã©ã®ãã¹ãã©ããªãªã¯ã¨ã¹ããåãä»ãã¦ã©ããªã¬ã¹ãã³ã¹ãè¿ãã®ããã¨ããæ å ±ã yaml ããã㯠json ã®å½¢å¼ã§è¨è¿°ãããã¨ãã§ãã¾ãã以ä¸ã¯å ¬å¼ãµã¤ãã§ãã2024å¹´12æç¾å¨ãOpenAPI 3.1.0 ãææ°ãã¼ã¸ã§ã³ã®ããã§ãã
OpenAPI ã®è¦æ ¼ã«ãã£ã¦ API ã®ä»æ§ãè¨è¿°ãã¦ããã¨ãAPI ãå®è£ ä¸ãããã¯éç¨ã®éã«ããã¨ãã°ä»¥ä¸ã®ãããªã¡ãªãããããã¾ãã
- yaml ã json ã¯ãã®ã¾ã¾ã ã¨è¥å¹²äººéã«ã¯èªã¿ã«ããã§ãããSwagger UI ã®ãããªãã¼ã«ã使ã£ã¦äººéã«ãè¦ãããä»æ§æ¸ã®å½¢å¼ã«å¤æãããã¨ãã§ãã¾ãã
- ã¯ã©ã¤ã¢ã³ããµã¤ãã®ã³ã¼ããèªåçæãããã¨ã§ãAPI å¼ã³åºãã®ããã®å®è£ ãçç¥ã§ãã¾ããåãããè¨èªã§ããã°åå®å ¨ã« API å¼ã³åºãããããã¨ãã§ããããã«ãªãã¾ãã
- ãµã¼ãã¼ãµã¤ãã®ã³ã¼ããèªåçæãããã¨ã§ããªã¯ã¨ã¹ãã¨ã¬ã¹ãã³ã¹ã®åãå®è£ ããé¨åãçç¥ã§ãã¾ãã
- API ã®ä»æ§ã«å¤æ´ããã£ã¦ä»æ§ã®è¨è¼ãå¤æ´ããã¨ãããã³ã¼ããèªåçæãããã¨ã«ãã£ã¦å¤æ´ã«è¿½å¾ãããã¨ã容æã§ãã
ã³ã¼ãçæã®ããã®ãã¼ã«ã®ã²ã¨ã¤ã¨ãã¦ãoapi-codegen ãããã¾ãã
ã¹ã¿ãã£ãµããªãæ¯ãã¦ãããã¤ã¯ããµã¼ãã¹ã®ãã¡ãGo ã§æ¸ããã¦ãã¦ãã㤠oapi-codegen ã«ããã³ã¼ãçæãç¨ãã¦ãããµã¼ãã¼ã¢ããªããããªãã«åå¨ãã¾ããç¹ã«ç´è¿ã§ä½ããã¦ãããã®ã«ã¤ãã¦ã¯ oapi-codegen ã®ãªãã·ã§ã³ã®ã²ã¨ã¤ã§ãã strict-server ãªãã·ã§ã³ãç¨ãã¦ã³ã¼ãçæããã¦ãããã®ãå¢ãã¦ãã¾ã (ç§ãæ¨ãã¦ãã¾ã) ã
oapi-codegen ã® strict-server ãªãã·ã§ã³ã使ãã¨ä½ãå¬ããã®ã
ã³ã¼ããµã³ãã«
ãã¨ãã°ã以ä¸ã®ãã㪠yaml ãæ¸ããã¨ãã¾ããããã¯ã足跡ã®ä¸è¦§ãåå¾ãããã¨ããæ¶ç©ºã® API ã§ãã足跡ã¨ããã®ã¯ã²ã¹ãããã¯1ã®ãã¨ã§ãã
paths: /ashiatos: get: summary: Get Ashiato List operationId: getAshiatoList parameters: - name: page in: query required: true schema: type: integer - name: per_page in: query required: true schema: type: integer responses: "200": description: Success content: application/json: schema: $ref: "#/components/schemas/GetAshiatoListResponse" "400": description: Bad Request "500": description: Internal Server Error # ä¸ç¥ components: schemas: GetAshiatoListResponse: type: object properties: total_count: type: integer per_page: type: integer page: type: integer ashiato_list: type: array items: $ref: "#/components/schemas/Ashiato" required: - total_count - per_page - page - ashiato_list
ä½ãæ¸ããã¦ãããããã£ããæ¸ãã¨ã以ä¸ã®ä¸ç¹ã§ãã
- æåæã«ã¯ HTTP Status Code 200 ã¨å ±ã« GetAshiatoListResponse ãè¿ã
- å¼æ°ãæ£ãããªãå ´å㯠HTTP Status Code 400 ãè¿ã
- ãã以å¤ã®ã¨ã©ã¼ãèµ·ããã¨ã㯠HTTP Status Code 500 ãè¿ã
ãããå ã« oapi-codegen ãç¨ãã¦ãµã¼ãã¼ã®ããã®ã³ã¼ããçæããã¨ããªã¯ã¨ã¹ããã¬ã¹ãã³ã¹ã®åãããªãã¼ã·ã§ã³çãè²ã çæããã¾ããçæã¯ä»¥ä¸ã®ãããªã³ãã³ãã§è¡ãã¾ã (å è¿°ã® yaml ãã¡ã¤ã«ã openapi.ymlãçæãããã¡ã¤ã«ã generated_types.go ã§ããã¨ä»®å®ãã¦ãã¾ã) ã
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen oapi-codegen -generate strict-server,types,chi-server,spec -package openapi openapi.yml > generated_types.go
èªåçæããããã®ã®ãã¡ãããã§ã¯ä»¥ä¸ã® interface ã«æ³¨ç®ãã¾ãã
// StrictServerInterface represents all server handlers. type StrictServerInterface interface { // Get Ashiato List // (GET /ashiatos) GetAshiatoList(ctx context.Context, request GetAshiatoListRequestObject) (GetAshiatoListResponseObject, error) }
StrictServerInterface
ã¯ãoapi-codegen ãç¨ãã¦ã³ã¼ãçæãè¡ãéã« strict-server
ãªãã·ã§ã³ãä»ä¸ããã¨çæããã interface ã§ãããã® interface ã«å®ç¾©ããã¦ããé¢æ°ãå®è£
ãããã¨ã§ããµã¼ãã¼ã¢ããªãä½ã£ã¦ããã¾ãã
interface ã®ä¸èº«ãè¦ã¦ã¿ãã¨ãGetAshiatoList
ã¨ããé¢æ°ãå®ç¾©ããã¦ãã¾ãããã®é¢æ°ã¯å¼æ°ã« GetAshiatoListRequestObject
ãã¨ããæ»ãå¤ã¨ã㦠GetAshiatoListResponseObject
ãè¿å´ãããããªé¢æ°ã§ãããããã®æ§é ä½ã oapi-codegen ã«ãã£ã¦èªåçæããã¦ãã¾ããæ§é ä½ã¯ä»¥ä¸ã®ããã«å®ç¾©ããã¦ãã¾ãã
type GetAshiatoListRequestObject struct { Params GetAshiatoListParams } // GetAshiatoListParams defines parameters for GetAshiatoList. type GetAshiatoListParams struct { Page int `form:"page" json:"page"` PerPage int `form:"per_page" json:"per_page"` }
type GetAshiatoListResponseObject interface { VisitGetAshiatoListResponse(w http.ResponseWriter) error } type GetAshiatoList200JSONResponse GetAshiatoListResponse func (response GetAshiatoList200JSONResponse) VisitGetAshiatoListResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) return json.NewEncoder(w).Encode(response) } type GetAshiatoList400Response struct { } func (response GetAshiatoList400Response) VisitGetAshiatoListResponse(w http.ResponseWriter) error { w.WriteHeader(400) return nil } type GetAshiatoList500Response struct { } func (response GetAshiatoList500Response) VisitGetAshiatoListResponse(w http.ResponseWriter) error { w.WriteHeader(500) return nil }
å¬ããç¹
GetAshiatoList
ã®æ»ãå¤ã§ããã¨ããã® GetAshiatoListResponseObject
㯠interface ã§ããGetAshiatoList200JSONResponse
GetAshiatoList400Response
GetAshiatoList500Response
ãåæã«çæããã¦ããããããã®æ§é ä½ã«ã¯å·¦è¨ã® interface ãæºãããããªé¢æ°ãå®è£
ããã¦ãã¾ãã
ã¤ã¾ããGetAshiatoList
ãè¿ããã¨ãã§ããå¤ã¯ããã3ã¤ã®æ§é ä½ã«å¶éããããã¨ã«ãªãã¾ããããã3ã¤ã®æ§é ä½ã®ãã¡ã®ã²ã¨ã¤ãé¸ãã§æ»ãå¤ã¨ãããã¨ã§ãèªåçã«ã¬ã¹ãã³ã¹ã®å½¢ã«å¤æããã¦ã¯ã©ã¤ã¢ã³ãå´ã«è¿å´ããã¦ããã¾ãããã®ä»çµã¿ã¯ãä»æ§ã«æ¸ãã¦ããªãå
容ã誤ã£ã¦ã¬ã¹ãã³ã¹ãã¦ãã¾ããã¨ãé²ãã§ããã¾ã2ã
Go ã®æ¨æºã©ã¤ãã©ãªã使ã£ã¦ HTTP ãã³ãã©ãå®è£
ããå ´åãã¬ã¹ãã³ã¹ããéã«ã¯ http.ResponseWriter
ã« byte ã®é
å (å¤ãã®å ´å JSON)ãæ¸ãè¾¼ãå®è£
ããã¾ãããã®ããæ¹ã ã¨ä»»æã® byte åãæ¸ãè¾¼ãã¦ãã¾ããããä»æ§éãã®ã¬ã¹ãã³ã¹ãæ¸ãè¾¼ãã§ãããã©ãããéçºè
ãã±ã¢ããå¿
è¦ãããã¾ã (oapi-codegen ãç¨ã㦠strict-server ãªãã·ã§ã³ãã¤ããªãã£ãã¨ããåæ§ã§ã) ãStrictServerInterface
ãå®è£
ããããæ¹ãããã°ãã¬ã¹ãã³ã¹å
容ãåãéããå¿é
ã大ãã軽æ¸ããã¦ä¾¿å©ã§ãã
è£è¶³
middleware (å®çªã®å½¢ããã¦ãã) ãæ¿ã
StrictServerInterface
ãç¨ããã¨ããmiddleware ãæ§ç¯ããããã«ä»¥ä¸ã®ãããªå°ç¨ã®åãç¨æããã¦ãã¾ããGo ã® HTTP ãµã¼ãã¼ãå®è£
ããã¨ãã«ãã°ãã°ç®ã«ãããã㪠middleware ã®å½¢ã¨ã¡ãã£ã¨éã£ã¦ãã¾ãã
type StrictHTTPMiddlewareFunc func(f StrictHTTPHandlerFunc, operationID string) StrictHTTPHandlerFunc
ãã°ãã°ç®ã«ããå®çªã® middleware ã¨ããã°ã以ä¸ã®åã§ã¯ãªãã§ãããããhttp.Handler
ãå¼æ°ã«ã¨ã£ã¦ http.Handler
ãè¿å´ããé¢æ°ã®å½¢ã§ãã
func typicalMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // ä½ãå¦çããã next.ServeHTTP(w, r) }) }
chi3 ã§ãã£ãã gorilla/mux4 ã§ãã£ãããHTTP ãµã¼ãã¼ãä½ããã¨æã£ãã¨ãã«ä½¿ãããå®çªã®ã©ã¤ãã©ãªã«ã¯ middleware ãæºåããã¦ãããã®ãå¤ãããã®å½¢å¼ã¯æ¦ãå®çªã®å½¢ãè¸è¥²ããã¦ãã¾ããStrictHTTPMiddlewareFunc
ã«å½ã¦ã¯ãããã¨æãã¨ã¡ãã£ã¨ã²ã¨æéãå¿
è¦ã«ãªããä¸ä¾¿ã§ããã§ããã°ãã®ã¾ã¾ä½¿ãããã§ãããã大ä¸å¤«ã§ãããã®ã¾ã¾åå©ç¨ã§ãã¾ãã
// chi ã使ãä¾ router := chi.NewRouter() // chi ãæºåãã¦ããã¦ãã middlewares ãè¨å®ãã router.Use(chimiddleware.Logger) router.Use(chimiddleware.Recoverer) router.Use(chimiddleware.Timeout(25 * time.Second)) // requestHandler 㯠StrictServerInterface ãå®è£ ããæ§é ä½ handler := &requestHandler{} // oapi-codegen ã«èªåçæãã¦ããã£ã Handler ã¤ã³ã¹ã¿ã³ã¹çæã®ããã®é¢æ°ãå¼ã³åºã // 第äºå¼æ°ã§è¨å®ã§ããå°ç¨ã®åã® middleware ã¯è¨å®ããªã (nil ã«ãã¦ãã) h := openapi.HandlerFromMux(openapi.NewStrictHandlerWithOptions(handler, nil, openapi.StrictHTTPServerOptions{}), router) // ListenAndServe ãã server := &http.Server{ Handler: h } server.ListenAndServe()
ã¾ã¨ã
oapi-codegen ã§ãµã¼ãã¼ã¢ããªã®ã³ã¼ãçæãããã¨ãã®ãªãã·ã§ã³ã®ã²ã¨ã¤ã§ãã strict-server ãªãã·ã§ã³ãç´¹ä»ãã¾ãããä»æ§ã¨ãã¦è¨è¼ããå 容ãããµã¼ãã¼ã®å®è£ ãä¹é¢ãã¥ãããªããããã¸ã便å©ã§ãããªã¹ã¹ã¡ã§ãã
- ã²ã¹ããã㯠- Wikipedia↩
- 工夫ãããã°ããã以å¤ãè¿ããã¨ãå¯è½ããã§ãããããã¦å·¥å¤«ãããªãéãã¯å¤§ä¸å¤«↩
- https://github.com/go-chi/chi↩
- https://github.com/gorilla/mux↩