github.com/thetreep/go-swagger@v0.0.0-20240223100711-35af64f14f01/docs/faq/faq_model.md (about)

     1  <!-- Questions about model generation -->
     2  
     3  ## Model generation
     4  
     5  ### Custom validation
     6  _Use-Case_: is it possible to write my own validation code for custom types? If so, can someone give me an example?
     7  
     8  >Usage example:
     9  >There is bookstore, with info about books: author, title, price.
    10  > And we want that books from some author will not cost more than some price.
    11  > So I want to write and use a function ValidateBookCustom() like:
    12  ```golang
    13  if book.author == "Some author" {
    14      if book.price > 1000 {
    15         return false
    16     }
    17      else return true
    18  }
    19  ```
    20  
    21  
    22  **Answer**: there are several ways to achieve that.
    23  - reusing customized models
    24  - reusing custom go types
    25  - customizing code generation
    26  
    27  You should know that models may be generated independently from server, then reused when generating a new server.
    28  
    29  You might build on that: generating a first model, customizing the validation code, then reusing this model (possibly with some others) in your servers.
    30  
    31  Another way is to use the `x-go-type extension`, to replace type generation with a custom type.
    32  
    33  There is the opportunity to get go-swagger to reuse a predefined type to satisfy the definition in the swagger spec.
    34  Imported package and type alias may be specified as options, as shown in this example:
    35  https://github.com/thetreep/go-swagger/blob/master/fixtures/codegen/existing-model.yml#L99-L103
    36  
    37  That example reuses a type provided by a library with a package alias and type name. The code generator will respect this.
    38  
    39  You might use both, preparing a customized model from an initially generated structure, then reusing type custom type in other declarations by hinting the generator with x-go-type.
    40  
    41  Further, for repetitive customization, you might be willing to customize the generator's templates. Like in [here](https://github.com/thetreep/go-swagger/blob/master/generator/templates/schemavalidator.gotmpl)
    42  for models, or in [here](https://github.com/thetreep/go-swagger/blob/master/generator/templates/server/parameter.gotmpl) for inline parameters.
    43  
    44  Originally from issues [#997](https://github.com/thetreep/go-swagger/issues/997) and [#1334](https://github.com/thetreep/go-swagger/issues/1334)
    45  
    46  ### Non-required or nullable property?
    47  _Use-Case_: when a definition has a property N, if N is a number and is not required,
    48  the corresponding generated model has the struct flag `omitempty` for N.
    49  This means that when N has been set to 0 the generated JSON omits N, despite it being validly set to 0.
    50  
    51  I would still like to allow this variable to be unset, by setting it to null for example.
    52  This will also apply for returning objects that return false and so on.
    53  
    54  >The `"omitempty"` option specifies that the field should be omitted from the encoding if the field has an empty value,
    55  >defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string.
    56  >(from https://golang.org/pkg/encoding/json/#Marshal)
    57  
    58  **Hint**: a workaround for this is to use the extension **x-nullable:true** on properties.
    59  
    60  Originally from issue [#959](https://github.com/thetreep/go-swagger/issues/959). (*more discussion on edge cases there*).
    61  
    62  Related: [go-openapi/validate#19](https://github.com/go-openapi/validate/issues/19).
    63  
    64  ### String parameter in body and query
    65  _Use-case_: I want to create an operation with string parameter in body, but go-swagger fails while generating.
    66  
    67  When I change body to query, it works. How can I send my parameter in body with type string?
    68  
    69  This *works* (param in query):
    70  ```YAML
    71  post:
    72    description: post func
    73    operationId: postfunc
    74    parameters:
    75      - name: myparam
    76        in: query
    77        type: string
    78  ```
    79  **But this fails (param in body):**
    80  ```YAML
    81  post:
    82    description: post func
    83    operationId: postfunc
    84    parameters:
    85      - name: myparam
    86        in: body
    87        type: string
    88  ```
    89  
    90  **Answer**: add the schema definition in body. This works:
    91  ```YAML
    92  post:
    93    description: post func
    94    operationId: postfunc
    95    parameters:
    96      - name: myparam
    97        in: body
    98        required: true
    99        schema:
   100          type: string
   101  ```
   102  
   103  **Hint**: more generally, you might want to check the validity of your spec re the OpenAPI 2.0 schema before trying generation, using the `swagger validate {spec}` command.
   104  
   105  Originally from issue [#990](https://github.com/thetreep/go-swagger/issues/990).
   106  
   107  ### Request response can have different objects returned based on query parameters
   108  _Use-Case_: I have a POST request that returns different object models based on the query parameters.
   109  
   110  *Is there any way to add multiple responses under the swagger route annotation?*
   111  
   112  Like:
   113  
   114  ```YAML
   115  Responses:
   116    200: response1
   117    200: response2
   118    ... etc
   119  ```
   120  
   121  *Also is it possible to have different models for the request?*
   122  
   123  **Answer**: **No**, as this is not supported in Openapi 2.0 specification
   124  
   125  That being said, if you specify a wrapper class or base class, you can return multiple responses.
   126  
   127  For example (in pseudo-swagger):
   128  
   129  ``` YAML
   130  ResponseWrapper:
   131    type: object
   132    properties:
   133      response1:
   134        $ref: '#/definitions/response1'
   135      response2:
   136        $ref: '#/definitions/response2'
   137  ```
   138  
   139  or perhaps more elegantly:
   140  ``` YAML
   141  BaseObject:
   142    type: object
   143    properties:
   144      id:
   145        type: string
   146        format: uuid
   147  
   148  Response1:
   149    allOf:
   150      - $ref: '#/definitions/BaseObject'
   151      - type: object
   152        properties:
   153          extendedAttributeForResponse1
   154  
   155  Response2:
   156    allOf:
   157      - $ref: '#/definitions/BaseObject'
   158      - type: object
   159         properties:
   160           extendedAttribForResponse2
   161  ```
   162  
   163  Allegedly, with OpenAPI 3.0 you'll be able to use the `anyOf:` operator, with the different response types.
   164  
   165  Regarding parameters, you may also achieve this by putting in the path the query parameters that dictate the model.
   166  ``` YAML
   167  paths:
   168    "/something?objectType=thisThing":
   169        get:
   170  ...
   171    "/something?objectType=otherThing":
   172        get:
   173  ...
   174  ```
   175  
   176  Originally from issue [#932](https://github.com/thetreep/go-swagger/issues/932).
   177  
   178  ### How to validate dates and times?
   179  JSON schema and Swagger (aka OpenAPI 2.0) define ISO-8601 dates as a known format (e.g. date-time, or `yyyy-MM-dd'T'HH:mm:ss.SSS'Z`).
   180  
   181  This format definition is used by go-swagger validators.
   182  You just have to define the format as in:
   183  ```JSON
   184  {
   185    "description": "The date and time that the device was registered.",
   186    "type":"string",
   187    "format": "date-time"
   188  }
   189  ```
   190  
   191  The `go-openapi/strfmt` package supports many additional string formats for validation.
   192  
   193  Check out for more in [this repo](https://github.com/go-openapi/strfmt/tree/master/README.md). The full API
   194  is documented [here](https://godoc.org/github.com/go-openapi/strfmt).
   195  
   196  Regarding dates, this package extends validation to [RFC3339](https://tools.ietf.org/html/rfc3339) full-date format (e.g. "2006-01-02").
   197  
   198  Originally from issue [#643](https://github.com/thetreep/go-swagger/issues/643).
   199  
   200  ### Accessing the Default return value
   201  _Use-Case_: I was wondering how I would get the default response from the client?
   202  
   203  Note: see also [Access HTTP status code from client#597](https://github.com/thetreep/go-swagger/issues/597).
   204  
   205  I have a spec like this:
   206  ```YAML
   207  /deploys/{deploy_id}:
   208    get:
   209      operationId: getDeploy
   210      parameters:
   211        - name: deploy_id
   212          type: string
   213          in: path
   214          required: true
   215      responses:
   216        '200':
   217          description: OK
   218          schema:
   219            $ref: "#/definitions/deploy"
   220        default:
   221          description: error
   222          schema:
   223            $ref: "#/definitions/error"
   224  ```
   225  This spec generates two models: `GetDeployOK` and `GetDeployDefault`. The API generated will return the OK case.
   226  ```golang
   227  func (a *Client) GetDeploy(params *GetDeployParams, authInfo runtime.ClientAuthInfoWriter) (*GetDeployOK, error) {
   228      // TODO: Validate the params before sending
   229      if params == nil {
   230          params = NewGetDeployParams()
   231      }
   232  
   233      result, err := a.transport.Submit(&runtime.ClientOperation{
   234          ID: "getDeploy",
   235          Method: "GET",
   236          PathPattern: "/deploys/{deploy_id}",
   237          ProducesMediaTypes: []string{"application/json"},
   238          ConsumesMediaTypes: []string{"application/json"},
   239          Schemes: []string{"https"},
   240          Params: params,
   241          Reader: &GetDeployReader{formats: a.formats},
   242          AuthInfo: authInfo,
   243      })
   244      if err != nil {
   245          return nil, err
   246      }
   247      return result.(*GetDeployOK), nil  TODO
   248  }
   249  ```
   250  *Does that mean that, if I get a non-2xx response, I should check the err to actually be a `GetDeployDefault` reference?*
   251  
   252  Something like:
   253  ```golang
   254  resp, err := c.Operations.GetDeploy(&params, authInfo)
   255  if err != nil {
   256      if casted, ok := err.(models.GetDeployDefault); ok {
   257          // do something here....
   258      } else {
   259          false, err
   260      }
   261  }
   262  ```
   263  
   264  >I've been tracing through the code in `Runtime.Submit`: it delegates to the `GetDeployReader.ReadResponse` which makes the distinction.
   265  >However, it remains unclear how that response is actually surfaced.
   266  
   267  **Answer**: you can get pretty close to that with something like:
   268  ```golang
   269  casted, ok := err.(*operations.GetDeployDefault)
   270  ```
   271  
   272  Because it's a struct type it will be a pointer.
   273  
   274  Originally from issue [#616](https://github.com/thetreep/go-swagger/issues/616).
   275  
   276  ### How to avoid deep copies of complex data structures that need to be marshalled across the API?
   277  _Use-Case_:
   278  >An API that provides access to a complex data structure, defined and governed by a subsystem, should not have to spec the
   279  >same data model to be marshalled, as this would require a deep copy of the data structure from the subsystem to the API layer's
   280  >model universe.
   281  
   282  *How do others deal with this problem?*
   283  
   284  - If your question is "How do I write arbitrary response bodies from go-swagger generated server code?"
   285    (e.g. from subsystem structs that you have marshalled) then you may want to write your own `middleware.Responder`,
   286    which gives you direct access to the underlying `http.ResponseWriter`.
   287    At this point, though, why use go-swagger instead  of a lighter-weight framework?
   288  - If your question is "how can I generate a swagger spec from my subsystem structs?", then you could check out the `swagger generate
   289    spec` CLI command.
   290  
   291  >Further, a subsystem that builds a complex hierarchical data structure to support its own requirements for efficiency,
   292  >access, and serialization does not want the types of the API data model to be injected into its namespace.
   293  
   294  >Eventually, the subsystem can exist in many different contexts beyond the API, which is another reason it should not
   295  >become dependent on any API type.
   296  
   297  -------------
   298  
   299  _Similar Use-Case_:
   300  >A new requirement is proposed that wants API access to that complex data structure, and we decide to use go-swagger for that
   301  >implementation. It is a pure 'read' requirement, so no need for parameter validation by the API, just the ability to gain an XML
   302  >or JSON form of the data structure by a client.
   303  
   304  >Our organization decided to keep the API and subsystem layers separate, and to perform deep copies between them.
   305  >The runtime performance costs are acceptable to us, and worth it to keep API-layer dependencies out of our core library.
   306  >If someone can think of a better solution we would love to know!
   307  
   308  >If we define a data model in the swagger specification, we end up having to do a
   309  >deep copy of that data structure from subsystem to API if we want to avoid type injection.
   310  
   311  *How do you use the swagger spec to define a raw JSON or XML transfer, defined by the subsystem's types?*
   312  
   313  **Hint**: you may use the `x-go-type` model annotation that allows you to use pre-existing types as models, you annotate your spec like this:
   314  https://github.com/thetreep/go-swagger/blob/master/fixtures/codegen/existing-model.yml#L99-103
   315  
   316  Originally from issue [#948](https://github.com/thetreep/go-swagger/issues/948).
   317  
   318  ### Extra sections in POST body
   319  
   320  _Use-case_: additional properties in object
   321  
   322  If I have a swagger spec that expects
   323  
   324  {"foo": 123}
   325  
   326  and provide
   327  
   328  {"foo": 123, "blah": 345}
   329  
   330  it happily goes on about this way.
   331  
   332  Two questions:
   333  1. can I make it complain if extra stuff is included
   334  2. can I access these extra sections within the go code/handler?
   335  
   336  **Answer**: use `additionalProperties: false` or `additionalProperties: true` in your definition.
   337  when it's set to true you'll have a `map[string]interface{}` added.
   338  
   339  Originally from issue [#1337](https://github.com/thetreep/go-swagger/issues/1337).
   340  
   341  ### How to support generate type int?
   342  
   343  _Use-case_: generating `int` types
   344  
   345  > I need to use swagger to generate my modes in go code.
   346  > But I find I can hardly generate type `int`, always `int64`.
   347  > Since I need to keep back compatibility for my project, I can hardly change the type.
   348  > So in this case, does go-swagger meet this requirement?
   349  
   350  **Answer**:  int is not a good option to support when it comes to contracts.
   351  
   352  > Consider the following: you have an arm32 client on which int is int32, however your server is amd64.
   353  > At this stage it's perfectly valid for the server to return int32 max value + 1, this will cause the client to overflow.
   354  > So while go allows int as type I think for API contracts int is too ambiguous as definition leading to subtle but hard to debug failures.
   355  > Similarly other languages may choose to default to int32 type instead of int64 type regardless of platform.
   356  
   357  Originally from issue [#1205](https://github.com/thetreep/go-swagger/issues/1205).
   358  
   359  ### Generate all models necessary for specified operation
   360  
   361  _Use-case_: I'm specifying specific operations and I'd like to restrict the models to those needed for those operations. Is there a way to do that?
   362  
   363  **Answer:** when using the generate server command, a repeatable --operation=xxx is available to restrict the scope of operations.
   364  
   365   > NOTE: this option is not available for `generate model`.
   366  
   367  Originally from issue [#1427](https://github.com/thetreep/go-swagger/issues/1427).
   368  
   369  ### Generated code changes the order of properties in struct
   370  
   371  _Use-case_: the generated struct has attributes ordered differently than the original specification
   372  
   373  Example:
   374  
   375  ```yaml
   376  Product:
   377      type: "object"
   378      properties:
   379        product_id:
   380          type: "string"
   381        name:
   382          type: "string"
   383  ```
   384  Generated by "swagger generate server":
   385  ```go
   386  type Product struct {
   387  	Name string `json:"name,omitempty"`
   388  	ProductID string `json:"product_id,omitempty"`
   389  }
   390  ```
   391  I want product_id be the first property of Product struct.
   392  Is there any way to keep the order of properties?
   393  
   394  **Answer:** try x-order: n extension
   395  
   396  Originally from issue [#1759](https://github.com/thetreep/go-swagger/issues/1759).
   397  
   398  ### Fail to use swagger generate model -name
   399  
   400  _Use-case_: I met a problem when I tried to rename the filename of the auto-generated model.
   401  
   402  Example:
   403  
   404  1. `swagger generate model -m ./models/vo  --name Person`
   405  `unknown models: Person`
   406  2. `swagger generate model -m ./models/vo  -name Person`
   407  `unknown models: ame`
   408  3. `swagger generate model -m ./models/vo  -name= Person`
   409  `unknown models: ame=`
   410  
   411  ```json
   412  {
   413    "swagger": "2.0",
   414     "info": {
   415          "version": "1.0.0",
   416          "title": "Simple API",
   417          "description": "A simple API to learn how to write OpenAPI Specification"
   418      },
   419     "schemes": [
   420          "http"
   421      ],
   422    "paths": {
   423        "/persons":{
   424  	      "get":{
   425  		      "summary":"获取一些目标person",
   426  			  "description": "Returns a list containing all persons.",
   427  			  "responses": {
   428                      "200": {
   429                          "description": "A list of Person",
   430                          "schema": {
   431                              "type": "array",
   432                              "items": {
   433                                  "properties": {
   434                                      "firstName": {
   435                                          "type": "string"
   436                                      },
   437                                      "lastName": {
   438                                          "type": "string"
   439                                      },
   440                                      "username": {
   441                                          "type": "string"
   442                                      }
   443                                  }
   444                              }
   445                          }
   446                      }
   447                  }
   448  		  }
   449  	}
   450    }
   451  }
   452  ```
   453  
   454  **Answer:** you need to make it available with that name in the definitions section then it will know
   455  
   456  Originally from issue [#1517](https://github.com/thetreep/go-swagger/issues/1517).
   457  
   458  -------------
   459  
   460  Back to [all contributions](README.md#all-contributed-questions)