github.com/thetreep/go-swagger@v0.0.0-20240223100711-35af64f14f01/docs/tutorial/todo-list.md (about) 1 # Todo List Tutorial 2 3 This example walks you through a hypothetical project, building a todo list. 4 5 It uses a todo list because this is well-understood application, so you can focus on the go-swagger pieces. In this example we build a server and a client. 6 7 <!--more--> 8 9 To create your application start with `swagger init`: 10 11 ``` 12 swagger init spec \ 13 --title "A Todo list application" \ 14 --description "From the todo list tutorial on goswagger.io" \ 15 --version 1.0.0 \ 16 --scheme http \ 17 --consumes application/io.goswagger.examples.todo-list.v1+json \ 18 --produces application/io.goswagger.examples.todo-list.v1+json 19 ``` 20 21 This gives you a skeleton `swagger.yml` file: 22 23 ```yaml 24 --- 25 consumes: 26 - application/io.goswagger.examples.todo-list.v1+json 27 definitions: {} 28 info: 29 description: From the todo list tutorial on goswagger.io 30 title: A Todo list application 31 version: 1.0.0 32 paths: {} 33 produces: 34 - application/io.goswagger.examples.todo-list.v1+json 35 schemes: 36 - http 37 swagger: "2.0" 38 ``` 39 40 This doesn't do much but it does pass validation: 41 42 ``` 43 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list 44 git:(master) ✗ ? » swagger validate ./swagger.yml 45 The swagger spec at "./swagger.yml" is valid against swagger specification 2.0 46 ``` 47 48 Now that you have an empty but valid specification document, it's time to declare some models and endpoints for the API. You'll need a model to represent a todo item, so you can define that in the definitions section: 49 50 ```yaml 51 --- 52 definitions: 53 item: 54 type: object 55 required: 56 - description 57 properties: 58 id: 59 type: integer 60 format: int64 61 readOnly: true 62 description: 63 type: string 64 minLength: 1 65 completed: 66 type: boolean 67 ``` 68 69 In this model definition we say that the model `item` is an _object_ with a required property `description`. This item model has 3 properties: `id`, `description`, and `completed`. The `id` property is an int64 value and is marked as _readOnly_, meaning that it will be provided by the API server and it will be ignored when the item is created. 70 71 This document also says that the description must be at least 1 char long, which results in a string property that's [not a pointer](../use/models/schemas.md#nullability). 72 73 At this moment you have enough so that actual code could be generated, but let's continue defining the rest of the API so that the code generation will be more useful. Now that you have a model so you can add some endpoints to list the todo's: 74 75 ```yaml 76 --- 77 paths: 78 /: 79 get: 80 tags: 81 - todos 82 responses: 83 200: 84 description: list the todo operations 85 schema: 86 type: array 87 items: 88 $ref: "#/definitions/item" 89 ``` 90 91 This snippet of yaml defines a `GET /` operation and tags it with _todos_. Tagging things is useful for many tools, for example helping UI tools group endpoints appropriately. Code generators might turn them into 'controllers'. There is also a response defined with a generic description about the response content. Note that some generators will put the description into the http status message. The response also defines endpoint's return type. In this case the endpoint returns a list of todo items, so the schema is an _array_ and the array will contain `item` objects, which you defined previously. 92 93 But wait a minute, what if there are 100's of todo items, will we just return all of them for everybody? It would be good to add a `since` and `limit` param here. The ids will have to be ordered for a `since` param to work but you're in control of that so that's fine. 94 95 ```yaml 96 --- 97 paths: 98 /: 99 get: 100 tags: 101 - todos 102 parameters: 103 - name: since 104 in: query 105 type: integer 106 format: int64 107 - name: limit 108 in: query 109 type: integer 110 format: int32 111 default: 20 112 responses: 113 200: 114 description: list the todo operations 115 schema: 116 type: array 117 items: 118 $ref: "#/definitions/item" 119 ``` 120 121 With this new version of the operation you now have query params. These parameters have defaults so users can leave them off and the API will still function as intended. 122 123 However, this definition is extremely optimistic and only defines a response for the "happy path". It's very likely that the API will need to return errors too. That means you have to define a model errors, as well as at least one more response definition to cover the error response. 124 125 The error definition looks like this: 126 127 ```yaml 128 --- 129 definitions: 130 error: 131 type: object 132 required: 133 - message 134 properties: 135 code: 136 type: integer 137 format: int64 138 message: 139 type: string 140 ``` 141 142 For the error response you can use the default response, on the assumption that every successful response from your API is defying the odds. 143 144 ```yaml 145 --- 146 paths: 147 /: 148 get: 149 tags: 150 - todos 151 parameters: 152 - name: since 153 in: query 154 type: integer 155 format: int64 156 - name: limit 157 in: query 158 type: integer 159 format: int32 160 default: 20 161 responses: 162 200: 163 description: list the todo operations 164 schema: 165 type: array 166 items: 167 $ref: "#/definitions/item" 168 default: 169 description: generic error response 170 schema: 171 $ref: "#/definitions/error" 172 ``` 173 174 At this point you've defined your first endpoint completely. To improve the strength of this contract you could define responses for each of the status codes and perhaps return different error messages for different statuses. For now, the status code will be provided in the error message. 175 176 Try validating the specification again with `swagger validate ./swagger.yml` to ensure that code generation will work as expected. Generating code from an invalid specification leads to unpredictable results. 177 178 Your completed spec should look like this: 179 180 ```yaml 181 --- 182 swagger: "2.0" 183 info: 184 description: From the todo list tutorial on goswagger.io 185 title: A Todo list application 186 version: 1.0.0 187 consumes: 188 - application/io.goswagger.examples.todo-list.v1+json 189 produces: 190 - application/io.goswagger.examples.todo-list.v1+json 191 schemes: 192 - http 193 paths: 194 /: 195 get: 196 tags: 197 - todos 198 parameters: 199 - name: since 200 in: query 201 type: integer 202 format: int64 203 - name: limit 204 in: query 205 type: integer 206 format: int32 207 default: 20 208 responses: 209 200: 210 description: list the todo operations 211 schema: 212 type: array 213 items: 214 $ref: "#/definitions/item" 215 default: 216 description: generic error response 217 schema: 218 $ref: "#/definitions/error" 219 definitions: 220 item: 221 type: object 222 required: 223 - description 224 properties: 225 id: 226 type: integer 227 format: int64 228 readOnly: true 229 description: 230 type: string 231 minLength: 1 232 completed: 233 type: boolean 234 error: 235 type: object 236 required: 237 - message 238 properties: 239 code: 240 type: integer 241 format: int64 242 message: 243 type: string 244 ``` 245 246 When you generate a server for this spec you'll see the following output: 247 248 ``` 249 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-1 250 git:(master) ✗ !? » swagger generate server -A todo-list -f ./swagger.yml 251 2018/01/06 11:49:16 building a plan for generation 252 2018/01/06 11:49:16 planning definitions 253 2018/01/06 11:49:16 planning operations 254 2018/01/06 11:49:16 grouping operations into packages 255 2018/01/06 11:49:16 planning meta data and facades 256 2018/01/06 11:49:16 rendering 3 models 257 2018/01/06 11:49:16 rendering 1 templates for model getOKBody 258 2018/01/06 11:49:16 name field getOKBody 259 2018/01/06 11:49:16 package field models 260 2018/01/06 11:49:16 creating generated file "get_okbody.go" in "models" as definition 261 2018/01/06 11:49:16 executed template asset:model 262 2018/01/06 11:49:16 rendering 1 templates for model item 263 2018/01/06 11:49:16 name field item 264 2018/01/06 11:49:16 package field models 265 2018/01/06 11:49:16 creating generated file "item.go" in "models" as definition 266 2018/01/06 11:49:16 executed template asset:model 267 2018/01/06 11:49:16 rendering 1 templates for model error 268 2018/01/06 11:49:16 name field error 269 2018/01/06 11:49:16 package field models 270 2018/01/06 11:49:16 creating generated file "error.go" in "models" as definition 271 2018/01/06 11:49:16 executed template asset:model 272 2018/01/06 11:49:16 rendering 1 operation groups (tags) 273 2018/01/06 11:49:16 rendering 1 operations for todos 274 2018/01/06 11:49:16 rendering 4 templates for operation todo-list 275 2018/01/06 11:49:16 name field Get 276 2018/01/06 11:49:16 package field todos 277 2018/01/06 11:49:16 creating generated file "get_parameters.go" in "restapi/operations/todos" as parameters 278 2018/01/06 11:49:16 executed template asset:serverParameter 279 2018/01/06 11:49:16 name field Get 280 2018/01/06 11:49:16 package field todos 281 2018/01/06 11:49:16 creating generated file "get_urlbuilder.go" in "restapi/operations/todos" as urlbuilder 282 2018/01/06 11:49:16 executed template asset:serverUrlbuilder 283 2018/01/06 11:49:16 name field Get 284 2018/01/06 11:49:16 package field todos 285 2018/01/06 11:49:16 creating generated file "get_responses.go" in "restapi/operations/todos" as responses 286 2018/01/06 11:49:16 executed template asset:serverResponses 287 2018/01/06 11:49:16 name field Get 288 2018/01/06 11:49:16 package field todos 289 2018/01/06 11:49:16 creating generated file "get.go" in "restapi/operations/todos" as handler 290 2018/01/06 11:49:16 executed template asset:serverOperation 291 2018/01/06 11:49:16 rendering 0 templates for operation group todo-list 292 2018/01/06 11:49:16 rendering support 293 2018/01/06 11:49:16 rendering 6 templates for application TodoList 294 2018/01/06 11:49:16 name field TodoList 295 2018/01/06 11:49:16 package field operations 296 2018/01/06 11:49:16 creating generated file "configure_todo_list.go" in "restapi" as configure 297 2018/01/06 11:49:16 executed template asset:serverConfigureapi 298 2018/01/06 11:49:16 name field TodoList 299 2018/01/06 11:49:16 package field operations 300 2018/01/06 11:49:16 creating generated file "main.go" in "cmd/todo-list-server" as main 301 2018/01/06 11:49:16 executed template asset:serverMain 302 2018/01/06 11:49:16 name field TodoList 303 2018/01/06 11:49:16 package field operations 304 2018/01/06 11:49:16 creating generated file "embedded_spec.go" in "restapi" as embedded_spec 305 2018/01/06 11:49:16 executed template asset:swaggerJsonEmbed 306 2018/01/06 11:49:16 name field TodoList 307 2018/01/06 11:49:16 package field operations 308 2018/01/06 11:49:16 creating generated file "server.go" in "restapi" as server 309 2018/01/06 11:49:16 executed template asset:serverServer 310 2018/01/06 11:49:16 name field TodoList 311 2018/01/06 11:49:16 package field operations 312 2018/01/06 11:49:16 creating generated file "todo_list_api.go" in "restapi/operations" as builder 313 2018/01/06 11:49:16 executed template asset:serverBuilder 314 2018/01/06 11:49:16 name field TodoList 315 2018/01/06 11:49:16 package field operations 316 2018/01/06 11:49:16 creating generated file "doc.go" in "restapi" as doc 317 2018/01/06 11:49:16 executed template asset:serverDoc 318 2018/01/06 11:49:16 Generation completed! 319 320 For this generation to compile you need to have some packages in your GOPATH: 321 322 * github.com/go-openapi/runtime 323 * github.com/jessevdk/go-flags 324 325 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-1 326 git:(master) ✗ !? » tree 327 . 328 ├── cmd 329 │ └── todo-list-server 330 │ └── main.go 331 ├── models 332 │ ├── error.go 333 │ ├── get_okbody.go 334 │ └── item.go 335 ├── restapi 336 │ ├── configure_todo_list.go 337 │ ├── doc.go 338 │ ├── embedded_spec.go 339 │ ├── operations 340 │ │ ├── todo_list_api.go 341 │ │ └── todos 342 │ │ ├── get.go 343 │ │ ├── get_parameters.go 344 │ │ ├── get_responses.go 345 │ │ └── get_urlbuilder.go 346 │ └── server.go 347 └── swagger.yml 348 349 6 directories, 14 files 350 ``` 351 352 In this file tree you see that there is a `cmd/todo-list-server` directory. The swagger generator adds "-server" to the application name that you gave via the `-A` argument. 353 354 The next section in this tree is the `models` package. This package contains go representations for all item definitions in the swagger spec document. 355 356 The last section is `restapi`. The `restapi` package is generated based on the `paths` property in the swagger specification. The go swagger generator uses tags to group the operations into packages. 357 358 You can also name operation by specifying an `operationId` in the specification for a path: 359 360 361 ```yaml 362 --- 363 paths: 364 /: 365 get: 366 tags: 367 - todos 368 operationId: find_todos 369 ... 370 ``` 371 372 These `operationId` values are used to name the generated files: 373 374 ``` 375 . 376 ├── cmd 377 │ └── todo-list-server 378 │ └── main.go 379 ├── models 380 │ ├── error.go 381 │ ├── find_todos_okbody.go 382 │ ├── get_okbody.go 383 │ └── item.go 384 ├── restapi 385 │ ├── configure_todo_list.go 386 │ ├── doc.go 387 │ ├── embedded_spec.go 388 │ ├── operations 389 │ │ ├── todo_list_api.go 390 │ │ └── todos 391 │ │ ├── find_todos.go 392 │ │ ├── find_todos_parameters.go 393 │ │ ├── find_todos_responses.go 394 │ │ └── find_todos_urlbuilder.go 395 │ └── server.go 396 └── swagger.yml 397 ``` 398 399 You can see that the files under `restapi/operations/todos` now use the `operationId` as part of the generated file names. 400 401 At this point can start the server, but first let's see what `--help` gives you. First install the server binary and then run it: 402 403 ``` 404 ± ~/go/src/.../examples/tutorials/todo-list/server-1 405 » go install ./cmd/todo-list-server/ 406 ± ~/go/src/.../examples/tutorials/todo-list/server-1 407 » todo-list-server --help 408 Usage: 409 todo-list-server [OPTIONS] 410 411 From the todo list tutorial on goswagger.io 412 413 Application Options: 414 --scheme= the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec 415 --cleanup-timeout= grace period for which to wait before shutting down the server (default: 10s) 416 --max-header-size= controls the maximum number of bytes the server will read parsing the request header's keys and values, including the 417 request line. It does not limit the size of the request body. (default: 1MiB) 418 --socket-path= the unix socket to listen on (default: /var/run/todo-list.sock) 419 --host= the IP to listen on (default: localhost) [$HOST] 420 --port= the port to listen on for insecure connections, defaults to a random value [$PORT] 421 --listen-limit= limit the number of outstanding requests 422 --keep-alive= sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download) 423 (default: 3m) 424 --read-timeout= maximum duration before timing out read of the request (default: 30s) 425 --write-timeout= maximum duration before timing out write of the response (default: 60s) 426 --tls-host= the IP to listen on for tls, when not specified it's the same as --host [$TLS_HOST] 427 --tls-port= the port to listen on for secure connections, defaults to a random value [$TLS_PORT] 428 --tls-certificate= the certificate to use for secure connections [$TLS_CERTIFICATE] 429 --tls-key= the private key to use for secure connections [$TLS_PRIVATE_KEY] 430 --tls-ca= the certificate authority file to be used with mutual tls auth [$TLS_CA_CERTIFICATE] 431 --tls-listen-limit= limit the number of outstanding requests 432 --tls-keep-alive= sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download) 433 --tls-read-timeout= maximum duration before timing out read of the request 434 --tls-write-timeout= maximum duration before timing out write of the response 435 436 Help Options: 437 -h, --help Show this help message 438 ``` 439 440 If you run your application now it will start on a random port by default. This might not be what you want, so you can configure a port through a command line argument or a `PORT` env var. 441 442 ``` 443 git:(master) ✗ !? » todo-list-server 444 serving todo list at http://127.0.0.1:64637 445 ``` 446 447 You can use `curl` to check your API: 448 449 ``` 450 git:(master) ✗ !? » curl -i http://127.0.0.1:64637/ 451 ``` 452 ```http 453 HTTP/1.1 501 Not Implemented 454 Content-Type: application/io.goswagger.examples.todo-list.v1+json 455 Date: Thu, 31 Dec 2015 22:42:10 GMT 456 Content-Length: 57 457 458 "operation todos.FindTodos has not yet been implemented" 459 ``` 460 461 As you can see, the generated API isn't very usable yet, but we know it runs and does something. To make it useful you'll need to implement the actual logic behind those endpoints. And you'll also want to add some more endpoints, like adding a new todo item and updating an existing item to change its description or mark it completed. 462 463 To supporting adding a todo item you should define a `POST` operation: 464 465 ```yaml 466 --- 467 paths: 468 /: 469 post: 470 tags: 471 - todos 472 operationId: addOne 473 parameters: 474 - name: body 475 in: body 476 schema: 477 $ref: "#/definitions/item" 478 responses: 479 201: 480 description: Created 481 schema: 482 $ref: "#/definitions/item" 483 default: 484 description: error 485 schema: 486 $ref: "#/definitions/error" 487 ``` 488 489 This snippet has something new. You see that the parameters are defined using a `schema` that references our exist item model. Remember that we defined this object's `id` key as _readOnly_, so it will not be accepted as part of the `POST` body. 490 491 Next you can define a `DELETE` to remove a todo item from the list: 492 493 ```yaml 494 --- 495 paths: 496 /{id}: 497 delete: 498 tags: 499 - todos 500 operationId: destroyOne 501 parameters: 502 - type: integer 503 format: int64 504 name: id 505 in: path 506 required: true 507 responses: 508 204: 509 description: Deleted 510 default: 511 description: error 512 schema: 513 $ref: "#/definitions/error" 514 ``` 515 516 This time you're defining a parameter that is part of the `path`. This operation will look in the URI templated path for an id. Since there's nothing to return after a delete, the success response is `204 No Content`. 517 518 Finally, you need to define a way to update an existing item: 519 520 ```yaml 521 --- 522 paths: 523 /{id}: 524 parameters: 525 - type: integer 526 format: int64 527 name: id 528 in: path 529 required: true 530 put: 531 tags: ["todos"] 532 operationId: updateOne 533 parameters: 534 - name: body 535 in: body 536 schema: 537 $ref: "#/definitions/item" 538 responses: 539 '200': 540 description: OK 541 schema: 542 $ref: "#/definitions/item" 543 default: 544 description: error 545 schema: 546 $ref: "#/definitions/error" 547 delete: 548 # elided for brevity 549 ``` 550 551 There are two approaches typically taken for updates. A `PUT` indicates that the entire entity is being replaced, and a `PATCH` indicates that only the fields provided in the request should be updated. In the above example, you can see that the `PUT` "brute force" approach is being used. 552 553 Another thing to note is that because the `/{id}` path is shared for both `DELETE` and `PUT`, they can share a `parameters` definition. 554 555 At this point you should have a complete specification for the todo list API: 556 557 ```yaml 558 --- 559 swagger: "2.0" 560 info: 561 description: From the todo list tutorial on goswagger.io 562 title: A Todo list application 563 version: 1.0.0 564 consumes: 565 - application/io.goswagger.examples.todo-list.v1+json 566 produces: 567 - application/io.goswagger.examples.todo-list.v1+json 568 schemes: 569 - http 570 - https 571 paths: 572 /: 573 get: 574 tags: 575 - todos 576 operationId: findTodos 577 parameters: 578 - name: since 579 in: query 580 type: integer 581 format: int64 582 - name: limit 583 in: query 584 type: integer 585 format: int32 586 default: 20 587 responses: 588 200: 589 description: list the todo operations 590 schema: 591 type: array 592 items: 593 $ref: "#/definitions/item" 594 default: 595 description: generic error response 596 schema: 597 $ref: "#/definitions/error" 598 post: 599 tags: 600 - todos 601 operationId: addOne 602 parameters: 603 - name: body 604 in: body 605 schema: 606 $ref: "#/definitions/item" 607 responses: 608 201: 609 description: Created 610 schema: 611 $ref: "#/definitions/item" 612 default: 613 description: error 614 schema: 615 $ref: "#/definitions/error" 616 /{id}: 617 parameters: 618 - type: integer 619 format: int64 620 name: id 621 in: path 622 required: true 623 put: 624 tags: 625 - todos 626 operationId: updateOne 627 parameters: 628 - name: body 629 in: body 630 schema: 631 $ref: "#/definitions/item" 632 responses: 633 200: 634 description: OK 635 schema: 636 $ref: "#/definitions/item" 637 default: 638 description: error 639 schema: 640 $ref: "#/definitions/error" 641 delete: 642 tags: 643 - todos 644 operationId: destroyOne 645 responses: 646 204: 647 description: Deleted 648 default: 649 description: error 650 schema: 651 $ref: "#/definitions/error" 652 definitions: 653 item: 654 type: object 655 required: 656 - description 657 properties: 658 id: 659 type: integer 660 format: int64 661 readOnly: true 662 description: 663 type: string 664 minLength: 1 665 completed: 666 type: boolean 667 error: 668 type: object 669 required: 670 - message 671 properties: 672 code: 673 type: integer 674 format: int64 675 message: 676 type: string 677 ``` 678 679 This is a good time to sanity check and by validating the schema: 680 681 ``` 682 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-2 683 git:(master) ✗ !? » swagger validate ./swagger.yml 684 The swagger spec at "./swagger.yml" is valid against swagger specification 2.0 685 ``` 686 687 Now you're ready to generate the API and start filling in the actual operations: 688 689 ``` 690 git:(master) ✗ !? » swagger generate server -A TodoList -f ./swagger.yml 691 ... elided output ... 692 2015/12/31 18:16:28 rendered main template: server.TodoList 693 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-2 694 git:(master) ✗ !? » tree 695 . 696 ├── cmd 697 │ └── todo-list-server 698 │ └── main.go 699 ├── models 700 │ ├── error.go 701 │ ├── find_todos_okbody.go 702 │ └── item.go 703 ├── restapi 704 │ ├── configure_todo_list.go 705 │ ├── doc.go 706 │ ├── embedded_spec.go 707 │ ├── operations 708 │ │ ├── todo_list_api.go 709 │ │ └── todos 710 │ │ ├── add_one.go 711 │ │ ├── add_one_parameters.go 712 │ │ ├── add_one_responses.go 713 │ │ ├── add_one_urlbuilder.go 714 │ │ ├── destroy_one.go 715 │ │ ├── destroy_one_parameters.go 716 │ │ ├── destroy_one_responses.go 717 │ │ ├── destroy_one_urlbuilder.go 718 │ │ ├── find_todos.go 719 │ │ ├── find_todos_parameters.go 720 │ │ ├── find_todos_responses.go 721 │ │ ├── find_todos_urlbuilder.go 722 │ │ ├── update_one.go 723 │ │ ├── update_one_parameters.go 724 │ │ ├── update_one_responses.go 725 │ │ └── update_one_urlbuilder.go 726 │ └── server.go 727 └── swagger.yml 728 729 6 directories, 26 files 730 ``` 731 732 To implement the core of your application you start by editing `restapi/configure_todo_list.go`. This file is safe to edit. Its content will not be overwritten if you run `swagger generate` again the future. 733 734 The simplest way to implement this application is to simply store all the todo items in a golang `map`. This provides a simple way to move forward without bringing in complications like a database or files. 735 736 To do this you'll need a map and a counter to track the last assigned id: 737 738 ```go 739 // the variables we need throughout our implementation 740 var items = make(map[int64]*models.Item) 741 var lastID int64 742 ``` 743 744 The simplest handler to implement now is the delete handler. Because the store is a map and the id of the item is provided in the request it's a one liner. 745 746 ```go 747 api.TodosDestroyOneHandler = todos.DestroyOneHandlerFunc(func(params todos.DestroyOneParams) middleware.Responder { 748 delete(items, params.ID) 749 return todos.NewDestroyOneNoContent() 750 }) 751 ``` 752 753 After deleting the item from the store, you need to provide a response. The code generator created responders for each response you defined in the the swagger specification, and you can see how one of those is being used in the example above. 754 755 The other 3 handler implementations are similar to this one. They are provided in the [source for this tutorial](https://github.com/thetreep/go-swagger/blob/master/examples/tutorials/todo-list/server-complete/restapi/configure_todo_list.go). 756 757 So assuming you go ahead and implement the remainder of the endpoints, you're all set to test it out: 758 759 ``` 760 » curl -i localhost:8765 761 ``` 762 ```http 763 HTTP/1.1 200 OK 764 Content-Type: application/io.goswagger.examples.todo-list.v1+json 765 Date: Fri, 01 Jan 2016 19:56:01 GMT 766 Content-Length: 3 767 768 [] 769 ``` 770 ``` 771 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-complete 772 ``` 773 ```http 774 » curl -i localhost:8765 -d "{\"description\":\"message $RANDOM\"}" 775 HTTP/1.1 415 Unsupported Media Type 776 Content-Type: application/io.goswagger.examples.todo-list.v1+json 777 Date: Fri, 01 Jan 2016 19:56:11 GMT 778 Content-Length: 157 779 780 {"code":415,"message":"unsupported media type \"application/x-www-form-urlencoded\", only [application/io.goswagger.examples.todo-list.v1+json] are allowed"} ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-complete 781 ``` 782 ``` 783 » curl -i localhost:8765 -d "{\"description\":\"message $RANDOM\"}" -H 'Content-Type: application/io.goswagger.examples.todo-list.v1+json' 784 ``` 785 ```http 786 HTTP/1.1 201 Created 787 Content-Type: application/io.goswagger.examples.todo-list.v1+json 788 Date: Fri, 01 Jan 2016 19:56:20 GMT 789 Content-Length: 39 790 791 {"description":"message 30925","id":1} 792 ``` 793 ``` 794 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-complete 795 » curl -i localhost:8765 -d "{\"description\":\"message $RANDOM\"}" -H 'Content-Type: application/io.goswagger.examples.todo-list.v1+json' 796 ``` 797 ```http 798 HTTP/1.1 201 Created 799 Content-Type: application/io.goswagger.examples.todo-list.v1+json 800 Date: Fri, 01 Jan 2016 19:56:23 GMT 801 Content-Length: 37 802 803 {"description":"message 104","id":2} 804 ``` 805 ``` 806 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-complete 807 » curl -i localhost:8765 -d "{\"description\":\"message $RANDOM\"}" -H 'Content-Type: application/io.goswagger.examples.todo-list.v1+json' 808 ``` 809 ```http 810 HTTP/1.1 201 Created 811 Content-Type: application/io.goswagger.examples.todo-list.v1+json 812 Date: Fri, 01 Jan 2016 19:56:24 GMT 813 Content-Length: 39 814 815 {"description":"message 15225","id":3} 816 ``` 817 ``` 818 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-complete 819 » curl -i localhost:8765 820 ``` 821 ```http 822 HTTP/1.1 200 OK 823 Content-Type: application/io.goswagger.examples.todo-list.v1+json 824 Date: Fri, 01 Jan 2016 19:56:26 GMT 825 Content-Length: 117 826 827 [{"description":"message 30925","id":1},{"description":"message 104","id":2},{"description":"message 15225","id":3}] 828 ``` 829 ``` 830 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-complete 831 » curl -i localhost:8765/3 -X PUT -H 'Content-Type: application/io.goswagger.examples.todo-list.v1+json' -d '{"description":"go shopping"}' 832 ``` 833 ```http 834 HTTP/1.1 200 OK 835 Content-Type: application/io.goswagger.examples.todo-list.v1+json 836 Date: Fri, 01 Jan 2016 19:56:32 GMT 837 Content-Length: 37 838 839 {"description":"go shopping","id":3} 840 ``` 841 ``` 842 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-complete 843 » curl -i localhost:8765 844 ``` 845 ```http 846 HTTP/1.1 200 OK 847 Content-Type: application/io.goswagger.examples.todo-list.v1+json 848 Date: Fri, 01 Jan 2016 19:56:34 GMT 849 Content-Length: 115 850 851 [{"description":"message 30925","id":1},{"description":"message 104","id":2},{"description":"go shopping","id":3}] 852 ``` 853 ``` 854 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-complete 855 » curl -i localhost:8765/1 -X DELETE -H 'Content-Type: application/io.goswagger.examples.todo-list.v1+json' 856 ``` 857 ```http 858 HTTP/1.1 204 No Content 859 Content-Type: application/io.goswagger.examples.todo-list.v1+json 860 Date: Fri, 01 Jan 2016 19:57:04 GMT 861 ``` 862 ``` 863 ± ~/go/src/github.com/thetreep/go-swagger/examples/tutorials/todo-list/server-complete 864 » curl -i localhost:8765 865 ``` 866 ```http 867 HTTP/1.1 200 OK 868 Content-Type: application/io.goswagger.examples.todo-list.v1+json 869 Date: Fri, 01 Jan 2016 19:57:06 GMT 870 Content-Length: 76 871 872 [{"description":"message 104","id":2},{"description":"go shopping","id":3}] 873 ```