github.com/Percona-Lab/go-swagger@v0.19.0/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 document](../generate/spec/strfmt.md). 194 Regarding dates, this package extends validation to [RFC3339](https://tools.ietf.org/html/rfc3339) full-date format (e.g. "2006-01-02"). 195 196 Originally from issue [#643](https://github.com/go-swagger/go-swagger/issues/643). 197 198 ### Accessing the Default return value 199 _Use-Case_: I was wondering how I would get the default response from the client? 200 201 Note: see also [Access HTTP status code from client#597](https://github.com/go-swagger/go-swagger/issues/597). 202 203 I have a spec like this: 204 ```YAML 205 /deploys/{deploy_id}: 206 get: 207 operationId: getDeploy 208 parameters: 209 - name: deploy_id 210 type: string 211 in: path 212 required: true 213 responses: 214 '200': 215 description: OK 216 schema: 217 $ref: "#/definitions/deploy" 218 default: 219 description: error 220 schema: 221 $ref: "#/definitions/error" 222 ``` 223 This spec generates two models: `GetDeployOK` and `GetDeployDefault`. The API generated will return the OK case. 224 ```golang 225 func (a *Client) GetDeploy(params *GetDeployParams, authInfo runtime.ClientAuthInfoWriter) (*GetDeployOK, error) { 226 // TODO: Validate the params before sending 227 if params == nil { 228 params = NewGetDeployParams() 229 } 230 231 result, err := a.transport.Submit(&runtime.ClientOperation{ 232 ID: "getDeploy", 233 Method: "GET", 234 PathPattern: "/deploys/{deploy_id}", 235 ProducesMediaTypes: []string{"application/json"}, 236 ConsumesMediaTypes: []string{"application/json"}, 237 Schemes: []string{"https"}, 238 Params: params, 239 Reader: &GetDeployReader{formats: a.formats}, 240 AuthInfo: authInfo, 241 }) 242 if err != nil { 243 return nil, err 244 } 245 return result.(*GetDeployOK), nil TODO 246 } 247 ``` 248 *Does that mean that, if I get a non-2xx response, I should check the err to actually be a `GetDeployDefault` reference?* 249 250 Something like: 251 ```golang 252 resp, err := c.Operations.GetDeploy(¶ms, authInfo) 253 if err != nil { 254 if casted, ok := err.(models.GetDeployDefault); ok { 255 // do something here.... 256 } else { 257 false, err 258 } 259 } 260 ``` 261 262 >I've been tracing through the code in `Runtime.Submit`: it delegates to the `GetDeployReader.ReadResponse` which makes the distinction. 263 >However, it remains unclear how that response is actually surfaced. 264 265 **Answer**: you can get pretty close to that with something like: 266 ```golang 267 casted, ok := err.(*operations.GetDeployDefault) 268 ``` 269 270 Because it's a struct type it will be a pointer. 271 272 Originally from issue [#616](https://github.com/go-swagger/go-swagger/issues/616). 273 274 ### How to avoid deep copies of complex data structures that need to be marshalled across the API? 275 _Use-Case_: 276 >An API that provides access to a complex data structure, defined and governed by a subsystem, should not have to spec the 277 >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 278 >model universe. 279 280 *How do others deal with this problem?* 281 282 - If your question is "How do I write arbitrary response bodies from go-swagger generated server code?" 283 (e.g. from subsystem structs that you have marshalled) then you may want to write your own `middleware.Responder`, 284 which gives you direct access to the underlying `http.ResponseWriter`. 285 At this point, though, why use go-swagger instead of a lighter-weight framework? 286 - If your question is "how can I generate a swagger spec from my subsystem structs?", then you could check out the `swagger generate 287 spec` CLI command. 288 289 >Further, a subsystem that builds a complex hierarchical data structure to support its own requirements for efficiency, 290 >access, and serialization does not want the types of the API data model to be injected into its namespace. 291 292 >Eventually, the subsystem can exist in many different contexts beyond the API, which is another reason it should not 293 >become dependent on any API type. 294 295 ------------- 296 297 _Similar Use-Case_: 298 >A new requirement is proposed that wants API access to that complex data structure, and we decide to use go-swagger for that 299 >implementation. It is a pure 'read' requirement, so no need for parameter validation by the API, just the ability to gain an XML 300 >or JSON form of the data structure by a client. 301 302 >Our organization decided to keep the API and subsystem layers separate, and to perform deep copies between them. 303 >The runtime performance costs are acceptable to us, and worth it to keep API-layer dependencies out of our core library. 304 >If someone can think of a better solution we would love to know! 305 306 >If we define a data model in the swagger specification, we end up having to do a 307 >deep copy of that data structure from subsystem to API if we want to avoid type injection. 308 309 *How do you use the swagger spec to define a raw JSON or XML transfer, defined by the subsystem's types?* 310 311 **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: 312 https://github.com/go-swagger/go-swagger/blob/master/fixtures/codegen/existing-model.yml#L99-103 313 314 Originally from issue [#948](https://github.com/go-swagger/go-swagger/issues/948). 315 316 ### Extra sections in POST body 317 318 _Use-case_: additional properties in object 319 320 If I have a swagger spec that expects 321 322 {"foo": 123} 323 324 and provide 325 326 {"foo": 123, "blah": 345} 327 328 it happily goes on about this way. 329 330 Two questions: 331 1. can I make it complain if extra stuff is included 332 2. can I access these extra sections within the go code/handler? 333 334 **Answer**: use `additionalProperties: false` or `additionalProperties: true` in your definition. 335 when it's set to true you'll have a `map[string]interface{}` added. 336 337 Originally from issue [#1337](https://github.com/go-swagger/go-swagger/issues/1337). 338 339 ### How to support generate type int? 340 341 _Use-case_: generating `int` types 342 343 > I need to use swagger to generate my modes in go code. 344 > But I find I can hardly generate type `int`, always `int64`. 345 > Since I need to keep back compatibility for my project, I can hardly change the type. 346 > So in this case, does go-swagger meet this requirement? 347 348 **Answer**: int is not a good option to support when it comes to contracts. 349 350 > Consider the following: you have an arm32 client on which int is int32, however your server is amd64. 351 > At this stage it's perfectly valid for the server to return int32 max value + 1, this will cause the client to overflow. 352 > 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. 353 > Similarly other languages may choose to default to int32 type instead of int64 type regardless of platform. 354 355 Originally from issue [#1205](https://github.com/go-swagger/go-swagger/issues/1205). 356 357 ### Generate all models necessary for specified operation 358 359 _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? 360 361 **Answer:** when using the generate server command, a repeatable --operation=xxx is available to restrict the scope of operations. 362 363 > NOTE: this option is not available for `generate model`. 364 365 Originally from issue [#1427](https://github.com/go-swagger/go-swagger/issues/1427). 366 367 ### Generated code changes the order of properties in struct 368 369 _Use-case_: the generated struct has attributes ordered differently than the original specification 370 371 Example: 372 373 ```yaml 374 Product: 375 type: "object" 376 properties: 377 product_id: 378 type: "string" 379 name: 380 type: "string" 381 ``` 382 Generated by "swagger generate server": 383 ```go 384 type Product struct { 385 Name string `json:"name,omitempty"` 386 ProductID string `json:"product_id,omitempty"` 387 } 388 ``` 389 I want product_id be the first property of Product struct. 390 Is there any way to keep the order of properties? 391 392 **Answer:** try x-order: n extension 393 394 Originally from issue [#1759](https://github.com/go-swagger/go-swagger/issues/1759). 395 396 ### Fail to use swagger generate model -name 397 398 _Use-case_: I met a problem when I tried to rename the filename of the auto-generated model. 399 400 Example: 401 402 1. `swagger generate model -m ./models/vo --name Person` 403 `unknown models: Person` 404 2. `swagger generate model -m ./models/vo -name Person` 405 `unknown models: ame` 406 3. `swagger generate model -m ./models/vo -name= Person` 407 `unknown models: ame=` 408 409 ```json 410 { 411 "swagger": "2.0", 412 "info": { 413 "version": "1.0.0", 414 "title": "Simple API", 415 "description": "A simple API to learn how to write OpenAPI Specification" 416 }, 417 "schemes": [ 418 "http" 419 ], 420 "paths": { 421 "/persons":{ 422 "get":{ 423 "summary":"获取一些目标person", 424 "description": "Returns a list containing all persons.", 425 "responses": { 426 "200": { 427 "description": "A list of Person", 428 "schema": { 429 "type": "array", 430 "items": { 431 "properties": { 432 "firstName": { 433 "type": "string" 434 }, 435 "lastName": { 436 "type": "string" 437 }, 438 "username": { 439 "type": "string" 440 } 441 } 442 } 443 } 444 } 445 } 446 } 447 } 448 } 449 } 450 ``` 451 452 **Answer:** you need to make it available with that name in the definitions section then it will know 453 454 Originally from issue [#1517](https://github.com/go-swagger/go-swagger/issues/1517). 455 456 ------------- 457 458 Back to [all contributions](README.md#all-contributed-questions)