Replies: 2 comments 1 reply
-
@su8ru , having the same challenge, did you ever find a solution for this? |
Beta Was this translation helpful? Give feedback.
-
This is kindof hacky, but I think it will work for you. This is what the generated code looks like// output.go
type PostAuthLogin200ResponseHeaders struct {
SetCookie []string
}
func (response PostAuthLogin200JSONResponse) VisitPostAuthLoginResponse(w http.ResponseWriter) error {
w.Header().Set("Content-Type", "application/json")
for _, cookie := range response.Headers.SetCookie {
w.Header().Set("Set-Cookie", cookie)
}
w.WriteHeader(200)
return json.NewEncoder(w).Encode(response.Body)
} The config yamlBasically, I added # yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
package: api
output: gen.go
generate:
echo-server: true
models: true
strict-server: true
embedded-spec: true
output-options:
user-templates:
strict/strict-interface.tmpl: |
{{range .}}
{{$opid := .OperationId -}}
type {{$opid | ucFirst}}RequestObject struct {
{{range .PathParams -}}
{{.GoName | ucFirst}} {{.TypeDef}} {{.JsonTag}}
{{end -}}
{{if .RequiresParamObject -}}
Params {{$opid}}Params
{{end -}}
{{if .HasMaskedRequestContentTypes -}}
ContentType string
{{end -}}
{{$multipleBodies := gt (len .Bodies) 1 -}}
{{range .Bodies -}}
{{if $multipleBodies}}{{.NameTag}}{{end}}Body {{if eq .NameTag "Multipart"}}*multipart.Reader{{else if ne .NameTag ""}}*{{$opid}}{{.NameTag}}RequestBody{{else}}io.Reader{{end}}
{{end -}}
}
type {{$opid | ucFirst}}ResponseObject interface {
Visit{{$opid}}Response(w http.ResponseWriter) error
}
{{range .Responses}}
{{$statusCode := .StatusCode -}}
{{$hasHeaders := ne 0 (len .Headers) -}}
{{$fixedStatusCode := .HasFixedStatusCode -}}
{{$isRef := .IsRef -}}
{{$isExternalRef := .IsExternalRef -}}
{{$ref := .Ref | ucFirstWithPkgName -}}
{{$headers := .Headers -}}
{{if (and $hasHeaders (not $isRef)) -}}
type {{$opid}}{{$statusCode}}ResponseHeaders struct {
{{range .Headers -}}
{{/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CUSTOM CODE BEGIN !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */}}
{{if eq .Name "Set-Cookie" -}}
SetCookie []string
{{else -}}
{{.GoName}} {{.Schema.TypeDecl}}
{{end -}}
{{/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CUSTOM CODE END !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */}}
{{end -}}
}
{{end}}
{{range .Contents}}
{{$receiverTypeName := printf "%s%s%s%s" $opid $statusCode .NameTagOrContentType "Response"}}
{{if and $fixedStatusCode $isRef -}}
{{ if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) (eq .NameTag "Multipart") -}}
type {{$receiverTypeName}} {{$ref}}{{.NameTagOrContentType}}Response
{{else if $isExternalRef -}}
type {{$receiverTypeName}} struct { {{$ref}} }
{{else -}}
type {{$receiverTypeName}} struct{ {{$ref}}{{.NameTagOrContentType}}Response }
{{end}}
{{else if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) -}}
type {{$receiverTypeName}} {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{if and .Schema.IsRef (not .Schema.IsExternalRef)}}={{end}} {{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
{{else -}}
type {{$receiverTypeName}} struct {
Body {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
{{if $hasHeaders -}}
Headers {{if $isRef}}{{$ref}}{{else}}{{$opid}}{{$statusCode}}{{end}}ResponseHeaders
{{end -}}
{{if not $fixedStatusCode -}}
StatusCode int
{{end -}}
{{if not .HasFixedContentType -}}
ContentType string
{{end -}}
{{if not .IsSupported -}}
ContentLength int64
{{end -}}
}
{{end}}
func (response {{$receiverTypeName}}) Visit{{$opid}}Response(w http.ResponseWriter) error {
{{if eq .NameTag "Multipart" -}}
writer := multipart.NewWriter(w)
{{end -}}
w.Header().Set("Content-Type", {{if eq .NameTag "Multipart"}}{{if eq .ContentType "multipart/form-data"}}writer.FormDataContentType(){{else}}mime.FormatMediaType("{{.ContentType}}", map[string]string{"boundary": writer.Boundary()}){{end}}{{else if .HasFixedContentType }}"{{.ContentType}}"{{else}}response.ContentType{{end}})
{{if not .IsSupported -}}
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
}
{{end -}}
{{/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CUSTOM CODE BEGIN !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */}}
{{range $headers -}}
{{if eq .Name "Set-Cookie" -}}
for _, cookie := range response.Headers.SetCookie {
w.Header().Add("Set-Cookie", cookie)
}
{{else -}}
w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
{{end -}}
{{end -}}
{{/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CUSTOM CODE END !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */}}
w.WriteHeader({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
{{$hasBodyVar := or ($hasHeaders) (not $fixedStatusCode) (not .IsSupported)}}
{{if .IsJSON -}}
{{$hasUnionElements := ne 0 (len .Schema.UnionElements)}}
return json.NewEncoder(w).Encode(response{{if $hasBodyVar}}.Body{{end}}{{if $hasUnionElements}}.union{{end}})
{{else if eq .NameTag "Text" -}}
_, err := w.Write([]byte({{if $hasBodyVar}}response.Body{{else}}response{{end}}))
return err
{{else if eq .NameTag "Formdata" -}}
if form, err := runtime.MarshalForm({{if $hasBodyVar}}response.Body{{else}}response{{end}}, nil); err != nil {
return err
} else {
_, err := w.Write([]byte(form.Encode()))
return err
}
{{else if eq .NameTag "Multipart" -}}
defer writer.Close()
return {{if $hasBodyVar}}response.Body{{else}}response{{end}}(writer);
{{else -}}
if closer, ok := response.Body.(io.ReadCloser); ok {
defer closer.Close()
}
_, err := io.Copy(w, response.Body)
return err
{{end}}{{/* if eq .NameTag "JSON" */ -}}
}
{{end}}
{{if eq 0 (len .Contents) -}}
{{if and $fixedStatusCode $isRef -}}
type {{$opid}}{{$statusCode}}Response {{if not $isExternalRef}}={{end}} {{$ref}}Response
{{else -}}
type {{$opid}}{{$statusCode}}Response struct {
{{if $hasHeaders -}}
Headers {{if $isRef}}{{$ref}}{{else}}{{$opid}}{{$statusCode}}{{end}}ResponseHeaders
{{end}}
{{if not $fixedStatusCode -}}
StatusCode int
{{end -}}
}
{{end -}}
func (response {{$opid}}{{$statusCode}}Response) Visit{{$opid}}Response(w http.ResponseWriter) error {
{{range $headers -}}
{{/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CUSTOM CODE BEGIN !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */}}
{{if eq .Name "Set-Cookie" -}}
for _, cookie := range response.Headers.SetCookie {
w.Header().Add("Set-Cookie", cookie)
}
{{else -}}
w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
{{end -}}
{{/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CUSTOM CODE END !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */}}
{{end -}}
w.WriteHeader({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
return nil
}
{{end}}
{{end}}
{{end}}
// StrictServerInterface represents all server handlers.
type StrictServerInterface interface {
{{range .}}{{.SummaryAsComment }}
// ({{.Method}} {{.Path}})
{{$opid := .OperationId -}}
{{$opid}}(ctx context.Context, request {{$opid | ucFirst}}RequestObject) ({{$opid | ucFirst}}ResponseObject, error)
{{end}}{{/* range . */ -}}
} AlternativeYou can of course overwrite the strict interface template to directly pass the echo context instead. But imo, the above solution feels better. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Currently, OAS does not support situations where there are multiple
set-cookie
headers (OAI/OpenAPI-Specification#1237). This means that it is not possible to include multipleset-cookie
headers in a Strict Server response (it is possible to have bothset-cookie
andSet-Cookie
, but the fields are duplicated in Go).There is no way to access
echo.Context
in Strict Server, so it is not possible to set cookies with it.Is there a way to set multiple cookies in Strict Server?
(I looked for examples and tests, but I'm sorry if I missed anything!)
Beta Was this translation helpful? Give feedback.
All reactions