-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
gin-server support #385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gin-server support #385
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -662,6 +662,35 @@ func GenerateTypesForOperations(t *template.Template, ops []OperationDefinition) | |
| return buf.String(), nil | ||
| } | ||
|
|
||
| // GenerateChiServer This function generates all the go code for the ServerInterface as well as | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit. GenerateChiServer should be GenerateGinServer |
||
| // all the wrapper functions around our handlers. | ||
| func GenerateGinServer(t *template.Template, operations []OperationDefinition) (string, error) { | ||
| var buf bytes.Buffer | ||
| w := bufio.NewWriter(&buf) | ||
|
|
||
| err := t.ExecuteTemplate(w, "gin-interface.tmpl", operations) | ||
| if err != nil { | ||
| return "", errors.Wrap(err, "error generating server interface") | ||
| } | ||
|
|
||
| err = t.ExecuteTemplate(w, "gin-middleware.tmpl", operations) | ||
| if err != nil { | ||
| return "", errors.Wrap(err, "error generating server middleware") | ||
| } | ||
|
|
||
| err = t.ExecuteTemplate(w, "gin-handler.tmpl", operations) | ||
| if err != nil { | ||
| return "", errors.Wrap(err, "error generating server http handler") | ||
| } | ||
|
|
||
| err = w.Flush() | ||
| if err != nil { | ||
| return "", errors.Wrap(err, "error flushing output buffer for server") | ||
| } | ||
|
|
||
| return buf.String(), nil | ||
| } | ||
|
|
||
| // GenerateChiServer This function generates all the go code for the ServerInterface as well as | ||
| // all the wrapper functions around our handlers. | ||
| func GenerateChiServer(t *template.Template, operations []OperationDefinition) (string, error) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| // Handler creates http.Handler with routing matching OpenAPI spec. | ||
| func Handler(si ServerInterface) *gin.Engine { | ||
| return HandlerWithOptions(si, GinServerOptions{}) | ||
| } | ||
|
|
||
| type GinServerOptions struct { | ||
| BaseURL string | ||
| BaseRouter *gin.Engine | ||
| Middlewares []MiddlewareFunc | ||
| } | ||
|
|
||
| // HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. | ||
| func HandlerFromMux(si ServerInterface, r *gin.Engine) *gin.Engine { | ||
| return HandlerWithOptions(si, GinServerOptions { | ||
| BaseRouter: r, | ||
| }) | ||
| } | ||
|
|
||
| func HandlerFromMuxWithBaseURL(si ServerInterface, r *gin.Engine, baseURL string) *gin.Engine { | ||
| return HandlerWithOptions(si, GinServerOptions { | ||
| BaseURL: baseURL, | ||
| BaseRouter: r, | ||
| }) | ||
| } | ||
|
|
||
| // HandlerWithOptions creates http.Handler with additional options | ||
| func HandlerWithOptions(si ServerInterface, options GinServerOptions) *gin.Engine { | ||
| r := options.BaseRouter | ||
|
|
||
| if r == nil { | ||
| r = gin.New() | ||
| } | ||
| {{if .}}wrapper := ServerInterfaceWrapper{ | ||
| Handler: si, | ||
| HandlerMiddlewares: options.Middlewares, | ||
| } | ||
| {{end}} | ||
| {{range .}} | ||
| r.{{.Method | upper }}(options.BaseURL+"{{.Path | swaggerUriToGinUri}}", wrapper.{{.OperationId}}) | ||
| {{end}} | ||
| return r | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| // ServerInterface represents all server handlers. | ||
| type ServerInterface interface { | ||
| {{range .}}{{.SummaryAsComment }} | ||
| // ({{.Method}} {{.Path}}) | ||
| {{.OperationId}}(c *gin.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) | ||
| {{end}} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| // ServerInterfaceWrapper converts contexts to parameters. | ||
| type ServerInterfaceWrapper struct { | ||
| Handler ServerInterface | ||
| HandlerMiddlewares []MiddlewareFunc | ||
| } | ||
|
|
||
| type MiddlewareFunc func(c *gin.Context) | ||
|
|
||
| {{range .}}{{$opid := .OperationId}} | ||
|
|
||
| // {{$opid}} operation middleware | ||
| func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { | ||
|
|
||
| {{if or .RequiresParamObject (gt (len .PathParams) 0) }} | ||
| var err error | ||
| {{end}} | ||
|
|
||
| {{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" ------------- | ||
| var {{$varName := .GoVariableName}}{{$varName}} {{.TypeDef}} | ||
|
|
||
| {{if .IsPassThrough}} | ||
| {{$varName}} = c.Query("{{.ParamName}}") | ||
| {{end}} | ||
| {{if .IsJson}} | ||
| err = json.Unmarshal([]byte(c.Query("{{.ParamName}}")), &{{$varName}}) | ||
| if err != nil { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unmarshaling parameter '{{.ParamName}}' as JSON"}) | ||
| return | ||
| } | ||
| {{end}} | ||
| {{if .IsStyled}} | ||
| err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", c.Query("{{.ParamName}}"), &{{$varName}}) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be |
||
| if err != nil { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)}) | ||
| return | ||
| } | ||
| {{end}} | ||
|
|
||
| {{end}} | ||
|
|
||
| {{range .SecurityDefinitions}} | ||
| c.Set({{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}}) | ||
| {{end}} | ||
|
|
||
| {{if .RequiresParamObject}} | ||
| // Parameter object where we will unmarshal all parameters from the context | ||
| var params {{.OperationId}}Params | ||
|
|
||
| {{range $paramIdx, $param := .QueryParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" ------------- | ||
| if paramValue := c.Query("{{.ParamName}}"); paramValue != "" { | ||
|
|
||
| {{if .IsPassThrough}} | ||
| params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue | ||
| {{end}} | ||
|
|
||
| {{if .IsJson}} | ||
| var value {{.TypeDef}} | ||
| err = json.Unmarshal([]byte(paramValue), &value) | ||
| if err != nil { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unmarshaling parameter '{{.ParamName}}' as JSON"}) | ||
| return | ||
| } | ||
|
|
||
| params.{{.GoName}} = {{if not .Required}}&{{end}}value | ||
| {{end}} | ||
| }{{if .Required}} else { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": "Query argument {{.ParamName}} is required, but not found"}) | ||
| return | ||
| }{{end}} | ||
| {{if .IsStyled}} | ||
| err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", c.Request.URL.Query(), ¶ms.{{.GoName}}) | ||
| if err != nil { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)}) | ||
| return | ||
| } | ||
| {{end}} | ||
| {{end}} | ||
|
|
||
| {{if .HeaderParams}} | ||
| headers := r.Header | ||
|
|
||
| {{range .HeaderParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} header parameter "{{.ParamName}}" ------------- | ||
| if valueList, found := headers[http.CanonicalHeaderKey("{{.ParamName}}")]; found { | ||
| var {{.GoName}} {{.TypeDef}} | ||
| n := len(valueList) | ||
| if n != 1 { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Expected one value for {{.ParamName}}, got %d", n)}) | ||
| return | ||
| } | ||
|
|
||
| {{if .IsPassThrough}} | ||
| params.{{.GoName}} = {{if not .Required}}&{{end}}valueList[0] | ||
| {{end}} | ||
|
|
||
| {{if .IsJson}} | ||
| err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}}) | ||
| if err != nil { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unmarshaling parameter '{{.ParamName}}' as JSON"}) | ||
| return | ||
| } | ||
| {{end}} | ||
|
|
||
| {{if .IsStyled}} | ||
| err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}}) | ||
| if err != nil { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)}) | ||
| return | ||
| } | ||
| {{end}} | ||
|
|
||
| params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}} | ||
|
|
||
| } {{if .Required}}else { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": fmt.Sprintf("Header parameter {{.ParamName}} is required, but not found: %s", err)}) | ||
| return | ||
| }{{end}} | ||
|
|
||
| {{end}} | ||
| {{end}} | ||
|
|
||
| {{range .CookieParams}} | ||
| var cookie *http.Cookie | ||
|
|
||
| if cookie, err = c.Cookie("{{.ParamName}}"); err == nil { | ||
|
|
||
| {{- if .IsPassThrough}} | ||
| params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value | ||
| {{end}} | ||
|
|
||
| {{- if .IsJson}} | ||
| var value {{.TypeDef}} | ||
| var decoded string | ||
| decoded, err := url.QueryUnescape(cookie.Value) | ||
| if err != nil { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unescaping cookie parameter '{{.ParamName}}'"}) | ||
| return | ||
| } | ||
|
|
||
| err = json.Unmarshal([]byte(decoded), &value) | ||
| if err != nil { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": "Error unmarshaling parameter '{{.ParamName}}' as JSON"}) | ||
| return | ||
| } | ||
|
|
||
| params.{{.GoName}} = {{if not .Required}}&{{end}}value | ||
| {{end}} | ||
|
|
||
| {{- if .IsStyled}} | ||
| var value {{.TypeDef}} | ||
| err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value) | ||
| if err != nil { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": "Invalid format for parameter {{.ParamName}}: %s"}) | ||
| return | ||
| } | ||
| params.{{.GoName}} = {{if not .Required}}&{{end}}value | ||
| {{end}} | ||
|
|
||
| } | ||
|
|
||
| {{- if .Required}} else { | ||
| c.JSON(http.StatusBadRequest, gin.H{"msg": "Query argument {{.ParamName}} is required, but not found"}) | ||
| return | ||
| } | ||
| {{- end}} | ||
| {{end}} | ||
| {{end}} | ||
|
|
||
| for _, middleware := range siw.HandlerMiddlewares { | ||
| middleware(c) | ||
| } | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe you want a |
||
| siw.Handler.{{.OperationId}}(c{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}}) | ||
| } | ||
| {{end}} | ||
|
|
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit. GenerateChiServer should be GenerateGinServer