mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-10-13 16:03:43 +00:00
Add tests with optional body for go-server (#22034)
* add tests with optional body for go-server * update workfllow
This commit is contained in:
parent
d8d9744154
commit
c1931c10da
7
.github/workflows/samples-go.yaml
vendored
7
.github/workflows/samples-go.yaml
vendored
@ -6,13 +6,13 @@ on:
|
||||
- 'samples/server/petstore/go-echo-server/**'
|
||||
- 'samples/server/petstore/go-api-server/**'
|
||||
- 'samples/server/petstore/go-chi-server/**'
|
||||
- 'samples/server/others/go-server/no-body-path-params/**'
|
||||
- 'samples/server/others/go-server/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'samples/server/petstore/go-echo-server/**'
|
||||
- 'samples/server/petstore/go-api-server/**'
|
||||
- 'samples/server/petstore/go-chi-server/**'
|
||||
- 'samples/server/others/go-server/no-body-path-params/**'
|
||||
- 'samples/server/others/go-server/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -26,6 +26,7 @@ jobs:
|
||||
- samples/server/petstore/go-api-server/
|
||||
- samples/server/petstore/go-chi-server/
|
||||
- samples/server/others/go-server/no-body-path-params/
|
||||
- samples/server/others/go-server/optional-body/
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-go@v6
|
||||
@ -58,4 +59,4 @@ jobs:
|
||||
go mod tidy
|
||||
- name: Run tests
|
||||
working-directory: ${{ matrix.sample }}
|
||||
run: go test ./samples_tests -v
|
||||
run: go test ./samples_tests -v
|
||||
|
8
bin/configs/go-server-optional-body.yaml
Normal file
8
bin/configs/go-server-optional-body.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
generatorName: go-server
|
||||
outputDir: samples/server/others/go-server/optional-body
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/optional_body.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/go-server
|
||||
additionalProperties:
|
||||
hideGenerationTimestamp: "true"
|
||||
packageName: petstoreserver
|
||||
addResponseHeaders: true
|
@ -0,0 +1,35 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: optional body
|
||||
version: 1.0.1
|
||||
servers:
|
||||
- url: https://api.123.com/api/v1
|
||||
tags:
|
||||
- name: just-api
|
||||
description: Everything about API functions
|
||||
paths:
|
||||
/silly:
|
||||
post:
|
||||
tags:
|
||||
- just-api
|
||||
operationId: send_optional_payload
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Payload"
|
||||
responses:
|
||||
'200':
|
||||
description: Successful operation
|
||||
content:
|
||||
application/text:
|
||||
schema:
|
||||
type: string
|
||||
components:
|
||||
schemas:
|
||||
Payload:
|
||||
type: object
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
description: Some kind of token - usually received by Email
|
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
@ -0,0 +1,14 @@
|
||||
Dockerfile
|
||||
README.md
|
||||
api/openapi.yaml
|
||||
go.mod
|
||||
go/api.go
|
||||
go/api_just_api.go
|
||||
go/api_just_api_service.go
|
||||
go/error.go
|
||||
go/helpers.go
|
||||
go/impl.go
|
||||
go/logger.go
|
||||
go/model_payload.go
|
||||
go/routers.go
|
||||
main.go
|
@ -0,0 +1 @@
|
||||
7.16.0-SNAPSHOT
|
15
samples/server/others/go-server/optional-body/Dockerfile
Normal file
15
samples/server/others/go-server/optional-body/Dockerfile
Normal file
@ -0,0 +1,15 @@
|
||||
FROM golang:1.19 AS build
|
||||
WORKDIR /go/src
|
||||
COPY go ./go
|
||||
COPY main.go .
|
||||
COPY go.sum .
|
||||
COPY go.mod .
|
||||
|
||||
ENV CGO_ENABLED=0
|
||||
|
||||
RUN go build -o petstoreserver .
|
||||
|
||||
FROM scratch AS runtime
|
||||
COPY --from=build /go/src/petstoreserver ./
|
||||
EXPOSE 8080/tcp
|
||||
ENTRYPOINT ["./petstoreserver"]
|
35
samples/server/others/go-server/optional-body/README.md
Normal file
35
samples/server/others/go-server/optional-body/README.md
Normal file
@ -0,0 +1,35 @@
|
||||
# Go API Server for petstoreserver
|
||||
|
||||
No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
|
||||
## Overview
|
||||
This server was generated by the [openapi-generator]
|
||||
(https://openapi-generator.tech) project.
|
||||
By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub.
|
||||
|
||||
To see how to make this your own, look here:
|
||||
|
||||
[README](https://openapi-generator.tech)
|
||||
|
||||
- API version: 1.0.1
|
||||
- Generator version: 7.16.0-SNAPSHOT
|
||||
|
||||
|
||||
### Running the server
|
||||
To run the server, follow these simple steps:
|
||||
|
||||
```
|
||||
go run main.go
|
||||
```
|
||||
|
||||
The server will be available on `http://localhost:8080`.
|
||||
|
||||
To run the server in a docker container
|
||||
```
|
||||
docker build --network=host -t petstoreserver .
|
||||
```
|
||||
|
||||
Once image is built use
|
||||
```
|
||||
docker run --rm -it petstoreserver
|
||||
```
|
@ -0,0 +1,37 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: optional body
|
||||
version: 1.0.1
|
||||
servers:
|
||||
- url: https://api.123.com/api/v1
|
||||
tags:
|
||||
- description: Everything about API functions
|
||||
name: just-api
|
||||
paths:
|
||||
/silly:
|
||||
post:
|
||||
operationId: send_optional_payload
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Payload"
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/text:
|
||||
schema:
|
||||
type: string
|
||||
description: Successful operation
|
||||
tags:
|
||||
- just-api
|
||||
components:
|
||||
schemas:
|
||||
Payload:
|
||||
example:
|
||||
token: token
|
||||
properties:
|
||||
token:
|
||||
description: Some kind of token - usually received by Email
|
||||
type: string
|
||||
type: object
|
4
samples/server/others/go-server/optional-body/go.mod
Normal file
4
samples/server/others/go-server/optional-body/go.mod
Normal file
@ -0,0 +1,4 @@
|
||||
module github.com/GIT_USER_ID/GIT_REPO_ID
|
||||
|
||||
go 1.18
|
||||
|
34
samples/server/others/go-server/optional-body/go/api.go
Normal file
34
samples/server/others/go-server/optional-body/go/api.go
Normal file
@ -0,0 +1,34 @@
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
/*
|
||||
* optional body
|
||||
*
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* API version: 1.0.1
|
||||
*/
|
||||
|
||||
package petstoreserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
||||
|
||||
// JustApiAPIRouter defines the required methods for binding the api requests to a responses for the JustApiAPI
|
||||
// The JustApiAPIRouter implementation should parse necessary information from the http request,
|
||||
// pass the data to a JustApiAPIServicer to perform the required actions, then write the service results to the http response.
|
||||
type JustApiAPIRouter interface {
|
||||
SendOptionalPayload(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
|
||||
// JustApiAPIServicer defines the api actions for the JustApiAPI service
|
||||
// This interface intended to stay up to date with the openapi yaml used to generate it,
|
||||
// while the service implementation can be ignored with the .openapi-generator-ignore file
|
||||
// and updated with the logic required for the API.
|
||||
type JustApiAPIServicer interface {
|
||||
SendOptionalPayload(context.Context, Payload) (ImplResponse, error)
|
||||
}
|
102
samples/server/others/go-server/optional-body/go/api_just_api.go
Normal file
102
samples/server/others/go-server/optional-body/go/api_just_api.go
Normal file
@ -0,0 +1,102 @@
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
/*
|
||||
* optional body
|
||||
*
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* API version: 1.0.1
|
||||
*/
|
||||
|
||||
package petstoreserver
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// JustApiAPIController binds http requests to an api service and writes the service results to the http response
|
||||
type JustApiAPIController struct {
|
||||
service JustApiAPIServicer
|
||||
errorHandler ErrorHandler
|
||||
}
|
||||
|
||||
// JustApiAPIOption for how the controller is set up.
|
||||
type JustApiAPIOption func(*JustApiAPIController)
|
||||
|
||||
// WithJustApiAPIErrorHandler inject ErrorHandler into controller
|
||||
func WithJustApiAPIErrorHandler(h ErrorHandler) JustApiAPIOption {
|
||||
return func(c *JustApiAPIController) {
|
||||
c.errorHandler = h
|
||||
}
|
||||
}
|
||||
|
||||
// NewJustApiAPIController creates a default api controller
|
||||
func NewJustApiAPIController(s JustApiAPIServicer, opts ...JustApiAPIOption) *JustApiAPIController {
|
||||
controller := &JustApiAPIController{
|
||||
service: s,
|
||||
errorHandler: DefaultErrorHandler,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(controller)
|
||||
}
|
||||
|
||||
return controller
|
||||
}
|
||||
|
||||
// Routes returns all the api routes for the JustApiAPIController
|
||||
func (c *JustApiAPIController) Routes() Routes {
|
||||
return Routes{
|
||||
"SendOptionalPayload": Route{
|
||||
"SendOptionalPayload",
|
||||
strings.ToUpper("Post"),
|
||||
"/api/v1/silly",
|
||||
c.SendOptionalPayload,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// OrderedRoutes returns all the api routes in a deterministic order for the JustApiAPIController
|
||||
func (c *JustApiAPIController) OrderedRoutes() []Route {
|
||||
return []Route{
|
||||
Route{
|
||||
"SendOptionalPayload",
|
||||
strings.ToUpper("Post"),
|
||||
"/api/v1/silly",
|
||||
c.SendOptionalPayload,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// SendOptionalPayload -
|
||||
func (c *JustApiAPIController) SendOptionalPayload(w http.ResponseWriter, r *http.Request) {
|
||||
var payloadParam Payload
|
||||
d := json.NewDecoder(r.Body)
|
||||
d.DisallowUnknownFields()
|
||||
if err := d.Decode(&payloadParam); err != nil && !errors.Is(err, io.EOF) {
|
||||
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
|
||||
return
|
||||
}
|
||||
if err := AssertPayloadRequired(payloadParam); err != nil {
|
||||
c.errorHandler(w, r, err, nil)
|
||||
return
|
||||
}
|
||||
if err := AssertPayloadConstraints(payloadParam); err != nil {
|
||||
c.errorHandler(w, r, err, nil)
|
||||
return
|
||||
}
|
||||
result, err := c.service.SendOptionalPayload(r.Context(), payloadParam)
|
||||
// If an error occurred, encode the error with the status code
|
||||
if err != nil {
|
||||
c.errorHandler(w, r, err, &result)
|
||||
return
|
||||
}
|
||||
// If no error, encode the body and the result code
|
||||
_ = EncodeJSONResponse(result.Body, &result.Code, result.Headers, w)
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
/*
|
||||
* optional body
|
||||
*
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* API version: 1.0.1
|
||||
*/
|
||||
|
||||
package petstoreserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// JustApiAPIService is a service that implements the logic for the JustApiAPIServicer
|
||||
// This service should implement the business logic for every endpoint for the JustApiAPI API.
|
||||
// Include any external packages or services that will be required by this service.
|
||||
type JustApiAPIService struct {
|
||||
}
|
||||
|
||||
// NewJustApiAPIService creates a default api service
|
||||
func NewJustApiAPIService() *JustApiAPIService {
|
||||
return &JustApiAPIService{}
|
||||
}
|
||||
|
||||
// SendOptionalPayload -
|
||||
func (s *JustApiAPIService) SendOptionalPayload(ctx context.Context, payload Payload) (ImplResponse, error) {
|
||||
// TODO - update SendOptionalPayload with the required logic for this service method.
|
||||
// Add api_just_api_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
|
||||
|
||||
// TODO: Uncomment the next line to return response Response(200, string{}) or use other options such as http.Ok ...
|
||||
// return Response(200, string{}), nil
|
||||
|
||||
return Response(http.StatusNotImplemented, nil), errors.New("SendOptionalPayload method not implemented")
|
||||
}
|
74
samples/server/others/go-server/optional-body/go/error.go
Normal file
74
samples/server/others/go-server/optional-body/go/error.go
Normal file
@ -0,0 +1,74 @@
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
/*
|
||||
* optional body
|
||||
*
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* API version: 1.0.1
|
||||
*/
|
||||
|
||||
package petstoreserver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrTypeAssertionError is thrown when type an interface does not match the asserted type
|
||||
ErrTypeAssertionError = errors.New("unable to assert type")
|
||||
)
|
||||
|
||||
// ParsingError indicates that an error has occurred when parsing request parameters
|
||||
type ParsingError struct {
|
||||
Param string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *ParsingError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
func (e *ParsingError) Error() string {
|
||||
if e.Param == "" {
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
return e.Param + ": " + e.Err.Error()
|
||||
}
|
||||
|
||||
// RequiredError indicates that an error has occurred when parsing request parameters
|
||||
type RequiredError struct {
|
||||
Field string
|
||||
}
|
||||
|
||||
func (e *RequiredError) Error() string {
|
||||
return fmt.Sprintf("required field '%s' is zero value.", e.Field)
|
||||
}
|
||||
|
||||
// ErrorHandler defines the required method for handling error. You may implement it and inject this into a controller if
|
||||
// you would like errors to be handled differently from the DefaultErrorHandler
|
||||
type ErrorHandler func(w http.ResponseWriter, r *http.Request, err error, result *ImplResponse)
|
||||
|
||||
// DefaultErrorHandler defines the default logic on how to handle errors from the controller. Any errors from parsing
|
||||
// request params will return a StatusBadRequest. Otherwise, the error code originating from the servicer will be used.
|
||||
func DefaultErrorHandler(w http.ResponseWriter, _ *http.Request, err error, result *ImplResponse) {
|
||||
var parsingErr *ParsingError
|
||||
if ok := errors.As(err, &parsingErr); ok {
|
||||
// Handle parsing errors
|
||||
_ = EncodeJSONResponse(err.Error(), func(i int) *int { return &i }(http.StatusBadRequest), map[string][]string{}, w)
|
||||
return
|
||||
}
|
||||
|
||||
var requiredErr *RequiredError
|
||||
if ok := errors.As(err, &requiredErr); ok {
|
||||
// Handle missing required errors
|
||||
_ = EncodeJSONResponse(err.Error(), func(i int) *int { return &i }(http.StatusUnprocessableEntity), map[string][]string{}, w)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle all other errors
|
||||
_ = EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w)
|
||||
}
|
371
samples/server/others/go-server/optional-body/go/helpers.go
Normal file
371
samples/server/others/go-server/optional-body/go/helpers.go
Normal file
@ -0,0 +1,371 @@
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
/*
|
||||
* optional body
|
||||
*
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* API version: 1.0.1
|
||||
*/
|
||||
|
||||
package petstoreserver
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const errMsgRequiredMissing = "required parameter is missing"
|
||||
const errMsgMinValueConstraint = "provided parameter is not respecting minimum value constraint"
|
||||
const errMsgMaxValueConstraint = "provided parameter is not respecting maximum value constraint"
|
||||
|
||||
// Response return a ImplResponse struct filled
|
||||
func Response(code int, body interface{}) ImplResponse {
|
||||
return ImplResponse {
|
||||
Code: code,
|
||||
Headers: nil,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
|
||||
// ResponseWithHeaders return a ImplResponse struct filled, including headers
|
||||
func ResponseWithHeaders(code int, headers map[string][]string, body interface{}) ImplResponse {
|
||||
return ImplResponse {
|
||||
Code: code,
|
||||
Headers: headers,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
|
||||
// IsZeroValue checks if the val is the zero-ed value.
|
||||
func IsZeroValue(val interface{}) bool {
|
||||
return val == nil || reflect.DeepEqual(val, reflect.Zero(reflect.TypeOf(val)).Interface())
|
||||
}
|
||||
|
||||
// AssertRecurseInterfaceRequired recursively checks each struct in a slice against the callback.
|
||||
// This method traverse nested slices in a preorder fashion.
|
||||
func AssertRecurseInterfaceRequired[T any](obj interface{}, callback func(T) error) error {
|
||||
return AssertRecurseValueRequired(reflect.ValueOf(obj), callback)
|
||||
}
|
||||
|
||||
// AssertRecurseValueRequired checks each struct in the nested slice against the callback.
|
||||
// This method traverse nested slices in a preorder fashion. ErrTypeAssertionError is thrown if
|
||||
// the underlying struct does not match type T.
|
||||
func AssertRecurseValueRequired[T any](value reflect.Value, callback func(T) error) error {
|
||||
switch value.Kind() {
|
||||
// If it is a struct we check using callback
|
||||
case reflect.Struct:
|
||||
obj, ok := value.Interface().(T)
|
||||
if !ok {
|
||||
return ErrTypeAssertionError
|
||||
}
|
||||
|
||||
if err := callback(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If it is a slice we continue recursion
|
||||
case reflect.Slice:
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
if err := AssertRecurseValueRequired(value.Index(i), callback); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeJSONResponse uses the json encoder to write an interface to the http response with an optional status code
|
||||
func EncodeJSONResponse(i interface{}, status *int, headers map[string][]string, w http.ResponseWriter) error {
|
||||
wHeader := w.Header()
|
||||
for key, values := range headers {
|
||||
for _, value := range values {
|
||||
wHeader.Add(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
f, ok := i.(*os.File)
|
||||
if ok {
|
||||
data, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wHeader.Set("Content-Type", http.DetectContentType(data))
|
||||
wHeader.Set("Content-Disposition", "attachment; filename="+f.Name())
|
||||
if status != nil {
|
||||
w.WriteHeader(*status)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
return err
|
||||
}
|
||||
wHeader.Set("Content-Type", "application/json; charset=UTF-8")
|
||||
|
||||
if status != nil {
|
||||
w.WriteHeader(*status)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
if i != nil {
|
||||
return json.NewEncoder(w).Encode(i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadFormFileToTempFile reads file data from a request form and writes it to a temporary file
|
||||
func ReadFormFileToTempFile(r *http.Request, key string) (*os.File, error) {
|
||||
_, fileHeader, err := r.FormFile(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return readFileHeaderToTempFile(fileHeader)
|
||||
}
|
||||
|
||||
// ReadFormFilesToTempFiles reads files array data from a request form and writes it to a temporary files
|
||||
func ReadFormFilesToTempFiles(r *http.Request, key string) ([]*os.File, error) {
|
||||
if err := r.ParseMultipartForm(32 << 20); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
files := make([]*os.File, 0, len(r.MultipartForm.File[key]))
|
||||
|
||||
for _, fileHeader := range r.MultipartForm.File[key] {
|
||||
file, err := readFileHeaderToTempFile(fileHeader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
files = append(files, file)
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// readFileHeaderToTempFile reads multipart.FileHeader and writes it to a temporary file
|
||||
func readFileHeaderToTempFile(fileHeader *multipart.FileHeader) (*os.File, error) {
|
||||
formFile, err := fileHeader.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer formFile.Close()
|
||||
|
||||
// Use .* as suffix, because the asterisk is a placeholder for the random value,
|
||||
// and the period allows consumers of this file to remove the suffix to obtain the original file name
|
||||
file, err := os.CreateTemp("", fileHeader.Filename+".*")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
_, err = io.Copy(file, formFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func parseTimes(param string) ([]time.Time, error) {
|
||||
splits := strings.Split(param, ",")
|
||||
times := make([]time.Time, 0, len(splits))
|
||||
for _, v := range splits {
|
||||
t, err := parseTime(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
times = append(times, t)
|
||||
}
|
||||
return times, nil
|
||||
}
|
||||
|
||||
// parseTime will parses a string parameter into a time.Time using the RFC3339 format
|
||||
func parseTime(param string) (time.Time, error) {
|
||||
if param == "" {
|
||||
return time.Time{}, nil
|
||||
}
|
||||
return time.Parse(time.RFC3339, param)
|
||||
}
|
||||
|
||||
type Number interface {
|
||||
~int32 | ~int64 | ~float32 | ~float64
|
||||
}
|
||||
|
||||
type ParseString[T Number | string | bool] func(v string) (T, error)
|
||||
|
||||
// parseFloat64 parses a string parameter to an float64.
|
||||
func parseFloat64(param string) (float64, error) {
|
||||
if param == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return strconv.ParseFloat(param, 64)
|
||||
}
|
||||
|
||||
// parseFloat32 parses a string parameter to an float32.
|
||||
func parseFloat32(param string) (float32, error) {
|
||||
if param == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
v, err := strconv.ParseFloat(param, 32)
|
||||
return float32(v), err
|
||||
}
|
||||
|
||||
// parseInt64 parses a string parameter to an int64.
|
||||
func parseInt64(param string) (int64, error) {
|
||||
if param == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return strconv.ParseInt(param, 10, 64)
|
||||
}
|
||||
|
||||
// parseInt32 parses a string parameter to an int32.
|
||||
func parseInt32(param string) (int32, error) {
|
||||
if param == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
val, err := strconv.ParseInt(param, 10, 32)
|
||||
return int32(val), err
|
||||
}
|
||||
|
||||
// parseBool parses a string parameter to an bool.
|
||||
func parseBool(param string) (bool, error) {
|
||||
if param == "" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return strconv.ParseBool(param)
|
||||
}
|
||||
|
||||
type Operation[T Number | string | bool] func(actual string) (T, bool, error)
|
||||
|
||||
func WithRequire[T Number | string | bool](parse ParseString[T]) Operation[T] {
|
||||
var empty T
|
||||
return func(actual string) (T, bool, error) {
|
||||
if actual == "" {
|
||||
return empty, false, errors.New(errMsgRequiredMissing)
|
||||
}
|
||||
|
||||
v, err := parse(actual)
|
||||
return v, false, err
|
||||
}
|
||||
}
|
||||
|
||||
func WithDefaultOrParse[T Number | string | bool](def T, parse ParseString[T]) Operation[T] {
|
||||
return func(actual string) (T, bool, error) {
|
||||
if actual == "" {
|
||||
return def, true, nil
|
||||
}
|
||||
|
||||
v, err := parse(actual)
|
||||
return v, false, err
|
||||
}
|
||||
}
|
||||
|
||||
func WithParse[T Number | string | bool](parse ParseString[T]) Operation[T] {
|
||||
return func(actual string) (T, bool, error) {
|
||||
v, err := parse(actual)
|
||||
return v, false, err
|
||||
}
|
||||
}
|
||||
|
||||
type Constraint[T Number | string | bool] func(actual T) error
|
||||
|
||||
func WithMinimum[T Number](expected T) Constraint[T] {
|
||||
return func(actual T) error {
|
||||
if actual < expected {
|
||||
return errors.New(errMsgMinValueConstraint)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithMaximum[T Number](expected T) Constraint[T] {
|
||||
return func(actual T) error {
|
||||
if actual > expected {
|
||||
return errors.New(errMsgMaxValueConstraint)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// parseNumericParameter parses a numeric parameter to its respective type.
|
||||
func parseNumericParameter[T Number](param string, fn Operation[T], checks ...Constraint[T]) (T, error) {
|
||||
v, ok, err := fn(param)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !ok {
|
||||
for _, check := range checks {
|
||||
if err := check(v); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// parseBoolParameter parses a string parameter to a bool
|
||||
func parseBoolParameter(param string, fn Operation[bool]) (bool, error) {
|
||||
v, _, err := fn(param)
|
||||
return v, err
|
||||
}
|
||||
|
||||
// parseNumericArrayParameter parses a string parameter containing array of values to its respective type.
|
||||
func parseNumericArrayParameter[T Number](param, delim string, required bool, fn Operation[T], checks ...Constraint[T]) ([]T, error) {
|
||||
if param == "" {
|
||||
if required {
|
||||
return nil, errors.New(errMsgRequiredMissing)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
str := strings.Split(param, delim)
|
||||
values := make([]T, len(str))
|
||||
|
||||
for i, s := range str {
|
||||
v, ok, err := fn(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !ok {
|
||||
for _, check := range checks {
|
||||
if err := check(v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
values[i] = v
|
||||
}
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// parseQuery parses query parameters and returns an error if any malformed value pairs are encountered.
|
||||
func parseQuery(rawQuery string) (url.Values, error) {
|
||||
return url.ParseQuery(rawQuery)
|
||||
}
|
18
samples/server/others/go-server/optional-body/go/impl.go
Normal file
18
samples/server/others/go-server/optional-body/go/impl.go
Normal file
@ -0,0 +1,18 @@
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
/*
|
||||
* optional body
|
||||
*
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* API version: 1.0.1
|
||||
*/
|
||||
|
||||
package petstoreserver
|
||||
|
||||
// ImplResponse defines an implementation response with error code and the associated body
|
||||
type ImplResponse struct {
|
||||
Code int
|
||||
Headers map[string][]string
|
||||
Body interface{}
|
||||
}
|
33
samples/server/others/go-server/optional-body/go/logger.go
Normal file
33
samples/server/others/go-server/optional-body/go/logger.go
Normal file
@ -0,0 +1,33 @@
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
/*
|
||||
* optional body
|
||||
*
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* API version: 1.0.1
|
||||
*/
|
||||
|
||||
package petstoreserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Logger(inner http.Handler, name string) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
|
||||
inner.ServeHTTP(w, r)
|
||||
|
||||
log.Printf(
|
||||
"%s %s %s %s",
|
||||
r.Method,
|
||||
r.RequestURI,
|
||||
name,
|
||||
time.Since(start),
|
||||
)
|
||||
})
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
/*
|
||||
* optional body
|
||||
*
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* API version: 1.0.1
|
||||
*/
|
||||
|
||||
package petstoreserver
|
||||
|
||||
|
||||
|
||||
|
||||
type Payload struct {
|
||||
|
||||
// Some kind of token - usually received by Email
|
||||
Token string `json:"token,omitempty"`
|
||||
}
|
||||
|
||||
// AssertPayloadRequired checks if the required fields are not zero-ed
|
||||
func AssertPayloadRequired(obj Payload) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssertPayloadConstraints checks if the values respects the defined constraints
|
||||
func AssertPayloadConstraints(obj Payload) error {
|
||||
return nil
|
||||
}
|
52
samples/server/others/go-server/optional-body/go/routers.go
Normal file
52
samples/server/others/go-server/optional-body/go/routers.go
Normal file
@ -0,0 +1,52 @@
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
/*
|
||||
* optional body
|
||||
*
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* API version: 1.0.1
|
||||
*/
|
||||
|
||||
package petstoreserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// A Route defines the parameters for an api endpoint
|
||||
type Route struct {
|
||||
Name string
|
||||
Method string
|
||||
Pattern string
|
||||
HandlerFunc http.HandlerFunc
|
||||
}
|
||||
|
||||
// Routes is a map of defined api endpoints
|
||||
type Routes map[string]Route
|
||||
|
||||
// Router defines the required methods for retrieving api routes
|
||||
type Router interface {
|
||||
Routes() Routes
|
||||
OrderedRoutes() []Route
|
||||
}
|
||||
|
||||
// NewRouter creates a new router for any number of api routers
|
||||
func NewRouter(routers ...Router) *mux.Router {
|
||||
router := mux.NewRouter().StrictSlash(true)
|
||||
for _, api := range routers {
|
||||
for _, route := range api.OrderedRoutes() {
|
||||
var handler http.Handler = route.HandlerFunc
|
||||
handler = Logger(handler, route.Name)
|
||||
|
||||
router.
|
||||
Methods(route.Method).
|
||||
Path(route.Pattern).
|
||||
Name(route.Name).
|
||||
Handler(handler)
|
||||
}
|
||||
}
|
||||
|
||||
return router
|
||||
}
|
29
samples/server/others/go-server/optional-body/main.go
Normal file
29
samples/server/others/go-server/optional-body/main.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
/*
|
||||
* optional body
|
||||
*
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* API version: 1.0.1
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
petstoreserver "github.com/GIT_USER_ID/GIT_REPO_ID/go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Printf("Server started")
|
||||
|
||||
JustApiAPIService := petstoreserver.NewJustApiAPIService()
|
||||
JustApiAPIController := petstoreserver.NewJustApiAPIController(JustApiAPIService)
|
||||
|
||||
router := petstoreserver.NewRouter(JustApiAPIController)
|
||||
|
||||
log.Fatal(http.ListenAndServe(":8080", router))
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user