github.com/rzurga/go-swagger@v0.28.1-0.20211109195225-5d1f453ffa3a/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/go-swagger/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/go-swagger/go-swagger/blob/master/generator/templates/schemavalidator.gotmpl) 42 for models, or in [here](https://github.com/go-swagger/go-swagger/blob/master/generator/templates/server/parameter.gotmpl) for inline parameters. 43 44 Originally from issues [#997](https://github.com/go-swagger/go-swagger/issues/997) and [#1334](https://github.com/go-swagger/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/go-swagger/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/go-swagger/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/go-swagger/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/go-swagger/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/go-swagger/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(¶ms, 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/go-swagger/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/go-swagger/go-swagger/blob/master/fixtures/codegen/existing-model.yml#L99-103 315 316 Originally from issue [#948](https://github.com/go-swagger/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/go-swagger/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/go-swagger/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/go-swagger/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/go-swagger/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/go-swagger/go-swagger/issues/1517). 457 458 ------------- 459 460 Back to [all contributions](README.md#all-contributed-questions)