├── LICENSE ├── README.md ├── S01 ├── ARAC-Section01.postman-collection.json ├── Access the e-book for Section 1 here!.txt ├── New Text Document.txt ├── end-code - @classmethod across the board.zip ├── end-code - Adding basic type hinting.zip ├── end-code - Adding custom JSON types.zip ├── end-code - Improving errors with constants.zip ├── end-code - Refactoring our resources.zip ├── end-code - Should we have unique names.zip ├── end-code - Simplifying our error handling.zip ├── end-code - Using the current class as a type hint.zip ├── end-code- Using Black for code formatting.zip ├── start-code - @classmethod across the board.zip ├── start-code - Adding basic type hinting.zip ├── start-code - Adding custom JSON types.zip ├── start-code - Refactoring our resources.zip ├── start-code - Reviewing the beginner course code.zip ├── start-code - Should we have unique names.zip ├── start-code - Simplifying our error handling.zip ├── start-code - Using the current class as a type hint.zip ├── start-code- Improving errors with constants.zip ├── start-code.zip └── starter-code - Using Black for code formatting.zip ├── S02 ├── ARAC-Section02-Marshmallow.postman-collection.json ├── deserializing - Deserialization with Marshmallow.py ├── end-code - Adding stores to our REST API.zip ├── end-code - Deduplicating error handling.zip ├── end-code - Adding items to our REST API.zip ├── end-code - Introduction to Flask-Marshmallow.zip ├── end-code - Migrating from virtualenv to Pipenv.zip ├── end-code - Using vanilla Marshmallow with the API.zip ├── serializing - Serialization with Marshmallow.py ├── start-code - Adding stores to our REST API.zip ├── start-code - Deduplicating error handling.zip ├── start-code - Adding items to our REST API.zip ├── start-code - Introduction to Flask-Marshmallow.zip ├── start-code - Migrating from virtualenv to Pipenv.zip └── start-code - Using vanilla Marshmallow with the API.zip ├── S03 ├── ARAC-Section03-Email-Confirmation.postman-collection.json ├── end-code - Adding more configuration to .env.zip ├── end-code - Telling users they are active.zip ├── end-code - Activating users manually.zip ├── end-code - Adding an activated property.zip ├── end-code - Creating our Mailgun library file.zip ├── end-code - Error handling in Mailgun.zip ├── end-code - Sending e-mails with Mailgun (Part 1).zip ├── end-code - Using .env files in Flask.zip ├── start-code - Adding more configuration to .env.zip ├── start-code - Telling users they are active.zip ├── start-code - Activating users manually.zip ├── start-code - Adding an activated property.zip ├── start-code - Creating our Mailgun library file.zip ├── start-code - Error handling in Mailgun.zip ├── start-code - Sending e-mails with Mailgun (Part 1).zip └── start-code - Using .env files in Flask.zip ├── S04 ├── ARAC-Section04-ConfirmationModel.postman-collection.json ├── New Text Document.txt ├── end-code - Creating the ConfirmationModel.zip ├── end-code - Updating our UserResource.zip ├── end-code - Adding a new language to our API.zip ├── end-code - Adding the last confirmation to the user schema.zip ├── end-code - Changes in our UserModel.zip ├── end-code - Creating a simple translation library.zip ├── end-code - Creating our ConfirmationResource.zip ├── end-code - Fixing our app.py.zip ├── end-code - Storing strings in config files.zip ├── end-code - Updating our resources to use translations.zip ├── start-code - Creating the ConfirmationModel.zip ├── start-code - Updating our UserResource.zip ├── start-code - Adding a new language to our API.zip ├── start-code - Adding the last confirmation to the user schema.zip ├── start-code - Changes in our UserModel.zip ├── start-code - Creating a simple translation library.zip ├── start-code - Creating our ConfirmationResource.zip ├── start-code - Fixing our app.py.zip ├── start-code - Storing strings in config files.zip ├── start-code - Updating our resources to use translations.zip └── translation-file-checking-script.py ├── S05 ├── ARA-Section05-FlowTests.postman-collection.json └── ARAC-Section05-Documentation.postman-collection.json ├── S06 ├── ARAC-Section06-ImageUpload.postman-collection.json ├── New Text Document.txt ├── end-code - Creating our image helper library.zip ├── end-code - Config files in Flask.zip ├── end-code - Creating our image schema.zip ├── end-code - Creating our image upload resource.zip ├── end-code - Installing Flask-Uploads.zip ├── end-code - Retrieving and deleting images.zip ├── end-code - Trying out our image upload.zip ├── end-code_ Another example user avatars.zip ├── end-code_Adding the avatar resource.zip ├── start-code - Creating our image helper library.zip ├── start-code - Config files in Flask.zip ├── start-code - Creating our image schema.zip ├── start-code - Creating our image upload resource.zip ├── start-code - Installing Flask-Uploads.zip ├── start-code - Retrieving and deleting images.zip ├── start-code - Trying out our image upload.zip ├── start-code_ Another example user avatars.zip └── start-code_Adding the avatar resource.zip ├── S07 ├── ARAC-Section07-Database-Migrations.postman-collection.json ├── New Text Document.txt ├── end-code_ Connecting to our remote database.zip ├── end-code_Adding a new column with migrations.zip ├── end-code_Checking the Alembic script (important!).zip ├── end-code_Defining a SQLAlchemy naming convention.zip ├── end-code_Initialising Flask-Migrate and Alembic.zip ├── start-code_ Connecting to our remote database.zip ├── start-code_Adding a new column with migrations.zip ├── start-code_Checking the Alembic script (important!).zip ├── start-code_Defining a SQLAlchemy naming convention.zip ├── start-code_Initialising Flask-Migrate and Alembic.zip └── start-code_What's in our starter code.zip ├── S08 ├── ARAC-Section08-OAuth.postman-collection.json ├── Authorizing OAuth Apps.txt ├── Flask Application context.txt ├── Flask OAuthlib Documentation.txt ├── Flask g.txt ├── Flask url_for.txt ├── Github Developer settings, Authorizing OAuth apps.txt ├── Marshmallow- Version 3 change.txt ├── New Text Document.txt ├── end-code_ Creating a GitHub OAuth App.zip ├── end-code_ Flask-OAuthlib.zip ├── end-code_Adding some error handling.zip ├── end-code_Finishing our GithubAuthorize resource.zip ├── end-code_Our GithubLogin resource.zip ├── end-code_Setting up our GitHub client.zip ├── end-code_Setting user passwords.zip ├── end-code_Using url_for with Flask-RESTful.zip ├── end-code_What is a tokengetter.zip ├── flask-g-test-code.zip ├── start-code_ Creating a GitHub OAuth App.zip ├── start-code_ Flask-OAuthlib.zip ├── start-code_Adding some error handling.zip ├── start-code_Finishing our GithubAuthorize resource.zip ├── start-code_Our GithubLogin resource.zip ├── start-code_Setting up our GitHub client.zip ├── start-code_Setting user passwords.zip ├── start-code_Using url_for with Flask-RESTful.zip ├── start-code_What is a tokengetter.zip └── start-code_What's in our starter code.zip └── S09 ├── ARAC-Section09-Payments.postman-collection.json ├── New Text Document.txt ├── SQLAlchemy Many to many relationships.txt ├── SQLAlchemy_Assossiation object.txt ├── SQLAlchemy_backref.txt ├── Stripe API Keys.txt ├── Stripe Card Payments for Quick start.txt ├── Stripe_Card Payments Quickstart.txt ├── end-code_ Creating our OrderModel.zip ├── end-code_After payment receiving order data.zip ├── end-code_Calculating the amount and description.zip ├── end-code_Charging orders with Stripe.zip ├── end-code_Creating a way to view existing orders.zip ├── end-code_Many-to-many relationships with SQLAlchemy.zip ├── end-code_Using the Association Object in our Resourcee.zip ├── end-code_When things go wrong error handling in Stripe.zip ├── order.py ├── start-code_ Creating our OrderModel.zip ├── start-code_After payment receiving order data.zip ├── start-code_Calculating the amount and description.zip ├── start-code_Charging orders with Stripe.zip ├── start-code_Creating a way to view existing orders.zip ├── start-code_Many-to-many relationships with SQLAlchemy.zip ├── start-code_Using the Association Object in our Resourcee.zip └── start-code_When things go wrong error handling in Stripe.zip /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Advanced-REST-APIs-with-Flask-and-Python 5 | Code Repository for Advanced REST APIs with Flask and Python, Published by Packt 6 | -------------------------------------------------------------------------------- /S01/ARAC-Section01.postman-collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "4e9e56af-5b06-4dd5-a8c9-20c6e0ea2f28", 4 | "name": "ARAC-Section01", 5 | "description": "This collection contains the requests for the section 01 code of the Advanced REST API Course.", 6 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 7 | }, 8 | "item": [ 9 | { 10 | "name": "users", 11 | "item": [ 12 | { 13 | "name": "register a new user", 14 | "request": { 15 | "method": "POST", 16 | "header": [ 17 | { 18 | "key": "Content-Type", 19 | "value": "application/json" 20 | } 21 | ], 22 | "body": { 23 | "mode": "raw", 24 | "raw": "{\n\t\"username\": \"jose\",\n\t\"password\": \"1234\"\n}" 25 | }, 26 | "url": { 27 | "raw": "{{url}}/register", 28 | "host": [ 29 | "{{url}}" 30 | ], 31 | "path": [ 32 | "register" 33 | ] 34 | } 35 | }, 36 | "response": [] 37 | }, 38 | { 39 | "name": "login", 40 | "event": [ 41 | { 42 | "listen": "test", 43 | "script": { 44 | "id": "8c0c0ed6-c206-4c88-9349-429e024e312b", 45 | "type": "text/javascript", 46 | "exec": [ 47 | "var jsonData = pm.response.json();", 48 | "pm.test(\"access_token not empty\", function () {", 49 | " pm.expect(jsonData.access_token).not.eql(undefined);", 50 | "});", 51 | "", 52 | "pm.test(\"refresh token not empty\", function () {", 53 | " pm.expect(jsonData.refresh_token).not.eql(undefined);", 54 | "});", 55 | "// set access token as environement variable", 56 | "if (jsonData.access_token !== undefined) {", 57 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 58 | "} else {", 59 | " postman.setEnvironmentVariable(\"access_token\", null);", 60 | "}", 61 | "// set refresh token as environement variable", 62 | "if (jsonData.refresh_token !== undefined) {", 63 | " postman.setEnvironmentVariable(\"refresh_token\", jsonData.refresh_token);", 64 | "} else {", 65 | " postman.setEnvironmentVariable(\"refresh_token\", null);", 66 | "}" 67 | ] 68 | } 69 | } 70 | ], 71 | "request": { 72 | "method": "POST", 73 | "header": [ 74 | { 75 | "key": "Content-Type", 76 | "value": "application/json" 77 | } 78 | ], 79 | "body": { 80 | "mode": "raw", 81 | "raw": "{\n \"username\" : \"jose\",\n \"password\" : \"1234\"\n}" 82 | }, 83 | "url": { 84 | "raw": "{{url}}/login", 85 | "host": [ 86 | "{{url}}" 87 | ], 88 | "path": [ 89 | "login" 90 | ] 91 | } 92 | }, 93 | "response": [] 94 | }, 95 | { 96 | "name": "logout", 97 | "event": [ 98 | { 99 | "listen": "test", 100 | "script": { 101 | "id": "dc763e9b-e6c7-4ff3-9766-637976a5c64b", 102 | "type": "text/javascript", 103 | "exec": [ 104 | "" 105 | ] 106 | } 107 | } 108 | ], 109 | "request": { 110 | "method": "POST", 111 | "header": [ 112 | { 113 | "key": "Authorization", 114 | "value": "Bearer {{access_token}}" 115 | } 116 | ], 117 | "body": { 118 | "mode": "raw", 119 | "raw": "" 120 | }, 121 | "url": { 122 | "raw": "{{url}}/logout", 123 | "host": [ 124 | "{{url}}" 125 | ], 126 | "path": [ 127 | "logout" 128 | ] 129 | } 130 | }, 131 | "response": [] 132 | }, 133 | { 134 | "name": "refresh token", 135 | "event": [ 136 | { 137 | "listen": "test", 138 | "script": { 139 | "id": "ad818ea6-8f79-436e-b756-ad878666ae9e", 140 | "type": "text/javascript", 141 | "exec": [ 142 | "var jsonData = pm.response.json();", 143 | "pm.test(\"access_token not empty\", function () {", 144 | " pm.expect(jsonData.access_token).not.eql(undefined);", 145 | "});", 146 | "// set access token as environement variable", 147 | "if (jsonData.access_token !== undefined) {", 148 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 149 | "} else {", 150 | " postman.setEnvironmentVariable(\"access_token\", null);", 151 | "}" 152 | ] 153 | } 154 | } 155 | ], 156 | "request": { 157 | "method": "POST", 158 | "header": [ 159 | { 160 | "key": "Content-Type", 161 | "value": "application/json" 162 | }, 163 | { 164 | "key": "Authorization", 165 | "value": "Bearer {{refresh_token}}" 166 | } 167 | ], 168 | "body": { 169 | "mode": "raw", 170 | "raw": "" 171 | }, 172 | "url": { 173 | "raw": "{{url}}/refresh", 174 | "host": [ 175 | "{{url}}" 176 | ], 177 | "path": [ 178 | "refresh" 179 | ] 180 | } 181 | }, 182 | "response": [] 183 | }, 184 | { 185 | "name": "get user by id", 186 | "request": { 187 | "method": "GET", 188 | "header": [], 189 | "body": { 190 | "mode": "raw", 191 | "raw": "{\n\t\"username\": \"jose\",\n\t\"password\": \"1234\"\n}" 192 | }, 193 | "url": { 194 | "raw": "{{url}}/user/1", 195 | "host": [ 196 | "{{url}}" 197 | ], 198 | "path": [ 199 | "user", 200 | "1" 201 | ] 202 | } 203 | }, 204 | "response": [] 205 | }, 206 | { 207 | "name": "delete user by id", 208 | "request": { 209 | "method": "DELETE", 210 | "header": [], 211 | "body": { 212 | "mode": "raw", 213 | "raw": "{\n\t\"username\": \"jose\",\n\t\"password\": \"1234\"\n}" 214 | }, 215 | "url": { 216 | "raw": "{{url}}/user/2", 217 | "host": [ 218 | "{{url}}" 219 | ], 220 | "path": [ 221 | "user", 222 | "2" 223 | ] 224 | } 225 | }, 226 | "response": [] 227 | } 228 | ] 229 | }, 230 | { 231 | "name": "items", 232 | "item": [ 233 | { 234 | "name": "get item/name", 235 | "request": { 236 | "method": "GET", 237 | "header": [], 238 | "body": { 239 | "mode": "raw", 240 | "raw": "" 241 | }, 242 | "url": { 243 | "raw": "{{url}}/item/chair", 244 | "host": [ 245 | "{{url}}" 246 | ], 247 | "path": [ 248 | "item", 249 | "chair" 250 | ] 251 | } 252 | }, 253 | "response": [] 254 | }, 255 | { 256 | "name": "post item/name", 257 | "request": { 258 | "method": "POST", 259 | "header": [ 260 | { 261 | "key": "Authorization", 262 | "value": "Bearer {{access_token}}" 263 | }, 264 | { 265 | "key": "Content-Type", 266 | "value": "application/json" 267 | } 268 | ], 269 | "body": { 270 | "mode": "raw", 271 | "raw": "{\n \"price\": 12.99,\n \"store_id\": 1\n}" 272 | }, 273 | "url": { 274 | "raw": "{{url}}/item/chair", 275 | "host": [ 276 | "{{url}}" 277 | ], 278 | "path": [ 279 | "item", 280 | "chair" 281 | ] 282 | } 283 | }, 284 | "response": [] 285 | }, 286 | { 287 | "name": "put item/name", 288 | "request": { 289 | "method": "PUT", 290 | "header": [ 291 | { 292 | "key": "Content-Type", 293 | "value": "application/json" 294 | } 295 | ], 296 | "body": { 297 | "mode": "raw", 298 | "raw": "{\n \"price\": 20.99,\n \"store_id\": 1\n}" 299 | }, 300 | "url": { 301 | "raw": "{{url}}/item/chair", 302 | "host": [ 303 | "{{url}}" 304 | ], 305 | "path": [ 306 | "item", 307 | "chair" 308 | ] 309 | } 310 | }, 311 | "response": [] 312 | }, 313 | { 314 | "name": "delete item by name", 315 | "request": { 316 | "method": "DELETE", 317 | "header": [ 318 | { 319 | "key": "Authorization", 320 | "value": "Bearer {{access_token}}" 321 | }, 322 | { 323 | "key": "Content-Type", 324 | "value": "application/json" 325 | } 326 | ], 327 | "body": { 328 | "mode": "raw", 329 | "raw": "" 330 | }, 331 | "url": { 332 | "raw": "{{url}}/item/chair", 333 | "host": [ 334 | "{{url}}" 335 | ], 336 | "path": [ 337 | "item", 338 | "chair" 339 | ] 340 | } 341 | }, 342 | "response": [] 343 | }, 344 | { 345 | "name": "get all items", 346 | "request": { 347 | "method": "GET", 348 | "header": [], 349 | "body": { 350 | "mode": "raw", 351 | "raw": "{\n \"username\" : \"cristiano\",\n \"password\" : \"12345678\"\n}" 352 | }, 353 | "url": { 354 | "raw": "{{url}}/items", 355 | "host": [ 356 | "{{url}}" 357 | ], 358 | "path": [ 359 | "items" 360 | ] 361 | } 362 | }, 363 | "response": [] 364 | } 365 | ] 366 | }, 367 | { 368 | "name": "stores", 369 | "item": [ 370 | { 371 | "name": "create a new store", 372 | "request": { 373 | "method": "POST", 374 | "header": [], 375 | "body": { 376 | "mode": "raw", 377 | "raw": "" 378 | }, 379 | "url": { 380 | "raw": "{{url}}/store/My Wonderful Store", 381 | "host": [ 382 | "{{url}}" 383 | ], 384 | "path": [ 385 | "store", 386 | "My Wonderful Store" 387 | ] 388 | } 389 | }, 390 | "response": [] 391 | }, 392 | { 393 | "name": "get store by name", 394 | "request": { 395 | "method": "GET", 396 | "header": [], 397 | "body": { 398 | "mode": "raw", 399 | "raw": "" 400 | }, 401 | "url": { 402 | "raw": "{{url}}/store/My Wonderful Store", 403 | "host": [ 404 | "{{url}}" 405 | ], 406 | "path": [ 407 | "store", 408 | "My Wonderful Store" 409 | ] 410 | } 411 | }, 412 | "response": [] 413 | }, 414 | { 415 | "name": "delete a new store by name", 416 | "request": { 417 | "method": "DELETE", 418 | "header": [], 419 | "body": { 420 | "mode": "raw", 421 | "raw": "" 422 | }, 423 | "url": { 424 | "raw": "{{url}}/store/My Wonderful Store", 425 | "host": [ 426 | "{{url}}" 427 | ], 428 | "path": [ 429 | "store", 430 | "My Wonderful Store" 431 | ] 432 | } 433 | }, 434 | "response": [] 435 | }, 436 | { 437 | "name": "get all stores", 438 | "request": { 439 | "method": "GET", 440 | "header": [], 441 | "body": { 442 | "mode": "raw", 443 | "raw": "" 444 | }, 445 | "url": { 446 | "raw": "{{url}}/stores", 447 | "host": [ 448 | "{{url}}" 449 | ], 450 | "path": [ 451 | "stores" 452 | ] 453 | } 454 | }, 455 | "response": [] 456 | } 457 | ] 458 | } 459 | ] 460 | } -------------------------------------------------------------------------------- /S01/Access the e-book for Section 1 here!.txt: -------------------------------------------------------------------------------- 1 | Access the e-book for Section 1 here! 2 | Welcome to the course once again! 3 | 4 | In order to get up to speed, in this section we'll be looking at a basic REST API. It's something we learned about in the introductory course, but I appreciate you may not have taken that course! 5 | 6 | To help you with this section, we've written an e-book. You can read it, reference it, or treat it as an extra way to understand the starting code and what goes on in our first REST API. 7 | 8 | Access the e-book here. 9 | 10 | Together with the videos, it should be plenty to get you acquainted with REST APIs with Flask and Python! 11 | 12 | As always, if you have any questions, fire away in the Course Q&A or the Slack channel (which you can join by clicking this link: http://slack.tecla.do) -------------------------------------------------------------------------------- /S01/New Text Document.txt: -------------------------------------------------------------------------------- 1 | https://black.readthedocs.io/en/stable/ 2 | https://github.com/psf/black -------------------------------------------------------------------------------- /S01/end-code - @classmethod across the board.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/end-code - @classmethod across the board.zip -------------------------------------------------------------------------------- /S01/end-code - Adding basic type hinting.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/end-code - Adding basic type hinting.zip -------------------------------------------------------------------------------- /S01/end-code - Adding custom JSON types.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/end-code - Adding custom JSON types.zip -------------------------------------------------------------------------------- /S01/end-code - Improving errors with constants.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/end-code - Improving errors with constants.zip -------------------------------------------------------------------------------- /S01/end-code - Refactoring our resources.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/end-code - Refactoring our resources.zip -------------------------------------------------------------------------------- /S01/end-code - Should we have unique names.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/end-code - Should we have unique names.zip -------------------------------------------------------------------------------- /S01/end-code - Simplifying our error handling.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/end-code - Simplifying our error handling.zip -------------------------------------------------------------------------------- /S01/end-code - Using the current class as a type hint.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/end-code - Using the current class as a type hint.zip -------------------------------------------------------------------------------- /S01/end-code- Using Black for code formatting.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/end-code- Using Black for code formatting.zip -------------------------------------------------------------------------------- /S01/start-code - @classmethod across the board.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/start-code - @classmethod across the board.zip -------------------------------------------------------------------------------- /S01/start-code - Adding basic type hinting.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/start-code - Adding basic type hinting.zip -------------------------------------------------------------------------------- /S01/start-code - Adding custom JSON types.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/start-code - Adding custom JSON types.zip -------------------------------------------------------------------------------- /S01/start-code - Refactoring our resources.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/start-code - Refactoring our resources.zip -------------------------------------------------------------------------------- /S01/start-code - Reviewing the beginner course code.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/start-code - Reviewing the beginner course code.zip -------------------------------------------------------------------------------- /S01/start-code - Should we have unique names.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/start-code - Should we have unique names.zip -------------------------------------------------------------------------------- /S01/start-code - Simplifying our error handling.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/start-code - Simplifying our error handling.zip -------------------------------------------------------------------------------- /S01/start-code - Using the current class as a type hint.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/start-code - Using the current class as a type hint.zip -------------------------------------------------------------------------------- /S01/start-code- Improving errors with constants.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/start-code- Improving errors with constants.zip -------------------------------------------------------------------------------- /S01/start-code.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/start-code.zip -------------------------------------------------------------------------------- /S01/starter-code - Using Black for code formatting.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S01/starter-code - Using Black for code formatting.zip -------------------------------------------------------------------------------- /S02/ARAC-Section02-Marshmallow.postman-collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "8cc3e552-24fa-42a1-ad3d-e4ddce67ef75", 4 | "name": "ARAC-Section02-Marshmallow", 5 | "description": "This collection contains the requests for the section 01 code of the Advanced REST API Course.", 6 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 7 | }, 8 | "item": [ 9 | { 10 | "name": "users", 11 | "item": [ 12 | { 13 | "name": "register a new user", 14 | "request": { 15 | "method": "POST", 16 | "header": [ 17 | { 18 | "key": "Content-Type", 19 | "value": "application/json" 20 | } 21 | ], 22 | "body": { 23 | "mode": "raw", 24 | "raw": "{\n\t\"username\": \"jose\",\n\t\"password\": \"1234\"\n}" 25 | }, 26 | "url": { 27 | "raw": "{{url}}/register", 28 | "host": [ 29 | "{{url}}" 30 | ], 31 | "path": [ 32 | "register" 33 | ] 34 | } 35 | }, 36 | "response": [] 37 | }, 38 | { 39 | "name": "login", 40 | "event": [ 41 | { 42 | "listen": "test", 43 | "script": { 44 | "id": "8c0c0ed6-c206-4c88-9349-429e024e312b", 45 | "type": "text/javascript", 46 | "exec": [ 47 | "var jsonData = pm.response.json();", 48 | "pm.test(\"access_token not empty\", function () {", 49 | " pm.expect(jsonData.access_token).not.eql(undefined);", 50 | "});", 51 | "", 52 | "pm.test(\"refresh token not empty\", function () {", 53 | " pm.expect(jsonData.refresh_token).not.eql(undefined);", 54 | "});", 55 | "// set access token as environement variable", 56 | "if (jsonData.access_token !== undefined) {", 57 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 58 | "} else {", 59 | " postman.setEnvironmentVariable(\"access_token\", null);", 60 | "}", 61 | "// set refresh token as environement variable", 62 | "if (jsonData.refresh_token !== undefined) {", 63 | " postman.setEnvironmentVariable(\"refresh_token\", jsonData.refresh_token);", 64 | "} else {", 65 | " postman.setEnvironmentVariable(\"refresh_token\", null);", 66 | "}" 67 | ] 68 | } 69 | } 70 | ], 71 | "request": { 72 | "method": "POST", 73 | "header": [ 74 | { 75 | "key": "Content-Type", 76 | "value": "application/json" 77 | } 78 | ], 79 | "body": { 80 | "mode": "raw", 81 | "raw": "{\n \"username\" : \"jose\",\n \"password\" : \"1234\"\n}" 82 | }, 83 | "url": { 84 | "raw": "{{url}}/login", 85 | "host": [ 86 | "{{url}}" 87 | ], 88 | "path": [ 89 | "login" 90 | ] 91 | } 92 | }, 93 | "response": [] 94 | }, 95 | { 96 | "name": "logout", 97 | "event": [ 98 | { 99 | "listen": "test", 100 | "script": { 101 | "id": "dc763e9b-e6c7-4ff3-9766-637976a5c64b", 102 | "type": "text/javascript", 103 | "exec": [ 104 | "" 105 | ] 106 | } 107 | } 108 | ], 109 | "request": { 110 | "method": "POST", 111 | "header": [ 112 | { 113 | "key": "Authorization", 114 | "value": "Bearer {{access_token}}" 115 | } 116 | ], 117 | "body": { 118 | "mode": "raw", 119 | "raw": "" 120 | }, 121 | "url": { 122 | "raw": "{{url}}/logout", 123 | "host": [ 124 | "{{url}}" 125 | ], 126 | "path": [ 127 | "logout" 128 | ] 129 | } 130 | }, 131 | "response": [] 132 | }, 133 | { 134 | "name": "refresh token", 135 | "event": [ 136 | { 137 | "listen": "test", 138 | "script": { 139 | "id": "ad818ea6-8f79-436e-b756-ad878666ae9e", 140 | "type": "text/javascript", 141 | "exec": [ 142 | "var jsonData = pm.response.json();", 143 | "pm.test(\"access_token not empty\", function () {", 144 | " pm.expect(jsonData.access_token).not.eql(undefined);", 145 | "});", 146 | "// set access token as environement variable", 147 | "if (jsonData.access_token !== undefined) {", 148 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 149 | "} else {", 150 | " postman.setEnvironmentVariable(\"access_token\", null);", 151 | "}" 152 | ] 153 | } 154 | } 155 | ], 156 | "request": { 157 | "method": "POST", 158 | "header": [ 159 | { 160 | "key": "Content-Type", 161 | "value": "application/json" 162 | }, 163 | { 164 | "key": "Authorization", 165 | "value": "Bearer {{refresh_token}}" 166 | } 167 | ], 168 | "body": { 169 | "mode": "raw", 170 | "raw": "" 171 | }, 172 | "url": { 173 | "raw": "{{url}}/refresh", 174 | "host": [ 175 | "{{url}}" 176 | ], 177 | "path": [ 178 | "refresh" 179 | ] 180 | } 181 | }, 182 | "response": [] 183 | }, 184 | { 185 | "name": "get user by id", 186 | "request": { 187 | "method": "GET", 188 | "header": [], 189 | "body": { 190 | "mode": "raw", 191 | "raw": "{\n\t\"username\": \"jose\",\n\t\"password\": \"1234\"\n}" 192 | }, 193 | "url": { 194 | "raw": "{{url}}/user/1", 195 | "host": [ 196 | "{{url}}" 197 | ], 198 | "path": [ 199 | "user", 200 | "1" 201 | ] 202 | } 203 | }, 204 | "response": [] 205 | }, 206 | { 207 | "name": "delete user by id", 208 | "request": { 209 | "method": "DELETE", 210 | "header": [], 211 | "body": { 212 | "mode": "raw", 213 | "raw": "{\n\t\"username\": \"jose\",\n\t\"password\": \"1234\"\n}" 214 | }, 215 | "url": { 216 | "raw": "{{url}}/user/1", 217 | "host": [ 218 | "{{url}}" 219 | ], 220 | "path": [ 221 | "user", 222 | "1" 223 | ] 224 | } 225 | }, 226 | "response": [] 227 | } 228 | ] 229 | }, 230 | { 231 | "name": "items", 232 | "item": [ 233 | { 234 | "name": "get item/name", 235 | "request": { 236 | "method": "GET", 237 | "header": [], 238 | "body": { 239 | "mode": "raw", 240 | "raw": "" 241 | }, 242 | "url": { 243 | "raw": "{{url}}/item/chair", 244 | "host": [ 245 | "{{url}}" 246 | ], 247 | "path": [ 248 | "item", 249 | "chair" 250 | ] 251 | } 252 | }, 253 | "response": [] 254 | }, 255 | { 256 | "name": "post item/name", 257 | "request": { 258 | "method": "POST", 259 | "header": [ 260 | { 261 | "key": "Authorization", 262 | "value": "Bearer {{access_token}}" 263 | }, 264 | { 265 | "key": "Content-Type", 266 | "value": "application/json" 267 | } 268 | ], 269 | "body": { 270 | "mode": "raw", 271 | "raw": "{\n \"price\": 12.99,\n \"store_id\": 1\n}" 272 | }, 273 | "url": { 274 | "raw": "{{url}}/item/chair", 275 | "host": [ 276 | "{{url}}" 277 | ], 278 | "path": [ 279 | "item", 280 | "chair" 281 | ] 282 | } 283 | }, 284 | "response": [] 285 | }, 286 | { 287 | "name": "put item/name", 288 | "request": { 289 | "method": "PUT", 290 | "header": [ 291 | { 292 | "key": "Content-Type", 293 | "value": "application/json" 294 | } 295 | ], 296 | "body": { 297 | "mode": "raw", 298 | "raw": "{\n \"price\": 20.99,\n \"store_id\": 1\n}" 299 | }, 300 | "url": { 301 | "raw": "{{url}}/item/chair", 302 | "host": [ 303 | "{{url}}" 304 | ], 305 | "path": [ 306 | "item", 307 | "chair" 308 | ] 309 | } 310 | }, 311 | "response": [] 312 | }, 313 | { 314 | "name": "delete item by name", 315 | "request": { 316 | "method": "DELETE", 317 | "header": [ 318 | { 319 | "key": "Authorization", 320 | "value": "Bearer {{access_token}}" 321 | }, 322 | { 323 | "key": "Content-Type", 324 | "value": "application/json" 325 | } 326 | ], 327 | "body": { 328 | "mode": "raw", 329 | "raw": "" 330 | }, 331 | "url": { 332 | "raw": "{{url}}/item/chair", 333 | "host": [ 334 | "{{url}}" 335 | ], 336 | "path": [ 337 | "item", 338 | "chair" 339 | ] 340 | } 341 | }, 342 | "response": [] 343 | }, 344 | { 345 | "name": "get all items", 346 | "request": { 347 | "method": "GET", 348 | "header": [], 349 | "body": { 350 | "mode": "raw", 351 | "raw": "{\n \"username\" : \"cristiano\",\n \"password\" : \"12345678\"\n}" 352 | }, 353 | "url": { 354 | "raw": "{{url}}/items", 355 | "host": [ 356 | "{{url}}" 357 | ], 358 | "path": [ 359 | "items" 360 | ] 361 | } 362 | }, 363 | "response": [] 364 | } 365 | ] 366 | }, 367 | { 368 | "name": "stores", 369 | "item": [ 370 | { 371 | "name": "create a new store", 372 | "request": { 373 | "method": "POST", 374 | "header": [], 375 | "body": { 376 | "mode": "raw", 377 | "raw": "" 378 | }, 379 | "url": { 380 | "raw": "{{url}}/store/My Wonderful Store", 381 | "host": [ 382 | "{{url}}" 383 | ], 384 | "path": [ 385 | "store", 386 | "My Wonderful Store" 387 | ] 388 | } 389 | }, 390 | "response": [] 391 | }, 392 | { 393 | "name": "get store by name", 394 | "request": { 395 | "method": "GET", 396 | "header": [], 397 | "body": { 398 | "mode": "raw", 399 | "raw": "" 400 | }, 401 | "url": { 402 | "raw": "{{url}}/store/My Wonderful Store", 403 | "host": [ 404 | "{{url}}" 405 | ], 406 | "path": [ 407 | "store", 408 | "My Wonderful Store" 409 | ] 410 | } 411 | }, 412 | "response": [] 413 | }, 414 | { 415 | "name": "delete a new store by name", 416 | "request": { 417 | "method": "DELETE", 418 | "header": [], 419 | "body": { 420 | "mode": "raw", 421 | "raw": "" 422 | }, 423 | "url": { 424 | "raw": "{{url}}/store/My Wonderful Store", 425 | "host": [ 426 | "{{url}}" 427 | ], 428 | "path": [ 429 | "store", 430 | "My Wonderful Store" 431 | ] 432 | } 433 | }, 434 | "response": [] 435 | }, 436 | { 437 | "name": "get all stores", 438 | "request": { 439 | "method": "GET", 440 | "header": [], 441 | "body": { 442 | "mode": "raw", 443 | "raw": "" 444 | }, 445 | "url": { 446 | "raw": "{{url}}/stores", 447 | "host": [ 448 | "{{url}}" 449 | ], 450 | "path": [ 451 | "stores" 452 | ] 453 | } 454 | }, 455 | "response": [] 456 | } 457 | ] 458 | } 459 | ] 460 | } -------------------------------------------------------------------------------- /S02/deserializing - Deserialization with Marshmallow.py: -------------------------------------------------------------------------------- 1 | from marshmallow import Schema, fields 2 | 3 | 4 | class BookSchema(Schema): 5 | title = fields.Str() 6 | author = fields.Str() 7 | 8 | 9 | incoming_book_data = { 10 | "title": "Clean Code", 11 | "author": "Bob Martin", 12 | "description": "A book about writing cleaner code, with examples in Java", 13 | } 14 | 15 | book_schema = BookSchema() 16 | book = book_schema.load(incoming_book_data) 17 | 18 | print(book) 19 | -------------------------------------------------------------------------------- /S02/end-code - Adding stores to our REST API.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/end-code - Adding stores to our REST API.zip -------------------------------------------------------------------------------- /S02/end-code - Deduplicating error handling.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/end-code - Deduplicating error handling.zip -------------------------------------------------------------------------------- /S02/end-code - Adding items to our REST API.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/end-code - Adding items to our REST API.zip -------------------------------------------------------------------------------- /S02/end-code - Introduction to Flask-Marshmallow.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/end-code - Introduction to Flask-Marshmallow.zip -------------------------------------------------------------------------------- /S02/end-code - Migrating from virtualenv to Pipenv.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/end-code - Migrating from virtualenv to Pipenv.zip -------------------------------------------------------------------------------- /S02/end-code - Using vanilla Marshmallow with the API.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/end-code - Using vanilla Marshmallow with the API.zip -------------------------------------------------------------------------------- /S02/serializing - Serialization with Marshmallow.py: -------------------------------------------------------------------------------- 1 | from marshmallow import Schema, fields 2 | 3 | 4 | class BookSchema(Schema): 5 | title = fields.Str() 6 | author = fields.Str() 7 | 8 | 9 | class Book: 10 | def __init__(self, title, author): 11 | self.title = title 12 | self.author = author 13 | 14 | 15 | book = Book("Clean Code", "Bob Martin") 16 | 17 | book_schema = BookSchema() 18 | book_dict = book_schema.dump(book) 19 | 20 | print(book_dict) 21 | -------------------------------------------------------------------------------- /S02/start-code - Adding stores to our REST API.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/start-code - Adding stores to our REST API.zip -------------------------------------------------------------------------------- /S02/start-code - Deduplicating error handling.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/start-code - Deduplicating error handling.zip -------------------------------------------------------------------------------- /S02/start-code - Adding items to our REST API.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/start-code - Adding items to our REST API.zip -------------------------------------------------------------------------------- /S02/start-code - Introduction to Flask-Marshmallow.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/start-code - Introduction to Flask-Marshmallow.zip -------------------------------------------------------------------------------- /S02/start-code - Migrating from virtualenv to Pipenv.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/start-code - Migrating from virtualenv to Pipenv.zip -------------------------------------------------------------------------------- /S02/start-code - Using vanilla Marshmallow with the API.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S02/start-code - Using vanilla Marshmallow with the API.zip -------------------------------------------------------------------------------- /S03/ARAC-Section03-Email-Confirmation.postman-collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "4048ce38-8ae8-408b-a2a8-bf9ed1ce2ad4", 4 | "name": "ARAC-Section03-Email Confirmation", 5 | "description": "This collection contains the requests for the section 02, Email Confirmation, of the Advanced REST API Course.", 6 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 7 | }, 8 | "item": [ 9 | { 10 | "name": "users", 11 | "item": [ 12 | { 13 | "name": "register a new user", 14 | "request": { 15 | "method": "POST", 16 | "header": [ 17 | { 18 | "key": "Content-Type", 19 | "value": "application/json" 20 | } 21 | ], 22 | "body": { 23 | "mode": "raw", 24 | "raw": "{\n\t\"username\": \"jose\",\n\t\"email\": \"{{test_email}}\",\n\t\"password\": \"1234\"\n}" 25 | }, 26 | "url": { 27 | "raw": "{{url}}/register", 28 | "host": [ 29 | "{{url}}" 30 | ], 31 | "path": [ 32 | "register" 33 | ] 34 | } 35 | }, 36 | "response": [] 37 | }, 38 | { 39 | "name": "login", 40 | "event": [ 41 | { 42 | "listen": "test", 43 | "script": { 44 | "id": "8c0c0ed6-c206-4c88-9349-429e024e312b", 45 | "type": "text/javascript", 46 | "exec": [ 47 | "var jsonData = pm.response.json();", 48 | "pm.test(\"access_token not empty\", function () {", 49 | " pm.expect(jsonData.access_token).not.eql(undefined);", 50 | "});", 51 | "", 52 | "pm.test(\"refresh token not empty\", function () {", 53 | " pm.expect(jsonData.refresh_token).not.eql(undefined);", 54 | "});", 55 | "// set access token as environement variable", 56 | "if (jsonData.access_token !== undefined) {", 57 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 58 | "} else {", 59 | " postman.setEnvironmentVariable(\"access_token\", null);", 60 | "}", 61 | "// set refresh token as environement variable", 62 | "if (jsonData.refresh_token !== undefined) {", 63 | " postman.setEnvironmentVariable(\"refresh_token\", jsonData.refresh_token);", 64 | "} else {", 65 | " postman.setEnvironmentVariable(\"refresh_token\", null);", 66 | "}" 67 | ] 68 | } 69 | } 70 | ], 71 | "request": { 72 | "method": "POST", 73 | "header": [ 74 | { 75 | "key": "Content-Type", 76 | "value": "application/json" 77 | } 78 | ], 79 | "body": { 80 | "mode": "raw", 81 | "raw": "{\n \"username\" : \"jose\",\n \"email\": \"{{test_email}}\",\n \"password\" : \"1234\"\n}" 82 | }, 83 | "url": { 84 | "raw": "{{url}}/login", 85 | "host": [ 86 | "{{url}}" 87 | ], 88 | "path": [ 89 | "login" 90 | ] 91 | } 92 | }, 93 | "response": [] 94 | }, 95 | { 96 | "name": "refresh token", 97 | "event": [ 98 | { 99 | "listen": "test", 100 | "script": { 101 | "id": "ad818ea6-8f79-436e-b756-ad878666ae9e", 102 | "type": "text/javascript", 103 | "exec": [ 104 | "var jsonData = pm.response.json();", 105 | "pm.test(\"access_token not empty\", function () {", 106 | " pm.expect(jsonData.access_token).not.eql(undefined);", 107 | "});", 108 | "// set access token as environement variable", 109 | "if (jsonData.access_token !== undefined) {", 110 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 111 | "} else {", 112 | " postman.setEnvironmentVariable(\"access_token\", null);", 113 | "}" 114 | ] 115 | } 116 | } 117 | ], 118 | "request": { 119 | "method": "POST", 120 | "header": [ 121 | { 122 | "key": "Content-Type", 123 | "value": "application/json" 124 | }, 125 | { 126 | "key": "Authorization", 127 | "value": "Bearer {{refresh_token}}" 128 | } 129 | ], 130 | "body": { 131 | "mode": "raw", 132 | "raw": "" 133 | }, 134 | "url": { 135 | "raw": "{{url}}/refresh", 136 | "host": [ 137 | "{{url}}" 138 | ], 139 | "path": [ 140 | "refresh" 141 | ] 142 | } 143 | }, 144 | "response": [] 145 | }, 146 | { 147 | "name": "get user by id", 148 | "request": { 149 | "method": "GET", 150 | "header": [], 151 | "body": { 152 | "mode": "raw", 153 | "raw": "{\n\t\"username\": \"jose\",\n\t\"password\": \"1234\"\n}" 154 | }, 155 | "url": { 156 | "raw": "{{url}}/user/1", 157 | "host": [ 158 | "{{url}}" 159 | ], 160 | "path": [ 161 | "user", 162 | "1" 163 | ] 164 | } 165 | }, 166 | "response": [] 167 | }, 168 | { 169 | "name": "logout", 170 | "event": [ 171 | { 172 | "listen": "test", 173 | "script": { 174 | "id": "dc763e9b-e6c7-4ff3-9766-637976a5c64b", 175 | "type": "text/javascript", 176 | "exec": [ 177 | "" 178 | ] 179 | } 180 | } 181 | ], 182 | "request": { 183 | "method": "POST", 184 | "header": [ 185 | { 186 | "key": "Authorization", 187 | "value": "Bearer {{access_token}}" 188 | } 189 | ], 190 | "body": { 191 | "mode": "raw", 192 | "raw": "" 193 | }, 194 | "url": { 195 | "raw": "{{url}}/logout", 196 | "host": [ 197 | "{{url}}" 198 | ], 199 | "path": [ 200 | "logout" 201 | ] 202 | } 203 | }, 204 | "response": [] 205 | }, 206 | { 207 | "name": "delete user by id", 208 | "request": { 209 | "method": "DELETE", 210 | "header": [], 211 | "body": { 212 | "mode": "raw", 213 | "raw": "{\n\t\"username\": \"jose\",\n\t\"password\": \"1234\"\n}" 214 | }, 215 | "url": { 216 | "raw": "{{url}}/user/2", 217 | "host": [ 218 | "{{url}}" 219 | ], 220 | "path": [ 221 | "user", 222 | "2" 223 | ] 224 | } 225 | }, 226 | "response": [] 227 | }, 228 | { 229 | "name": "confirm registration", 230 | "event": [ 231 | { 232 | "listen": "test", 233 | "script": { 234 | "id": "703822c5-04cf-4085-bf99-049373d9bd23", 235 | "type": "text/javascript", 236 | "exec": [ 237 | "" 238 | ] 239 | } 240 | } 241 | ], 242 | "request": { 243 | "method": "GET", 244 | "header": [], 245 | "body": { 246 | "mode": "raw", 247 | "raw": "" 248 | }, 249 | "url": { 250 | "raw": "{{url}}/user_confirm/1", 251 | "host": [ 252 | "{{url}}" 253 | ], 254 | "path": [ 255 | "user_confirm", 256 | "1" 257 | ] 258 | } 259 | }, 260 | "response": [] 261 | } 262 | ] 263 | }, 264 | { 265 | "name": "items", 266 | "item": [ 267 | { 268 | "name": "post item/name", 269 | "request": { 270 | "method": "POST", 271 | "header": [ 272 | { 273 | "key": "Authorization", 274 | "value": "Bearer {{access_token}}" 275 | }, 276 | { 277 | "key": "Content-Type", 278 | "value": "application/json" 279 | } 280 | ], 281 | "body": { 282 | "mode": "raw", 283 | "raw": "{\n \"price\": 12.99,\n \"store_id\": 1\n}" 284 | }, 285 | "url": { 286 | "raw": "{{url}}/item/chair", 287 | "host": [ 288 | "{{url}}" 289 | ], 290 | "path": [ 291 | "item", 292 | "chair" 293 | ] 294 | } 295 | }, 296 | "response": [] 297 | }, 298 | { 299 | "name": "put item/name", 300 | "request": { 301 | "method": "PUT", 302 | "header": [ 303 | { 304 | "key": "Content-Type", 305 | "value": "application/json" 306 | } 307 | ], 308 | "body": { 309 | "mode": "raw", 310 | "raw": "{\n \"price\": 20.99,\n \"store_id\": 1\n}" 311 | }, 312 | "url": { 313 | "raw": "{{url}}/item/chair", 314 | "host": [ 315 | "{{url}}" 316 | ], 317 | "path": [ 318 | "item", 319 | "chair" 320 | ] 321 | } 322 | }, 323 | "response": [] 324 | }, 325 | { 326 | "name": "get all items", 327 | "request": { 328 | "method": "GET", 329 | "header": [], 330 | "body": { 331 | "mode": "raw", 332 | "raw": "{\n \"username\" : \"cristiano\",\n \"password\" : \"12345678\"\n}" 333 | }, 334 | "url": { 335 | "raw": "{{url}}/items", 336 | "host": [ 337 | "{{url}}" 338 | ], 339 | "path": [ 340 | "items" 341 | ] 342 | } 343 | }, 344 | "response": [] 345 | }, 346 | { 347 | "name": "get item/name", 348 | "request": { 349 | "method": "GET", 350 | "header": [], 351 | "body": { 352 | "mode": "raw", 353 | "raw": "" 354 | }, 355 | "url": { 356 | "raw": "{{url}}/item/chair", 357 | "host": [ 358 | "{{url}}" 359 | ], 360 | "path": [ 361 | "item", 362 | "chair" 363 | ] 364 | } 365 | }, 366 | "response": [] 367 | }, 368 | { 369 | "name": "delete item by name", 370 | "request": { 371 | "method": "DELETE", 372 | "header": [ 373 | { 374 | "key": "Authorization", 375 | "value": "Bearer {{access_token}}" 376 | }, 377 | { 378 | "key": "Content-Type", 379 | "value": "application/json" 380 | } 381 | ], 382 | "body": { 383 | "mode": "raw", 384 | "raw": "" 385 | }, 386 | "url": { 387 | "raw": "{{url}}/item/chair", 388 | "host": [ 389 | "{{url}}" 390 | ], 391 | "path": [ 392 | "item", 393 | "chair" 394 | ] 395 | } 396 | }, 397 | "response": [] 398 | } 399 | ] 400 | }, 401 | { 402 | "name": "stores", 403 | "item": [ 404 | { 405 | "name": "create a new store", 406 | "request": { 407 | "method": "POST", 408 | "header": [], 409 | "body": { 410 | "mode": "raw", 411 | "raw": "" 412 | }, 413 | "url": { 414 | "raw": "{{url}}/store/My Wonderful Store", 415 | "host": [ 416 | "{{url}}" 417 | ], 418 | "path": [ 419 | "store", 420 | "My Wonderful Store" 421 | ] 422 | } 423 | }, 424 | "response": [] 425 | }, 426 | { 427 | "name": "get store by name", 428 | "request": { 429 | "method": "GET", 430 | "header": [], 431 | "body": { 432 | "mode": "raw", 433 | "raw": "" 434 | }, 435 | "url": { 436 | "raw": "{{url}}/store/My Wonderful Store", 437 | "host": [ 438 | "{{url}}" 439 | ], 440 | "path": [ 441 | "store", 442 | "My Wonderful Store" 443 | ] 444 | } 445 | }, 446 | "response": [] 447 | }, 448 | { 449 | "name": "get all stores", 450 | "request": { 451 | "method": "GET", 452 | "header": [], 453 | "body": { 454 | "mode": "raw", 455 | "raw": "" 456 | }, 457 | "url": { 458 | "raw": "{{url}}/stores", 459 | "host": [ 460 | "{{url}}" 461 | ], 462 | "path": [ 463 | "stores" 464 | ] 465 | } 466 | }, 467 | "response": [] 468 | }, 469 | { 470 | "name": "delete a new store by name", 471 | "request": { 472 | "method": "DELETE", 473 | "header": [], 474 | "body": { 475 | "mode": "raw", 476 | "raw": "" 477 | }, 478 | "url": { 479 | "raw": "{{url}}/store/My Wonderful Store", 480 | "host": [ 481 | "{{url}}" 482 | ], 483 | "path": [ 484 | "store", 485 | "My Wonderful Store" 486 | ] 487 | } 488 | }, 489 | "response": [] 490 | } 491 | ] 492 | } 493 | ], 494 | "event": [ 495 | { 496 | "listen": "prerequest", 497 | "script": { 498 | "id": "e46eeb9a-a866-43bd-a696-a41334b3a97f", 499 | "type": "text/javascript", 500 | "exec": [ 501 | "" 502 | ] 503 | } 504 | }, 505 | { 506 | "listen": "test", 507 | "script": { 508 | "id": "43f785c7-bf37-4fb9-8d30-60f97919657d", 509 | "type": "text/javascript", 510 | "exec": [ 511 | "" 512 | ] 513 | } 514 | } 515 | ] 516 | } -------------------------------------------------------------------------------- /S03/end-code - Adding more configuration to .env.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/end-code - Adding more configuration to .env.zip -------------------------------------------------------------------------------- /S03/end-code - Telling users they are active.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/end-code - Telling users they are active.zip -------------------------------------------------------------------------------- /S03/end-code - Activating users manually.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/end-code - Activating users manually.zip -------------------------------------------------------------------------------- /S03/end-code - Adding an activated property.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/end-code - Adding an activated property.zip -------------------------------------------------------------------------------- /S03/end-code - Creating our Mailgun library file.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/end-code - Creating our Mailgun library file.zip -------------------------------------------------------------------------------- /S03/end-code - Error handling in Mailgun.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/end-code - Error handling in Mailgun.zip -------------------------------------------------------------------------------- /S03/end-code - Sending e-mails with Mailgun (Part 1).zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/end-code - Sending e-mails with Mailgun (Part 1).zip -------------------------------------------------------------------------------- /S03/end-code - Using .env files in Flask.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/end-code - Using .env files in Flask.zip -------------------------------------------------------------------------------- /S03/start-code - Adding more configuration to .env.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/start-code - Adding more configuration to .env.zip -------------------------------------------------------------------------------- /S03/start-code - Telling users they are active.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/start-code - Telling users they are active.zip -------------------------------------------------------------------------------- /S03/start-code - Activating users manually.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/start-code - Activating users manually.zip -------------------------------------------------------------------------------- /S03/start-code - Adding an activated property.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/start-code - Adding an activated property.zip -------------------------------------------------------------------------------- /S03/start-code - Creating our Mailgun library file.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/start-code - Creating our Mailgun library file.zip -------------------------------------------------------------------------------- /S03/start-code - Error handling in Mailgun.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/start-code - Error handling in Mailgun.zip -------------------------------------------------------------------------------- /S03/start-code - Sending e-mails with Mailgun (Part 1).zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/start-code - Sending e-mails with Mailgun (Part 1).zip -------------------------------------------------------------------------------- /S03/start-code - Using .env files in Flask.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S03/start-code - Using .env files in Flask.zip -------------------------------------------------------------------------------- /S04/ARAC-Section04-ConfirmationModel.postman-collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "a6a5b7ef-970a-4ac0-934a-197f606b13e0", 4 | "name": "ARAC-Section04-ConfirmationModel", 5 | "description": "This collection contains the requests for the section 04, Confirmation Model, of the Advanced REST API Course.", 6 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 7 | }, 8 | "item": [ 9 | { 10 | "name": "users", 11 | "item": [ 12 | { 13 | "name": "register a new user", 14 | "request": { 15 | "method": "POST", 16 | "header": [ 17 | { 18 | "key": "Content-Type", 19 | "value": "application/json" 20 | } 21 | ], 22 | "body": { 23 | "mode": "raw", 24 | "raw": "{\n\t\"username\": \"jose\",\n\t\"email\": \"{{test_email}}\",\n\t\"password\": \"1234\"\n}" 25 | }, 26 | "url": { 27 | "raw": "{{url}}/register", 28 | "host": [ 29 | "{{url}}" 30 | ], 31 | "path": [ 32 | "register" 33 | ] 34 | } 35 | }, 36 | "response": [] 37 | }, 38 | { 39 | "name": "login", 40 | "event": [ 41 | { 42 | "listen": "test", 43 | "script": { 44 | "id": "8c0c0ed6-c206-4c88-9349-429e024e312b", 45 | "type": "text/javascript", 46 | "exec": [ 47 | "var jsonData = pm.response.json();", 48 | "pm.test(\"access_token not empty\", function () {", 49 | " pm.expect(jsonData.access_token).not.eql(undefined);", 50 | "});", 51 | "", 52 | "pm.test(\"refresh token not empty\", function () {", 53 | " pm.expect(jsonData.refresh_token).not.eql(undefined);", 54 | "});", 55 | "// set access token as environement variable", 56 | "if (jsonData.access_token !== undefined) {", 57 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 58 | "} else {", 59 | " postman.setEnvironmentVariable(\"access_token\", null);", 60 | "}", 61 | "// set refresh token as environement variable", 62 | "if (jsonData.refresh_token !== undefined) {", 63 | " postman.setEnvironmentVariable(\"refresh_token\", jsonData.refresh_token);", 64 | "} else {", 65 | " postman.setEnvironmentVariable(\"refresh_token\", null);", 66 | "}" 67 | ] 68 | } 69 | } 70 | ], 71 | "request": { 72 | "method": "POST", 73 | "header": [ 74 | { 75 | "key": "Content-Type", 76 | "value": "application/json" 77 | } 78 | ], 79 | "body": { 80 | "mode": "raw", 81 | "raw": "{\n \"username\" : \"jose\",\n \"password\" : \"1234\"\n}" 82 | }, 83 | "url": { 84 | "raw": "{{url}}/login", 85 | "host": [ 86 | "{{url}}" 87 | ], 88 | "path": [ 89 | "login" 90 | ] 91 | } 92 | }, 93 | "response": [] 94 | }, 95 | { 96 | "name": "logout", 97 | "event": [ 98 | { 99 | "listen": "test", 100 | "script": { 101 | "id": "dc763e9b-e6c7-4ff3-9766-637976a5c64b", 102 | "type": "text/javascript", 103 | "exec": [ 104 | "" 105 | ] 106 | } 107 | } 108 | ], 109 | "request": { 110 | "method": "POST", 111 | "header": [ 112 | { 113 | "key": "Authorization", 114 | "value": "Bearer {{access_token}}" 115 | } 116 | ], 117 | "body": { 118 | "mode": "raw", 119 | "raw": "" 120 | }, 121 | "url": { 122 | "raw": "{{url}}/logout", 123 | "host": [ 124 | "{{url}}" 125 | ], 126 | "path": [ 127 | "logout" 128 | ] 129 | } 130 | }, 131 | "response": [] 132 | }, 133 | { 134 | "name": "get user by id", 135 | "event": [ 136 | { 137 | "listen": "test", 138 | "script": { 139 | "id": "4311f7d8-283e-4ba6-843b-d67de64489de", 140 | "type": "text/javascript", 141 | "exec": [ 142 | "var jsonData = pm.response.json();", 143 | "pm.test(\"user confirmation found\", function () {", 144 | " pm.expect(jsonData.confirmation).not.eql(undefined);", 145 | "});", 146 | "", 147 | "if (jsonData.confirmation !== undefined) {", 148 | " pm.environment.set(\"confirmation_id\", jsonData.confirmation.id);", 149 | "}" 150 | ] 151 | } 152 | } 153 | ], 154 | "request": { 155 | "method": "GET", 156 | "header": [], 157 | "body": { 158 | "mode": "raw", 159 | "raw": "{\n\t\"username\": \"jose\",\n\t\"password\": \"1234\"\n}" 160 | }, 161 | "url": { 162 | "raw": "{{url}}/user/1", 163 | "host": [ 164 | "{{url}}" 165 | ], 166 | "path": [ 167 | "user", 168 | "1" 169 | ] 170 | } 171 | }, 172 | "response": [] 173 | }, 174 | { 175 | "name": "delete user by id", 176 | "request": { 177 | "method": "DELETE", 178 | "header": [], 179 | "body": { 180 | "mode": "raw", 181 | "raw": "{\n\t\"username\": \"jose\",\n\t\"password\": \"1234\"\n}" 182 | }, 183 | "url": { 184 | "raw": "{{url}}/user/2", 185 | "host": [ 186 | "{{url}}" 187 | ], 188 | "path": [ 189 | "user", 190 | "2" 191 | ] 192 | } 193 | }, 194 | "response": [] 195 | }, 196 | { 197 | "name": "confirm registration", 198 | "event": [ 199 | { 200 | "listen": "test", 201 | "script": { 202 | "id": "703822c5-04cf-4085-bf99-049373d9bd23", 203 | "type": "text/javascript", 204 | "exec": [ 205 | "" 206 | ] 207 | } 208 | } 209 | ], 210 | "request": { 211 | "method": "GET", 212 | "header": [], 213 | "body": { 214 | "mode": "raw", 215 | "raw": "" 216 | }, 217 | "url": { 218 | "raw": "{{url}}/user_confirm/{{confirmation_id}}", 219 | "host": [ 220 | "{{url}}" 221 | ], 222 | "path": [ 223 | "user_confirm", 224 | "{{confirmation_id}}" 225 | ] 226 | } 227 | }, 228 | "response": [] 229 | }, 230 | { 231 | "name": "refresh token", 232 | "event": [ 233 | { 234 | "listen": "test", 235 | "script": { 236 | "id": "ad818ea6-8f79-436e-b756-ad878666ae9e", 237 | "type": "text/javascript", 238 | "exec": [ 239 | "var jsonData = pm.response.json();", 240 | "pm.test(\"access_token not empty\", function () {", 241 | " pm.expect(jsonData.access_token).not.eql(undefined);", 242 | "});", 243 | "// set access token as environement variable", 244 | "if (jsonData.access_token !== undefined) {", 245 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 246 | "} else {", 247 | " postman.setEnvironmentVariable(\"access_token\", null);", 248 | "}" 249 | ] 250 | } 251 | } 252 | ], 253 | "request": { 254 | "method": "POST", 255 | "header": [ 256 | { 257 | "key": "Content-Type", 258 | "value": "application/json" 259 | }, 260 | { 261 | "key": "Authorization", 262 | "value": "Bearer {{refresh_token}}" 263 | } 264 | ], 265 | "body": { 266 | "mode": "raw", 267 | "raw": "" 268 | }, 269 | "url": { 270 | "raw": "{{url}}/refresh", 271 | "host": [ 272 | "{{url}}" 273 | ], 274 | "path": [ 275 | "refresh" 276 | ] 277 | } 278 | }, 279 | "response": [] 280 | }, 281 | { 282 | "name": "get all confirmations by user id", 283 | "event": [ 284 | { 285 | "listen": "test", 286 | "script": { 287 | "id": "703822c5-04cf-4085-bf99-049373d9bd23", 288 | "type": "text/javascript", 289 | "exec": [ 290 | "" 291 | ] 292 | } 293 | } 294 | ], 295 | "request": { 296 | "method": "GET", 297 | "header": [], 298 | "body": { 299 | "mode": "raw", 300 | "raw": "" 301 | }, 302 | "url": { 303 | "raw": "{{url}}/confirmation/user/1", 304 | "host": [ 305 | "{{url}}" 306 | ], 307 | "path": [ 308 | "confirmation", 309 | "user", 310 | "1" 311 | ] 312 | } 313 | }, 314 | "response": [] 315 | }, 316 | { 317 | "name": "resend confirmation", 318 | "event": [ 319 | { 320 | "listen": "test", 321 | "script": { 322 | "id": "703822c5-04cf-4085-bf99-049373d9bd23", 323 | "type": "text/javascript", 324 | "exec": [ 325 | "" 326 | ] 327 | } 328 | } 329 | ], 330 | "request": { 331 | "method": "POST", 332 | "header": [], 333 | "body": { 334 | "mode": "raw", 335 | "raw": "" 336 | }, 337 | "url": { 338 | "raw": "{{url}}/confirmation/user/1", 339 | "host": [ 340 | "{{url}}" 341 | ], 342 | "path": [ 343 | "confirmation", 344 | "user", 345 | "1" 346 | ] 347 | } 348 | }, 349 | "response": [] 350 | } 351 | ] 352 | }, 353 | { 354 | "name": "items", 355 | "item": [ 356 | { 357 | "name": "post item/name", 358 | "request": { 359 | "method": "POST", 360 | "header": [ 361 | { 362 | "key": "Authorization", 363 | "value": "Bearer {{access_token}}" 364 | }, 365 | { 366 | "key": "Content-Type", 367 | "value": "application/json" 368 | } 369 | ], 370 | "body": { 371 | "mode": "raw", 372 | "raw": "{\n \"price\": 12.99,\n \"store_id\": 1\n}" 373 | }, 374 | "url": { 375 | "raw": "{{url}}/item/chair", 376 | "host": [ 377 | "{{url}}" 378 | ], 379 | "path": [ 380 | "item", 381 | "chair" 382 | ] 383 | } 384 | }, 385 | "response": [] 386 | }, 387 | { 388 | "name": "get item/name", 389 | "request": { 390 | "method": "GET", 391 | "header": [], 392 | "body": { 393 | "mode": "raw", 394 | "raw": "" 395 | }, 396 | "url": { 397 | "raw": "{{url}}/item/chair", 398 | "host": [ 399 | "{{url}}" 400 | ], 401 | "path": [ 402 | "item", 403 | "chair" 404 | ] 405 | } 406 | }, 407 | "response": [] 408 | }, 409 | { 410 | "name": "put item/name", 411 | "request": { 412 | "method": "PUT", 413 | "header": [ 414 | { 415 | "key": "Content-Type", 416 | "value": "application/json" 417 | } 418 | ], 419 | "body": { 420 | "mode": "raw", 421 | "raw": "{\n \"price\": 20.99,\n \"store_id\": 1\n}" 422 | }, 423 | "url": { 424 | "raw": "{{url}}/item/chair", 425 | "host": [ 426 | "{{url}}" 427 | ], 428 | "path": [ 429 | "item", 430 | "chair" 431 | ] 432 | } 433 | }, 434 | "response": [] 435 | }, 436 | { 437 | "name": "delete item by name", 438 | "request": { 439 | "method": "DELETE", 440 | "header": [ 441 | { 442 | "key": "Authorization", 443 | "value": "Bearer {{access_token}}" 444 | }, 445 | { 446 | "key": "Content-Type", 447 | "value": "application/json" 448 | } 449 | ], 450 | "body": { 451 | "mode": "raw", 452 | "raw": "" 453 | }, 454 | "url": { 455 | "raw": "{{url}}/item/chair", 456 | "host": [ 457 | "{{url}}" 458 | ], 459 | "path": [ 460 | "item", 461 | "chair" 462 | ] 463 | } 464 | }, 465 | "response": [] 466 | }, 467 | { 468 | "name": "get all items", 469 | "request": { 470 | "method": "GET", 471 | "header": [], 472 | "body": { 473 | "mode": "raw", 474 | "raw": "{\n \"username\" : \"cristiano\",\n \"password\" : \"12345678\"\n}" 475 | }, 476 | "url": { 477 | "raw": "{{url}}/items", 478 | "host": [ 479 | "{{url}}" 480 | ], 481 | "path": [ 482 | "items" 483 | ] 484 | } 485 | }, 486 | "response": [] 487 | } 488 | ] 489 | }, 490 | { 491 | "name": "stores", 492 | "item": [ 493 | { 494 | "name": "create a new store", 495 | "request": { 496 | "method": "POST", 497 | "header": [], 498 | "body": { 499 | "mode": "raw", 500 | "raw": "" 501 | }, 502 | "url": { 503 | "raw": "{{url}}/store/My Wonderful Store", 504 | "host": [ 505 | "{{url}}" 506 | ], 507 | "path": [ 508 | "store", 509 | "My Wonderful Store" 510 | ] 511 | } 512 | }, 513 | "response": [] 514 | }, 515 | { 516 | "name": "get store by name", 517 | "request": { 518 | "method": "GET", 519 | "header": [], 520 | "body": { 521 | "mode": "raw", 522 | "raw": "" 523 | }, 524 | "url": { 525 | "raw": "{{url}}/store/My Wonderful Store", 526 | "host": [ 527 | "{{url}}" 528 | ], 529 | "path": [ 530 | "store", 531 | "My Wonderful Store" 532 | ] 533 | } 534 | }, 535 | "response": [] 536 | }, 537 | { 538 | "name": "delete a new store by name", 539 | "request": { 540 | "method": "DELETE", 541 | "header": [], 542 | "body": { 543 | "mode": "raw", 544 | "raw": "" 545 | }, 546 | "url": { 547 | "raw": "{{url}}/store/My Wonderful Store", 548 | "host": [ 549 | "{{url}}" 550 | ], 551 | "path": [ 552 | "store", 553 | "My Wonderful Store" 554 | ] 555 | } 556 | }, 557 | "response": [] 558 | }, 559 | { 560 | "name": "get all stores", 561 | "request": { 562 | "method": "GET", 563 | "header": [], 564 | "body": { 565 | "mode": "raw", 566 | "raw": "" 567 | }, 568 | "url": { 569 | "raw": "{{url}}/stores", 570 | "host": [ 571 | "{{url}}" 572 | ], 573 | "path": [ 574 | "stores" 575 | ] 576 | } 577 | }, 578 | "response": [] 579 | } 580 | ] 581 | } 582 | ], 583 | "event": [ 584 | { 585 | "listen": "prerequest", 586 | "script": { 587 | "id": "e46eeb9a-a866-43bd-a696-a41334b3a97f", 588 | "type": "text/javascript", 589 | "exec": [ 590 | "" 591 | ] 592 | } 593 | }, 594 | { 595 | "listen": "test", 596 | "script": { 597 | "id": "43f785c7-bf37-4fb9-8d30-60f97919657d", 598 | "type": "text/javascript", 599 | "exec": [ 600 | "" 601 | ] 602 | } 603 | } 604 | ] 605 | } -------------------------------------------------------------------------------- /S04/New Text Document.txt: -------------------------------------------------------------------------------- 1 | https://pythonhosted.org/Flask-Babel/ -------------------------------------------------------------------------------- /S04/end-code - Creating the ConfirmationModel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/end-code - Creating the ConfirmationModel.zip -------------------------------------------------------------------------------- /S04/end-code - Updating our UserResource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/end-code - Updating our UserResource.zip -------------------------------------------------------------------------------- /S04/end-code - Adding a new language to our API.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/end-code - Adding a new language to our API.zip -------------------------------------------------------------------------------- /S04/end-code - Adding the last confirmation to the user schema.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/end-code - Adding the last confirmation to the user schema.zip -------------------------------------------------------------------------------- /S04/end-code - Changes in our UserModel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/end-code - Changes in our UserModel.zip -------------------------------------------------------------------------------- /S04/end-code - Creating a simple translation library.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/end-code - Creating a simple translation library.zip -------------------------------------------------------------------------------- /S04/end-code - Creating our ConfirmationResource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/end-code - Creating our ConfirmationResource.zip -------------------------------------------------------------------------------- /S04/end-code - Fixing our app.py.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/end-code - Fixing our app.py.zip -------------------------------------------------------------------------------- /S04/end-code - Storing strings in config files.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/end-code - Storing strings in config files.zip -------------------------------------------------------------------------------- /S04/end-code - Updating our resources to use translations.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/end-code - Updating our resources to use translations.zip -------------------------------------------------------------------------------- /S04/start-code - Creating the ConfirmationModel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/start-code - Creating the ConfirmationModel.zip -------------------------------------------------------------------------------- /S04/start-code - Updating our UserResource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/start-code - Updating our UserResource.zip -------------------------------------------------------------------------------- /S04/start-code - Adding a new language to our API.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/start-code - Adding a new language to our API.zip -------------------------------------------------------------------------------- /S04/start-code - Adding the last confirmation to the user schema.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/start-code - Adding the last confirmation to the user schema.zip -------------------------------------------------------------------------------- /S04/start-code - Changes in our UserModel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/start-code - Changes in our UserModel.zip -------------------------------------------------------------------------------- /S04/start-code - Creating a simple translation library.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/start-code - Creating a simple translation library.zip -------------------------------------------------------------------------------- /S04/start-code - Creating our ConfirmationResource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/start-code - Creating our ConfirmationResource.zip -------------------------------------------------------------------------------- /S04/start-code - Fixing our app.py.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/start-code - Fixing our app.py.zip -------------------------------------------------------------------------------- /S04/start-code - Storing strings in config files.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/start-code - Storing strings in config files.zip -------------------------------------------------------------------------------- /S04/start-code - Updating our resources to use translations.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S04/start-code - Updating our resources to use translations.zip -------------------------------------------------------------------------------- /S04/translation-file-checking-script.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | STRINGS_FOLDER = "strings" 5 | SOURCE_TRANSLATION = "en-gb.json" 6 | source_strings = {} 7 | 8 | 9 | with open(f"strings/{source}") as f: 10 | source_strings = json.load(f) 11 | 12 | 13 | def check_contains_all_strings(source, source_name, compared, compared_name): 14 | for key in source.keys(): 15 | if key not in compared.keys(): 16 | print(f"{key} was present in {source_name} but not in {compared_name}.") 17 | 18 | 19 | for filename in os.listdir(STRINGS_FOLDER): 20 | if SOURCE_TRANSLATION in filename: 21 | continue 22 | 23 | with open(f"{STRINGS_FOLDER}/{filename}") as file: 24 | strings = json.load(file) 25 | check_contains_all_strings( 26 | source_strings, 27 | SOURCE_TRANSLATION, 28 | strings, 29 | filename 30 | ) 31 | -------------------------------------------------------------------------------- /S05/ARA-Section05-FlowTests.postman-collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "e3e05580-f8c8-4207-9d25-bfea9a1010de", 4 | "name": "ARA-Section05-FlowTests", 5 | "description": "Tests of the flows of the API.", 6 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 7 | }, 8 | "item": [ 9 | { 10 | "name": "Item Creation Flow Test", 11 | "item": [ 12 | { 13 | "name": "Make sure item deleted before creating", 14 | "event": [ 15 | { 16 | "listen": "test", 17 | "script": { 18 | "id": "4d0b74d5-ece9-4e75-9859-4d41493c0d3d", 19 | "exec": [ 20 | "pm.test(\"Status code is 200\", function () {", 21 | " pm.response.to.not.have.status(401);", 22 | "});" 23 | ], 24 | "type": "text/javascript" 25 | } 26 | } 27 | ], 28 | "request": { 29 | "method": "DELETE", 30 | "header": [ 31 | { 32 | "key": "Authorization", 33 | "value": "Bearer {{access_token}}" 34 | }, 35 | { 36 | "key": "Content-Type", 37 | "value": "application/json" 38 | } 39 | ], 40 | "body": { 41 | "mode": "raw", 42 | "raw": "" 43 | }, 44 | "url": { 45 | "raw": "{{url}}/item/chair", 46 | "host": [ 47 | "{{url}}" 48 | ], 49 | "path": [ 50 | "item", 51 | "chair" 52 | ] 53 | }, 54 | "description": "Delete an item by name." 55 | }, 56 | "response": [ 57 | { 58 | "name": "delete non-existing item", 59 | "originalRequest": { 60 | "method": "DELETE", 61 | "header": [ 62 | { 63 | "key": "Authorization", 64 | "value": "Bearer {{access_token}}" 65 | }, 66 | { 67 | "key": "Content-Type", 68 | "value": "application/json" 69 | } 70 | ], 71 | "body": { 72 | "mode": "raw", 73 | "raw": "" 74 | }, 75 | "url": { 76 | "raw": "{{url}}/item/chairs", 77 | "host": [ 78 | "{{url}}" 79 | ], 80 | "path": [ 81 | "item", 82 | "chairs" 83 | ] 84 | } 85 | }, 86 | "status": "NOT FOUND", 87 | "code": 404, 88 | "_postman_previewlanguage": "json", 89 | "header": [ 90 | { 91 | "key": "Content-Length", 92 | "value": "37", 93 | "name": "Content-Length", 94 | "description": "The length of the response body in octets (8-bit bytes)" 95 | }, 96 | { 97 | "key": "Content-Type", 98 | "value": "application/json", 99 | "name": "Content-Type", 100 | "description": "The mime type of this content" 101 | }, 102 | { 103 | "key": "Date", 104 | "value": "Thu, 24 May 2018 18:38:47 GMT", 105 | "name": "Date", 106 | "description": "The date and time that the message was sent" 107 | }, 108 | { 109 | "key": "Server", 110 | "value": "Werkzeug/0.14.1 Python/3.6.1", 111 | "name": "Server", 112 | "description": "A name for the server" 113 | } 114 | ], 115 | "cookie": [], 116 | "body": "{\n \"message\": \"Item not found.\"\n}\n" 117 | }, 118 | { 119 | "name": "delete item by name", 120 | "originalRequest": { 121 | "method": "DELETE", 122 | "header": [ 123 | { 124 | "key": "Authorization", 125 | "value": "Bearer {{access_token}}" 126 | }, 127 | { 128 | "key": "Content-Type", 129 | "value": "application/json" 130 | } 131 | ], 132 | "body": { 133 | "mode": "raw", 134 | "raw": "" 135 | }, 136 | "url": { 137 | "raw": "{{url}}/item/chair", 138 | "host": [ 139 | "{{url}}" 140 | ], 141 | "path": [ 142 | "item", 143 | "chair" 144 | ] 145 | } 146 | }, 147 | "status": "OK", 148 | "code": 200, 149 | "_postman_previewlanguage": "json", 150 | "header": [ 151 | { 152 | "key": "Content-Length", 153 | "value": "35", 154 | "name": "Content-Length", 155 | "description": "The length of the response body in octets (8-bit bytes)" 156 | }, 157 | { 158 | "key": "Content-Type", 159 | "value": "application/json", 160 | "name": "Content-Type", 161 | "description": "The mime type of this content" 162 | }, 163 | { 164 | "key": "Date", 165 | "value": "Thu, 24 May 2018 18:38:33 GMT", 166 | "name": "Date", 167 | "description": "The date and time that the message was sent" 168 | }, 169 | { 170 | "key": "Server", 171 | "value": "Werkzeug/0.14.1 Python/3.6.1", 172 | "name": "Server", 173 | "description": "A name for the server" 174 | } 175 | ], 176 | "cookie": [], 177 | "body": "{\n \"message\": \"Item deleted.\"\n}\n" 178 | } 179 | ] 180 | }, 181 | { 182 | "name": "create an item", 183 | "event": [ 184 | { 185 | "listen": "test", 186 | "script": { 187 | "id": "e069da1a-ba13-4737-9220-5a151dfe323c", 188 | "exec": [ 189 | "pm.test(\"Item created successfully\", function () {", 190 | " pm.expect(pm.response.code).to.be.oneOf([201,202]);", 191 | "});" 192 | ], 193 | "type": "text/javascript" 194 | } 195 | } 196 | ], 197 | "request": { 198 | "method": "POST", 199 | "header": [ 200 | { 201 | "key": "Authorization", 202 | "value": "Bearer {{access_token}}" 203 | }, 204 | { 205 | "key": "Content-Type", 206 | "value": "application/json" 207 | } 208 | ], 209 | "body": { 210 | "mode": "raw", 211 | "raw": "{\n \"price\": 12.99,\n \"store_id\": 1\n}" 212 | }, 213 | "url": { 214 | "raw": "{{url}}/item/chair", 215 | "host": [ 216 | "{{url}}" 217 | ], 218 | "path": [ 219 | "item", 220 | "chair" 221 | ] 222 | }, 223 | "description": "Create a new item." 224 | }, 225 | "response": [ 226 | { 227 | "name": "post item without Bearer", 228 | "originalRequest": { 229 | "method": "POST", 230 | "header": [ 231 | { 232 | "key": "Authorization", 233 | "value": "Bearer {{access_token}}", 234 | "disabled": true 235 | }, 236 | { 237 | "key": "Content-Type", 238 | "value": "application/json" 239 | } 240 | ], 241 | "body": { 242 | "mode": "raw", 243 | "raw": "{\n \"price\": 12.99,\n \"store_id\": 1\n}" 244 | }, 245 | "url": { 246 | "raw": "{{url}}/item/chair", 247 | "host": [ 248 | "{{url}}" 249 | ], 250 | "path": [ 251 | "item", 252 | "chair" 253 | ] 254 | } 255 | }, 256 | "status": "UNAUTHORIZED", 257 | "code": 401, 258 | "_postman_previewlanguage": "json", 259 | "header": [ 260 | { 261 | "key": "Content-Length", 262 | "value": "44", 263 | "name": "Content-Length", 264 | "description": "The length of the response body in octets (8-bit bytes)" 265 | }, 266 | { 267 | "key": "Content-Type", 268 | "value": "application/json", 269 | "name": "Content-Type", 270 | "description": "The mime type of this content" 271 | }, 272 | { 273 | "key": "Date", 274 | "value": "Thu, 24 May 2018 18:35:25 GMT", 275 | "name": "Date", 276 | "description": "The date and time that the message was sent" 277 | }, 278 | { 279 | "key": "Server", 280 | "value": "Werkzeug/0.14.1 Python/3.6.1", 281 | "name": "Server", 282 | "description": "A name for the server" 283 | } 284 | ], 285 | "cookie": [], 286 | "body": "{\n \"msg\": \"Missing Authorization Header\"\n}\n" 287 | }, 288 | { 289 | "name": "post item with non-fresh token", 290 | "originalRequest": { 291 | "method": "POST", 292 | "header": [ 293 | { 294 | "key": "Authorization", 295 | "value": "Bearer {{access_token}}" 296 | }, 297 | { 298 | "key": "Content-Type", 299 | "value": "application/json" 300 | } 301 | ], 302 | "body": { 303 | "mode": "raw", 304 | "raw": "{\n \"price\": 12.99,\n \"store_id\": 1\n}" 305 | }, 306 | "url": { 307 | "raw": "{{url}}/item/chair", 308 | "host": [ 309 | "{{url}}" 310 | ], 311 | "path": [ 312 | "item", 313 | "chair" 314 | ] 315 | } 316 | }, 317 | "status": "UNAUTHORIZED", 318 | "code": 401, 319 | "_postman_previewlanguage": "json", 320 | "header": [ 321 | { 322 | "key": "Content-Length", 323 | "value": "36", 324 | "name": "Content-Length", 325 | "description": "The length of the response body in octets (8-bit bytes)" 326 | }, 327 | { 328 | "key": "Content-Type", 329 | "value": "application/json", 330 | "name": "Content-Type", 331 | "description": "The mime type of this content" 332 | }, 333 | { 334 | "key": "Date", 335 | "value": "Thu, 24 May 2018 18:35:49 GMT", 336 | "name": "Date", 337 | "description": "The date and time that the message was sent" 338 | }, 339 | { 340 | "key": "Server", 341 | "value": "Werkzeug/0.14.1 Python/3.6.1", 342 | "name": "Server", 343 | "description": "A name for the server" 344 | } 345 | ], 346 | "cookie": [], 347 | "body": "{\n \"msg\": \"Fresh token required\"\n}\n" 348 | }, 349 | { 350 | "name": "post item with duplicate name", 351 | "originalRequest": { 352 | "method": "POST", 353 | "header": [ 354 | { 355 | "key": "Authorization", 356 | "value": "Bearer {{access_token}}" 357 | }, 358 | { 359 | "key": "Content-Type", 360 | "value": "application/json" 361 | } 362 | ], 363 | "body": { 364 | "mode": "raw", 365 | "raw": "{\n \"price\": 12.99,\n \"store_id\": 1\n}" 366 | }, 367 | "url": { 368 | "raw": "{{url}}/item/chair", 369 | "host": [ 370 | "{{url}}" 371 | ], 372 | "path": [ 373 | "item", 374 | "chair" 375 | ] 376 | } 377 | }, 378 | "status": "BAD REQUEST", 379 | "code": 400, 380 | "_postman_previewlanguage": "json", 381 | "header": [ 382 | { 383 | "key": "Content-Length", 384 | "value": "61", 385 | "name": "Content-Length", 386 | "description": "The length of the response body in octets (8-bit bytes)" 387 | }, 388 | { 389 | "key": "Content-Type", 390 | "value": "application/json", 391 | "name": "Content-Type", 392 | "description": "The mime type of this content" 393 | }, 394 | { 395 | "key": "Date", 396 | "value": "Thu, 24 May 2018 18:35:07 GMT", 397 | "name": "Date", 398 | "description": "The date and time that the message was sent" 399 | }, 400 | { 401 | "key": "Server", 402 | "value": "Werkzeug/0.14.1 Python/3.6.1", 403 | "name": "Server", 404 | "description": "A name for the server" 405 | } 406 | ], 407 | "cookie": [], 408 | "body": "{\n \"message\": \"An item with name chair already exists.\"\n}\n" 409 | }, 410 | { 411 | "name": "post item by name", 412 | "originalRequest": { 413 | "method": "POST", 414 | "header": [ 415 | { 416 | "key": "Authorization", 417 | "value": "Bearer {{access_token}}" 418 | }, 419 | { 420 | "key": "Content-Type", 421 | "value": "application/json" 422 | } 423 | ], 424 | "body": { 425 | "mode": "raw", 426 | "raw": "{\n \"price\": 12.99,\n \"store_id\": 1\n}" 427 | }, 428 | "url": { 429 | "raw": "{{url}}/item/chair", 430 | "host": [ 431 | "{{url}}" 432 | ], 433 | "path": [ 434 | "item", 435 | "chair" 436 | ] 437 | } 438 | }, 439 | "status": "CREATED", 440 | "code": 201, 441 | "_postman_previewlanguage": "json", 442 | "header": [ 443 | { 444 | "key": "Content-Length", 445 | "value": "76", 446 | "name": "Content-Length", 447 | "description": "The length of the response body in octets (8-bit bytes)" 448 | }, 449 | { 450 | "key": "Content-Type", 451 | "value": "application/json", 452 | "name": "Content-Type", 453 | "description": "The mime type of this content" 454 | }, 455 | { 456 | "key": "Date", 457 | "value": "Thu, 24 May 2018 18:34:22 GMT", 458 | "name": "Date", 459 | "description": "The date and time that the message was sent" 460 | }, 461 | { 462 | "key": "Server", 463 | "value": "Werkzeug/0.14.1 Python/3.6.1", 464 | "name": "Server", 465 | "description": "A name for the server" 466 | } 467 | ], 468 | "cookie": [], 469 | "body": "{\n \"id\": 1,\n \"name\": \"chair\",\n \"price\": 12.99,\n \"store_id\": 1\n}\n" 470 | } 471 | ] 472 | }, 473 | { 474 | "name": "find item by name", 475 | "event": [ 476 | { 477 | "listen": "test", 478 | "script": { 479 | "id": "1ba6a91f-b745-4453-97b5-b55d4b3ebdc3", 480 | "exec": [ 481 | "pm.test(\"Item name and price correct\", function () {", 482 | " var jsonData = pm.response.json();", 483 | " pm.expect(jsonData.name).to.eql(\"chair\");", 484 | " pm.expect(jsonData.price).to.eql(12.99);", 485 | "});" 486 | ], 487 | "type": "text/javascript" 488 | } 489 | } 490 | ], 491 | "request": { 492 | "method": "GET", 493 | "header": [], 494 | "body": { 495 | "mode": "raw", 496 | "raw": "" 497 | }, 498 | "url": { 499 | "raw": "{{url}}/item/chair", 500 | "host": [ 501 | "{{url}}" 502 | ], 503 | "path": [ 504 | "item", 505 | "chair" 506 | ] 507 | }, 508 | "description": "Find an item by its name." 509 | }, 510 | "response": [ 511 | { 512 | "name": "get item by name", 513 | "originalRequest": { 514 | "method": "GET", 515 | "header": [], 516 | "body": { 517 | "mode": "raw", 518 | "raw": "" 519 | }, 520 | "url": { 521 | "raw": "{{url}}/item/chair", 522 | "host": [ 523 | "{{url}}" 524 | ], 525 | "path": [ 526 | "item", 527 | "chair" 528 | ] 529 | } 530 | }, 531 | "status": "OK", 532 | "code": 200, 533 | "_postman_previewlanguage": "json", 534 | "header": [ 535 | { 536 | "key": "Content-Length", 537 | "value": "76", 538 | "name": "Content-Length", 539 | "description": "The length of the response body in octets (8-bit bytes)" 540 | }, 541 | { 542 | "key": "Content-Type", 543 | "value": "application/json", 544 | "name": "Content-Type", 545 | "description": "The mime type of this content" 546 | }, 547 | { 548 | "key": "Date", 549 | "value": "Thu, 24 May 2018 18:36:09 GMT", 550 | "name": "Date", 551 | "description": "The date and time that the message was sent" 552 | }, 553 | { 554 | "key": "Server", 555 | "value": "Werkzeug/0.14.1 Python/3.6.1", 556 | "name": "Server", 557 | "description": "A name for the server" 558 | } 559 | ], 560 | "cookie": [], 561 | "body": "{\n \"id\": 1,\n \"name\": \"chair\",\n \"price\": 12.99,\n \"store_id\": 1\n}\n" 562 | } 563 | ] 564 | }, 565 | { 566 | "name": "upsert an item", 567 | "event": [ 568 | { 569 | "listen": "test", 570 | "script": { 571 | "id": "704e06fc-9dab-46e9-82e8-47cc9ec43c52", 572 | "exec": [ 573 | "pm.test(\"Item updated successfully\", function () {", 574 | " pm.expect(pm.response.code).eql(200);", 575 | "});", 576 | "", 577 | "pm.test(\"New price matches updated price\", function () {", 578 | " var jsonData = pm.response.json();", 579 | " pm.expect(jsonData.price).to.eql(20.99);", 580 | "});" 581 | ], 582 | "type": "text/javascript" 583 | } 584 | } 585 | ], 586 | "request": { 587 | "method": "PUT", 588 | "header": [ 589 | { 590 | "key": "Content-Type", 591 | "value": "application/json" 592 | } 593 | ], 594 | "body": { 595 | "mode": "raw", 596 | "raw": "{\n \"price\": 20.99,\n \"store_id\": 1\n}" 597 | }, 598 | "url": { 599 | "raw": "{{url}}/item/chair", 600 | "host": [ 601 | "{{url}}" 602 | ], 603 | "path": [ 604 | "item", 605 | "chair" 606 | ] 607 | }, 608 | "description": "Create or update an item. If is update, only the item price will get updated." 609 | }, 610 | "response": [ 611 | { 612 | "name": "create an item", 613 | "originalRequest": { 614 | "method": "PUT", 615 | "header": [ 616 | { 617 | "key": "Content-Type", 618 | "value": "application/json" 619 | } 620 | ], 621 | "body": { 622 | "mode": "raw", 623 | "raw": "{\n \"price\": 2000.99,\n \"store_id\": 1\n}" 624 | }, 625 | "url": { 626 | "raw": "{{url}}/item/piano", 627 | "host": [ 628 | "{{url}}" 629 | ], 630 | "path": [ 631 | "item", 632 | "piano" 633 | ] 634 | } 635 | }, 636 | "status": "OK", 637 | "code": 200, 638 | "_postman_previewlanguage": "json", 639 | "header": [ 640 | { 641 | "key": "Content-Length", 642 | "value": "78", 643 | "name": "Content-Length", 644 | "description": "The length of the response body in octets (8-bit bytes)" 645 | }, 646 | { 647 | "key": "Content-Type", 648 | "value": "application/json", 649 | "name": "Content-Type", 650 | "description": "The mime type of this content" 651 | }, 652 | { 653 | "key": "Date", 654 | "value": "Thu, 24 May 2018 18:40:52 GMT", 655 | "name": "Date", 656 | "description": "The date and time that the message was sent" 657 | }, 658 | { 659 | "key": "Server", 660 | "value": "Werkzeug/0.14.1 Python/3.6.1", 661 | "name": "Server", 662 | "description": "A name for the server" 663 | } 664 | ], 665 | "cookie": [], 666 | "body": "{\n \"id\": 2,\n \"name\": \"piano\",\n \"price\": 2000.99,\n \"store_id\": 1\n}\n" 667 | }, 668 | { 669 | "name": "upsert an item", 670 | "originalRequest": { 671 | "method": "PUT", 672 | "header": [ 673 | { 674 | "key": "Content-Type", 675 | "value": "application/json" 676 | } 677 | ], 678 | "body": { 679 | "mode": "raw", 680 | "raw": "{\n \"price\": 20.99,\n \"store_id\": 1\n}" 681 | }, 682 | "url": { 683 | "raw": "{{url}}/item/chair", 684 | "host": [ 685 | "{{url}}" 686 | ], 687 | "path": [ 688 | "item", 689 | "chair" 690 | ] 691 | } 692 | }, 693 | "status": "OK", 694 | "code": 200, 695 | "_postman_previewlanguage": "json", 696 | "header": [ 697 | { 698 | "key": "Content-Length", 699 | "value": "76", 700 | "name": "Content-Length", 701 | "description": "The length of the response body in octets (8-bit bytes)" 702 | }, 703 | { 704 | "key": "Content-Type", 705 | "value": "application/json", 706 | "name": "Content-Type", 707 | "description": "The mime type of this content" 708 | }, 709 | { 710 | "key": "Date", 711 | "value": "Thu, 24 May 2018 18:40:24 GMT", 712 | "name": "Date", 713 | "description": "The date and time that the message was sent" 714 | }, 715 | { 716 | "key": "Server", 717 | "value": "Werkzeug/0.14.1 Python/3.6.1", 718 | "name": "Server", 719 | "description": "A name for the server" 720 | } 721 | ], 722 | "cookie": [], 723 | "body": "{\n \"id\": 1,\n \"name\": \"chair\",\n \"price\": 20.99,\n \"store_id\": 1\n}\n" 724 | } 725 | ] 726 | }, 727 | { 728 | "name": "find updated item by name", 729 | "event": [ 730 | { 731 | "listen": "test", 732 | "script": { 733 | "id": "348106be-9c4b-4c82-9ff4-3dc58cea7402", 734 | "exec": [ 735 | "pm.test(\"New item price and name correct\", function () {", 736 | " var jsonData = pm.response.json();", 737 | " pm.expect(jsonData.name).to.eql(\"chair\");", 738 | " pm.expect(jsonData.price).to.eql(20.99);", 739 | "});" 740 | ], 741 | "type": "text/javascript" 742 | } 743 | } 744 | ], 745 | "request": { 746 | "method": "GET", 747 | "header": [], 748 | "body": { 749 | "mode": "raw", 750 | "raw": "" 751 | }, 752 | "url": { 753 | "raw": "{{url}}/item/chair", 754 | "host": [ 755 | "{{url}}" 756 | ], 757 | "path": [ 758 | "item", 759 | "chair" 760 | ] 761 | }, 762 | "description": "Find an item by its name." 763 | }, 764 | "response": [ 765 | { 766 | "name": "get item by name", 767 | "originalRequest": { 768 | "method": "GET", 769 | "header": [], 770 | "body": { 771 | "mode": "raw", 772 | "raw": "" 773 | }, 774 | "url": { 775 | "raw": "{{url}}/item/chair", 776 | "host": [ 777 | "{{url}}" 778 | ], 779 | "path": [ 780 | "item", 781 | "chair" 782 | ] 783 | } 784 | }, 785 | "status": "OK", 786 | "code": 200, 787 | "_postman_previewlanguage": "json", 788 | "header": [ 789 | { 790 | "key": "Content-Length", 791 | "value": "76", 792 | "name": "Content-Length", 793 | "description": "The length of the response body in octets (8-bit bytes)" 794 | }, 795 | { 796 | "key": "Content-Type", 797 | "value": "application/json", 798 | "name": "Content-Type", 799 | "description": "The mime type of this content" 800 | }, 801 | { 802 | "key": "Date", 803 | "value": "Thu, 24 May 2018 18:36:09 GMT", 804 | "name": "Date", 805 | "description": "The date and time that the message was sent" 806 | }, 807 | { 808 | "key": "Server", 809 | "value": "Werkzeug/0.14.1 Python/3.6.1", 810 | "name": "Server", 811 | "description": "A name for the server" 812 | } 813 | ], 814 | "cookie": [], 815 | "body": "{\n \"id\": 1,\n \"name\": \"chair\",\n \"price\": 12.99,\n \"store_id\": 1\n}\n" 816 | } 817 | ] 818 | }, 819 | { 820 | "name": "get all items", 821 | "event": [ 822 | { 823 | "listen": "test", 824 | "script": { 825 | "id": "9684d5b5-db2c-4fb7-bbb3-773d53791503", 826 | "exec": [ 827 | "pm.test(\"Item in list is chair costing 20.99\", function () {", 828 | " var jsonData = pm.response.json();", 829 | " pm.expect(jsonData.items).to.eql([{", 830 | " \"store_id\": 1,", 831 | " \"name\": \"chair\",", 832 | " \"id\": 1,", 833 | " \"price\": 20.99", 834 | " }]);", 835 | "});" 836 | ], 837 | "type": "text/javascript" 838 | } 839 | } 840 | ], 841 | "request": { 842 | "method": "GET", 843 | "header": [], 844 | "body": { 845 | "mode": "raw", 846 | "raw": "{\n \"username\" : \"cristiano\",\n \"password\" : \"12345678\"\n}" 847 | }, 848 | "url": { 849 | "raw": "{{url}}/items", 850 | "host": [ 851 | "{{url}}" 852 | ], 853 | "path": [ 854 | "items" 855 | ] 856 | }, 857 | "description": "Get a list of all items." 858 | }, 859 | "response": [ 860 | { 861 | "name": "get all items", 862 | "originalRequest": { 863 | "method": "GET", 864 | "header": [], 865 | "body": { 866 | "mode": "raw", 867 | "raw": "{\n \"username\" : \"cristiano\",\n \"password\" : \"12345678\"\n}" 868 | }, 869 | "url": { 870 | "raw": "{{url}}/items", 871 | "host": [ 872 | "{{url}}" 873 | ], 874 | "path": [ 875 | "items" 876 | ] 877 | } 878 | }, 879 | "status": "OK", 880 | "code": 200, 881 | "_postman_previewlanguage": "json", 882 | "header": [ 883 | { 884 | "key": "Content-Length", 885 | "value": "276", 886 | "name": "Content-Length", 887 | "description": "The length of the response body in octets (8-bit bytes)" 888 | }, 889 | { 890 | "key": "Content-Type", 891 | "value": "application/json", 892 | "name": "Content-Type", 893 | "description": "The mime type of this content" 894 | }, 895 | { 896 | "key": "Date", 897 | "value": "Thu, 24 May 2018 18:41:27 GMT", 898 | "name": "Date", 899 | "description": "The date and time that the message was sent" 900 | }, 901 | { 902 | "key": "Server", 903 | "value": "Werkzeug/0.14.1 Python/3.6.1", 904 | "name": "Server", 905 | "description": "A name for the server" 906 | } 907 | ], 908 | "cookie": [], 909 | "body": "{\n \"items\": [\n {\n \"id\": 1,\n \"name\": \"chair\",\n \"price\": 20.99,\n \"store_id\": 1\n },\n {\n \"id\": 2,\n \"name\": \"piano\",\n \"price\": 2000.99,\n \"store_id\": 1\n }\n ]\n}\n" 910 | } 911 | ] 912 | }, 913 | { 914 | "name": "delete item by name", 915 | "event": [ 916 | { 917 | "listen": "test", 918 | "script": { 919 | "id": "4d0b74d5-ece9-4e75-9859-4d41493c0d3d", 920 | "exec": [ 921 | "pm.test(\"Item deleted successfully\", function () {", 922 | " pm.response.to.have.status(200);", 923 | "});", 924 | "", 925 | "pm.test(\"Message is 'Item deleted.'\", function () {", 926 | " var jsonData = pm.response.json();", 927 | " pm.expect(jsonData.message).to.eql(\"Item deleted.\");", 928 | "});" 929 | ], 930 | "type": "text/javascript" 931 | } 932 | } 933 | ], 934 | "request": { 935 | "method": "DELETE", 936 | "header": [ 937 | { 938 | "key": "Authorization", 939 | "value": "Bearer {{access_token}}" 940 | }, 941 | { 942 | "key": "Content-Type", 943 | "value": "application/json" 944 | } 945 | ], 946 | "body": { 947 | "mode": "raw", 948 | "raw": "" 949 | }, 950 | "url": { 951 | "raw": "{{url}}/item/chair", 952 | "host": [ 953 | "{{url}}" 954 | ], 955 | "path": [ 956 | "item", 957 | "chair" 958 | ] 959 | }, 960 | "description": "Delete an item by name." 961 | }, 962 | "response": [ 963 | { 964 | "name": "delete non-existing item", 965 | "originalRequest": { 966 | "method": "DELETE", 967 | "header": [ 968 | { 969 | "key": "Authorization", 970 | "value": "Bearer {{access_token}}" 971 | }, 972 | { 973 | "key": "Content-Type", 974 | "value": "application/json" 975 | } 976 | ], 977 | "body": { 978 | "mode": "raw", 979 | "raw": "" 980 | }, 981 | "url": { 982 | "raw": "{{url}}/item/chairs", 983 | "host": [ 984 | "{{url}}" 985 | ], 986 | "path": [ 987 | "item", 988 | "chairs" 989 | ] 990 | } 991 | }, 992 | "status": "NOT FOUND", 993 | "code": 404, 994 | "_postman_previewlanguage": "json", 995 | "header": [ 996 | { 997 | "key": "Content-Length", 998 | "value": "37", 999 | "name": "Content-Length", 1000 | "description": "The length of the response body in octets (8-bit bytes)" 1001 | }, 1002 | { 1003 | "key": "Content-Type", 1004 | "value": "application/json", 1005 | "name": "Content-Type", 1006 | "description": "The mime type of this content" 1007 | }, 1008 | { 1009 | "key": "Date", 1010 | "value": "Thu, 24 May 2018 18:38:47 GMT", 1011 | "name": "Date", 1012 | "description": "The date and time that the message was sent" 1013 | }, 1014 | { 1015 | "key": "Server", 1016 | "value": "Werkzeug/0.14.1 Python/3.6.1", 1017 | "name": "Server", 1018 | "description": "A name for the server" 1019 | } 1020 | ], 1021 | "cookie": [], 1022 | "body": "{\n \"message\": \"Item not found.\"\n}\n" 1023 | }, 1024 | { 1025 | "name": "delete item by name", 1026 | "originalRequest": { 1027 | "method": "DELETE", 1028 | "header": [ 1029 | { 1030 | "key": "Authorization", 1031 | "value": "Bearer {{access_token}}" 1032 | }, 1033 | { 1034 | "key": "Content-Type", 1035 | "value": "application/json" 1036 | } 1037 | ], 1038 | "body": { 1039 | "mode": "raw", 1040 | "raw": "" 1041 | }, 1042 | "url": { 1043 | "raw": "{{url}}/item/chair", 1044 | "host": [ 1045 | "{{url}}" 1046 | ], 1047 | "path": [ 1048 | "item", 1049 | "chair" 1050 | ] 1051 | } 1052 | }, 1053 | "status": "OK", 1054 | "code": 200, 1055 | "_postman_previewlanguage": "json", 1056 | "header": [ 1057 | { 1058 | "key": "Content-Length", 1059 | "value": "35", 1060 | "name": "Content-Length", 1061 | "description": "The length of the response body in octets (8-bit bytes)" 1062 | }, 1063 | { 1064 | "key": "Content-Type", 1065 | "value": "application/json", 1066 | "name": "Content-Type", 1067 | "description": "The mime type of this content" 1068 | }, 1069 | { 1070 | "key": "Date", 1071 | "value": "Thu, 24 May 2018 18:38:33 GMT", 1072 | "name": "Date", 1073 | "description": "The date and time that the message was sent" 1074 | }, 1075 | { 1076 | "key": "Server", 1077 | "value": "Werkzeug/0.14.1 Python/3.6.1", 1078 | "name": "Server", 1079 | "description": "A name for the server" 1080 | } 1081 | ], 1082 | "cookie": [], 1083 | "body": "{\n \"message\": \"Item deleted.\"\n}\n" 1084 | } 1085 | ] 1086 | }, 1087 | { 1088 | "name": "get all items", 1089 | "event": [ 1090 | { 1091 | "listen": "test", 1092 | "script": { 1093 | "id": "7e635343-52f1-47a8-b233-6a76fdf1a832", 1094 | "exec": [ 1095 | "pm.test(\"Status code is 200\", function () {", 1096 | " pm.response.to.have.status(200);", 1097 | "});", 1098 | "", 1099 | "pm.test(\"No items returned\", function () {", 1100 | " var jsonData = pm.response.json();", 1101 | " pm.expect(jsonData.items.length).to.eql(0);", 1102 | "});" 1103 | ], 1104 | "type": "text/javascript" 1105 | } 1106 | } 1107 | ], 1108 | "request": { 1109 | "method": "GET", 1110 | "header": [], 1111 | "body": { 1112 | "mode": "raw", 1113 | "raw": "{\n \"username\" : \"cristiano\",\n \"password\" : \"12345678\"\n}" 1114 | }, 1115 | "url": { 1116 | "raw": "{{url}}/items", 1117 | "host": [ 1118 | "{{url}}" 1119 | ], 1120 | "path": [ 1121 | "items" 1122 | ] 1123 | }, 1124 | "description": "Get a list of all items." 1125 | }, 1126 | "response": [ 1127 | { 1128 | "name": "get all items", 1129 | "originalRequest": { 1130 | "method": "GET", 1131 | "header": [], 1132 | "body": { 1133 | "mode": "raw", 1134 | "raw": "{\n \"username\" : \"cristiano\",\n \"password\" : \"12345678\"\n}" 1135 | }, 1136 | "url": { 1137 | "raw": "{{url}}/items", 1138 | "host": [ 1139 | "{{url}}" 1140 | ], 1141 | "path": [ 1142 | "items" 1143 | ] 1144 | } 1145 | }, 1146 | "status": "OK", 1147 | "code": 200, 1148 | "_postman_previewlanguage": "json", 1149 | "header": [ 1150 | { 1151 | "key": "Content-Length", 1152 | "value": "276", 1153 | "name": "Content-Length", 1154 | "description": "The length of the response body in octets (8-bit bytes)" 1155 | }, 1156 | { 1157 | "key": "Content-Type", 1158 | "value": "application/json", 1159 | "name": "Content-Type", 1160 | "description": "The mime type of this content" 1161 | }, 1162 | { 1163 | "key": "Date", 1164 | "value": "Thu, 24 May 2018 18:41:27 GMT", 1165 | "name": "Date", 1166 | "description": "The date and time that the message was sent" 1167 | }, 1168 | { 1169 | "key": "Server", 1170 | "value": "Werkzeug/0.14.1 Python/3.6.1", 1171 | "name": "Server", 1172 | "description": "A name for the server" 1173 | } 1174 | ], 1175 | "cookie": [], 1176 | "body": "{\n \"items\": [\n {\n \"id\": 1,\n \"name\": \"chair\",\n \"price\": 20.99,\n \"store_id\": 1\n },\n {\n \"id\": 2,\n \"name\": \"piano\",\n \"price\": 2000.99,\n \"store_id\": 1\n }\n ]\n}\n" 1177 | } 1178 | ] 1179 | }, 1180 | { 1181 | "name": "find item by name", 1182 | "event": [ 1183 | { 1184 | "listen": "test", 1185 | "script": { 1186 | "id": "3e93b144-3066-45b7-86e3-0e1f8c81a53a", 1187 | "exec": [ 1188 | "pm.test(\"Message is 'Item not found.'\", function () {", 1189 | " var jsonData = pm.response.json();", 1190 | " pm.expect(jsonData.message).to.eql(\"Item not found.\");", 1191 | "});" 1192 | ], 1193 | "type": "text/javascript" 1194 | } 1195 | } 1196 | ], 1197 | "request": { 1198 | "method": "GET", 1199 | "header": [], 1200 | "body": { 1201 | "mode": "raw", 1202 | "raw": "" 1203 | }, 1204 | "url": { 1205 | "raw": "{{url}}/item/chair", 1206 | "host": [ 1207 | "{{url}}" 1208 | ], 1209 | "path": [ 1210 | "item", 1211 | "chair" 1212 | ] 1213 | }, 1214 | "description": "Find an item by its name." 1215 | }, 1216 | "response": [ 1217 | { 1218 | "name": "get item by name", 1219 | "originalRequest": { 1220 | "method": "GET", 1221 | "header": [], 1222 | "body": { 1223 | "mode": "raw", 1224 | "raw": "" 1225 | }, 1226 | "url": { 1227 | "raw": "{{url}}/item/chair", 1228 | "host": [ 1229 | "{{url}}" 1230 | ], 1231 | "path": [ 1232 | "item", 1233 | "chair" 1234 | ] 1235 | } 1236 | }, 1237 | "status": "OK", 1238 | "code": 200, 1239 | "_postman_previewlanguage": "json", 1240 | "header": [ 1241 | { 1242 | "key": "Content-Length", 1243 | "value": "76", 1244 | "name": "Content-Length", 1245 | "description": "The length of the response body in octets (8-bit bytes)" 1246 | }, 1247 | { 1248 | "key": "Content-Type", 1249 | "value": "application/json", 1250 | "name": "Content-Type", 1251 | "description": "The mime type of this content" 1252 | }, 1253 | { 1254 | "key": "Date", 1255 | "value": "Thu, 24 May 2018 18:36:09 GMT", 1256 | "name": "Date", 1257 | "description": "The date and time that the message was sent" 1258 | }, 1259 | { 1260 | "key": "Server", 1261 | "value": "Werkzeug/0.14.1 Python/3.6.1", 1262 | "name": "Server", 1263 | "description": "A name for the server" 1264 | } 1265 | ], 1266 | "cookie": [], 1267 | "body": "{\n \"id\": 1,\n \"name\": \"chair\",\n \"price\": 12.99,\n \"store_id\": 1\n}\n" 1268 | } 1269 | ] 1270 | } 1271 | ] 1272 | } 1273 | ] 1274 | } -------------------------------------------------------------------------------- /S06/New Text Document.txt: -------------------------------------------------------------------------------- 1 | https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface 2 | 3 | 4 | https://werkzeug.palletsprojects.com/en/0.14.x/datastructures/#werkzeug.datastructures.FileStorage -------------------------------------------------------------------------------- /S06/end-code - Creating our image helper library.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/end-code - Creating our image helper library.zip -------------------------------------------------------------------------------- /S06/end-code - Config files in Flask.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/end-code - Config files in Flask.zip -------------------------------------------------------------------------------- /S06/end-code - Creating our image schema.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/end-code - Creating our image schema.zip -------------------------------------------------------------------------------- /S06/end-code - Creating our image upload resource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/end-code - Creating our image upload resource.zip -------------------------------------------------------------------------------- /S06/end-code - Installing Flask-Uploads.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/end-code - Installing Flask-Uploads.zip -------------------------------------------------------------------------------- /S06/end-code - Retrieving and deleting images.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/end-code - Retrieving and deleting images.zip -------------------------------------------------------------------------------- /S06/end-code - Trying out our image upload.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/end-code - Trying out our image upload.zip -------------------------------------------------------------------------------- /S06/end-code_ Another example user avatars.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/end-code_ Another example user avatars.zip -------------------------------------------------------------------------------- /S06/end-code_Adding the avatar resource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/end-code_Adding the avatar resource.zip -------------------------------------------------------------------------------- /S06/start-code - Creating our image helper library.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/start-code - Creating our image helper library.zip -------------------------------------------------------------------------------- /S06/start-code - Config files in Flask.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/start-code - Config files in Flask.zip -------------------------------------------------------------------------------- /S06/start-code - Creating our image schema.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/start-code - Creating our image schema.zip -------------------------------------------------------------------------------- /S06/start-code - Creating our image upload resource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/start-code - Creating our image upload resource.zip -------------------------------------------------------------------------------- /S06/start-code - Installing Flask-Uploads.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/start-code - Installing Flask-Uploads.zip -------------------------------------------------------------------------------- /S06/start-code - Retrieving and deleting images.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/start-code - Retrieving and deleting images.zip -------------------------------------------------------------------------------- /S06/start-code - Trying out our image upload.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/start-code - Trying out our image upload.zip -------------------------------------------------------------------------------- /S06/start-code_ Another example user avatars.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/start-code_ Another example user avatars.zip -------------------------------------------------------------------------------- /S06/start-code_Adding the avatar resource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S06/start-code_Adding the avatar resource.zip -------------------------------------------------------------------------------- /S07/New Text Document.txt: -------------------------------------------------------------------------------- 1 | https://flask-sqlalchemy.palletsprojects.com/en/2.x/config/#using-custom-metadata-and-naming-conventions 2 | 3 | 4 | -------------------------------------------------------------------------------- /S07/end-code_ Connecting to our remote database.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S07/end-code_ Connecting to our remote database.zip -------------------------------------------------------------------------------- /S07/end-code_Adding a new column with migrations.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S07/end-code_Adding a new column with migrations.zip -------------------------------------------------------------------------------- /S07/end-code_Checking the Alembic script (important!).zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S07/end-code_Checking the Alembic script (important!).zip -------------------------------------------------------------------------------- /S07/end-code_Defining a SQLAlchemy naming convention.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S07/end-code_Defining a SQLAlchemy naming convention.zip -------------------------------------------------------------------------------- /S07/end-code_Initialising Flask-Migrate and Alembic.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S07/end-code_Initialising Flask-Migrate and Alembic.zip -------------------------------------------------------------------------------- /S07/start-code_ Connecting to our remote database.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S07/start-code_ Connecting to our remote database.zip -------------------------------------------------------------------------------- /S07/start-code_Adding a new column with migrations.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S07/start-code_Adding a new column with migrations.zip -------------------------------------------------------------------------------- /S07/start-code_Checking the Alembic script (important!).zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S07/start-code_Checking the Alembic script (important!).zip -------------------------------------------------------------------------------- /S07/start-code_Defining a SQLAlchemy naming convention.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S07/start-code_Defining a SQLAlchemy naming convention.zip -------------------------------------------------------------------------------- /S07/start-code_Initialising Flask-Migrate and Alembic.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S07/start-code_Initialising Flask-Migrate and Alembic.zip -------------------------------------------------------------------------------- /S07/start-code_What's in our starter code.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S07/start-code_What's in our starter code.zip -------------------------------------------------------------------------------- /S08/ARAC-Section08-OAuth.postman-collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "d9fefccf-8270-4109-971c-17494b06fe53", 4 | "name": "ARAC-Section08-OAuth", 5 | "description": "This collection contains the requests for the section 01 code of the Advanced REST API Course.", 6 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 7 | }, 8 | "item": [ 9 | { 10 | "name": "users", 11 | "item": [ 12 | { 13 | "name": "register a new user", 14 | "request": { 15 | "method": "POST", 16 | "header": [ 17 | { 18 | "key": "Content-Type", 19 | "value": "application/json" 20 | } 21 | ], 22 | "body": { 23 | "mode": "raw", 24 | "raw": "{\n \"username\": \"jose\",\n \"password\": \"1234\"\n}" 25 | }, 26 | "url": { 27 | "raw": "{{url}}/register", 28 | "host": [ 29 | "{{url}}" 30 | ], 31 | "path": [ 32 | "register" 33 | ] 34 | } 35 | }, 36 | "response": [] 37 | }, 38 | { 39 | "name": "set new user password", 40 | "request": { 41 | "method": "POST", 42 | "header": [ 43 | { 44 | "key": "Content-Type", 45 | "value": "application/json" 46 | }, 47 | { 48 | "key": "Authorization", 49 | "value": "Bearer {{access_token}}", 50 | "type": "text" 51 | } 52 | ], 53 | "body": { 54 | "mode": "raw", 55 | "raw": "{\n\t\"username\": \"jose\",\n\t\"password\": \"123456\"\n}" 56 | }, 57 | "url": { 58 | "raw": "{{server_address}}/user/password", 59 | "host": [ 60 | "{{server_address}}" 61 | ], 62 | "path": [ 63 | "user", 64 | "password" 65 | ] 66 | } 67 | }, 68 | "response": [] 69 | }, 70 | { 71 | "name": "get user by id", 72 | "request": { 73 | "method": "GET", 74 | "header": [], 75 | "body": { 76 | "mode": "raw", 77 | "raw": "{\n \"username\": \"jose\",\n \"password\": \"1234\"\n}" 78 | }, 79 | "url": { 80 | "raw": "{{server_address}}/user/1", 81 | "host": [ 82 | "{{server_address}}" 83 | ], 84 | "path": [ 85 | "user", 86 | "1" 87 | ] 88 | } 89 | }, 90 | "response": [] 91 | }, 92 | { 93 | "name": "delete user by id", 94 | "request": { 95 | "method": "DELETE", 96 | "header": [], 97 | "body": { 98 | "mode": "raw", 99 | "raw": "{\n \"username\": \"jose\",\n \"password\": \"1234\"\n}" 100 | }, 101 | "url": { 102 | "raw": "{{server_address}}/user/2", 103 | "host": [ 104 | "{{server_address}}" 105 | ], 106 | "path": [ 107 | "user", 108 | "2" 109 | ] 110 | } 111 | }, 112 | "response": [] 113 | }, 114 | { 115 | "name": "login", 116 | "event": [ 117 | { 118 | "listen": "test", 119 | "script": { 120 | "id": "8c0c0ed6-c206-4c88-9349-429e024e312b", 121 | "exec": [ 122 | "var jsonData = pm.response.json();", 123 | "pm.test(\"access_token not empty\", function () {", 124 | " pm.expect(jsonData.access_token).not.eql(undefined);", 125 | "});", 126 | "", 127 | "pm.test(\"refresh token not empty\", function () {", 128 | " pm.expect(jsonData.refresh_token).not.eql(undefined);", 129 | "});", 130 | "// set access token as environement variable", 131 | "if (jsonData.access_token !== undefined) {", 132 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 133 | "} else {", 134 | " postman.setEnvironmentVariable(\"access_token\", null);", 135 | "}", 136 | "// set refresh token as environement variable", 137 | "if (jsonData.refresh_token !== undefined) {", 138 | " postman.setEnvironmentVariable(\"refresh_token\", jsonData.refresh_token);", 139 | "} else {", 140 | " postman.setEnvironmentVariable(\"refresh_token\", null);", 141 | "}" 142 | ], 143 | "type": "text/javascript" 144 | } 145 | } 146 | ], 147 | "request": { 148 | "method": "POST", 149 | "header": [ 150 | { 151 | "key": "Content-Type", 152 | "value": "application/json" 153 | } 154 | ], 155 | "body": { 156 | "mode": "raw", 157 | "raw": "{\n \"username\" : \"jose\",\n \"password\" : \"123456\"\n}" 158 | }, 159 | "url": { 160 | "raw": "{{server_address}}/login", 161 | "host": [ 162 | "{{server_address}}" 163 | ], 164 | "path": [ 165 | "login" 166 | ] 167 | } 168 | }, 169 | "response": [] 170 | }, 171 | { 172 | "name": "logout", 173 | "event": [ 174 | { 175 | "listen": "test", 176 | "script": { 177 | "id": "dc763e9b-e6c7-4ff3-9766-637976a5c64b", 178 | "type": "text/javascript", 179 | "exec": [ 180 | "" 181 | ] 182 | } 183 | } 184 | ], 185 | "request": { 186 | "method": "POST", 187 | "header": [ 188 | { 189 | "key": "Authorization", 190 | "value": "Bearer {{access_token}}" 191 | } 192 | ], 193 | "body": { 194 | "mode": "raw", 195 | "raw": "" 196 | }, 197 | "url": { 198 | "raw": "{{server_address}}/logout", 199 | "host": [ 200 | "{{server_address}}" 201 | ], 202 | "path": [ 203 | "logout" 204 | ] 205 | } 206 | }, 207 | "response": [] 208 | }, 209 | { 210 | "name": "refresh token", 211 | "event": [ 212 | { 213 | "listen": "test", 214 | "script": { 215 | "id": "ad818ea6-8f79-436e-b756-ad878666ae9e", 216 | "type": "text/javascript", 217 | "exec": [ 218 | "var jsonData = pm.response.json();", 219 | "pm.test(\"access_token not empty\", function () {", 220 | " pm.expect(jsonData.access_token).not.eql(undefined);", 221 | "});", 222 | "// set access token as environement variable", 223 | "if (jsonData.access_token !== undefined) {", 224 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 225 | "} else {", 226 | " postman.setEnvironmentVariable(\"access_token\", null);", 227 | "}" 228 | ] 229 | } 230 | } 231 | ], 232 | "request": { 233 | "method": "POST", 234 | "header": [ 235 | { 236 | "key": "Content-Type", 237 | "value": "application/json" 238 | }, 239 | { 240 | "key": "Authorization", 241 | "value": "Bearer {{refresh_token}}" 242 | } 243 | ], 244 | "body": { 245 | "mode": "raw", 246 | "raw": "" 247 | }, 248 | "url": { 249 | "raw": "{{local_flask}}/refresh", 250 | "host": [ 251 | "{{local_flask}}" 252 | ], 253 | "path": [ 254 | "refresh" 255 | ] 256 | } 257 | }, 258 | "response": [] 259 | } 260 | ] 261 | } 262 | ] 263 | } -------------------------------------------------------------------------------- /S08/Authorizing OAuth Apps.txt: -------------------------------------------------------------------------------- 1 | https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/ -------------------------------------------------------------------------------- /S08/Flask Application context.txt: -------------------------------------------------------------------------------- 1 | https://flask.palletsprojects.com/en/1.0.x/appcontext/ -------------------------------------------------------------------------------- /S08/Flask OAuthlib Documentation.txt: -------------------------------------------------------------------------------- 1 | https://flask-oauthlib.readthedocs.io/en/latest/ -------------------------------------------------------------------------------- /S08/Flask g.txt: -------------------------------------------------------------------------------- 1 | https://flask.palletsprojects.com/en/1.0.x/api/#flask.g -------------------------------------------------------------------------------- /S08/Flask url_for.txt: -------------------------------------------------------------------------------- 1 | https://flask.palletsprojects.com/en/1.0.x/api/#flask.url_for -------------------------------------------------------------------------------- /S08/Github Developer settings, Authorizing OAuth apps.txt: -------------------------------------------------------------------------------- 1 | https://github.com/settings/developers 2 | 3 | https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/ -------------------------------------------------------------------------------- /S08/Marshmallow- Version 3 change.txt: -------------------------------------------------------------------------------- 1 | https://marshmallow.readthedocs.io/en/3.0/changelog.html -------------------------------------------------------------------------------- /S08/New Text Document.txt: -------------------------------------------------------------------------------- 1 | https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2 2 | 3 | https://oauth.net/2/ -------------------------------------------------------------------------------- /S08/end-code_ Creating a GitHub OAuth App.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/end-code_ Creating a GitHub OAuth App.zip -------------------------------------------------------------------------------- /S08/end-code_ Flask-OAuthlib.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/end-code_ Flask-OAuthlib.zip -------------------------------------------------------------------------------- /S08/end-code_Adding some error handling.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/end-code_Adding some error handling.zip -------------------------------------------------------------------------------- /S08/end-code_Finishing our GithubAuthorize resource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/end-code_Finishing our GithubAuthorize resource.zip -------------------------------------------------------------------------------- /S08/end-code_Our GithubLogin resource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/end-code_Our GithubLogin resource.zip -------------------------------------------------------------------------------- /S08/end-code_Setting up our GitHub client.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/end-code_Setting up our GitHub client.zip -------------------------------------------------------------------------------- /S08/end-code_Setting user passwords.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/end-code_Setting user passwords.zip -------------------------------------------------------------------------------- /S08/end-code_Using url_for with Flask-RESTful.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/end-code_Using url_for with Flask-RESTful.zip -------------------------------------------------------------------------------- /S08/end-code_What is a tokengetter.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/end-code_What is a tokengetter.zip -------------------------------------------------------------------------------- /S08/flask-g-test-code.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/flask-g-test-code.zip -------------------------------------------------------------------------------- /S08/start-code_ Creating a GitHub OAuth App.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/start-code_ Creating a GitHub OAuth App.zip -------------------------------------------------------------------------------- /S08/start-code_ Flask-OAuthlib.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/start-code_ Flask-OAuthlib.zip -------------------------------------------------------------------------------- /S08/start-code_Adding some error handling.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/start-code_Adding some error handling.zip -------------------------------------------------------------------------------- /S08/start-code_Finishing our GithubAuthorize resource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/start-code_Finishing our GithubAuthorize resource.zip -------------------------------------------------------------------------------- /S08/start-code_Our GithubLogin resource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/start-code_Our GithubLogin resource.zip -------------------------------------------------------------------------------- /S08/start-code_Setting up our GitHub client.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/start-code_Setting up our GitHub client.zip -------------------------------------------------------------------------------- /S08/start-code_Setting user passwords.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/start-code_Setting user passwords.zip -------------------------------------------------------------------------------- /S08/start-code_Using url_for with Flask-RESTful.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/start-code_Using url_for with Flask-RESTful.zip -------------------------------------------------------------------------------- /S08/start-code_What is a tokengetter.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/start-code_What is a tokengetter.zip -------------------------------------------------------------------------------- /S08/start-code_What's in our starter code.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S08/start-code_What's in our starter code.zip -------------------------------------------------------------------------------- /S09/ARAC-Section09-Payments.postman-collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "fc88d978-0397-401e-852a-f582b0fae119", 4 | "name": "ARAC-Section09-Payments", 5 | "description": "This collection contains the requests for the section 01 code of the Advanced REST API Course.", 6 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 7 | }, 8 | "item": [ 9 | { 10 | "name": "users", 11 | "item": [ 12 | { 13 | "name": "register a new user", 14 | "request": { 15 | "method": "POST", 16 | "header": [ 17 | { 18 | "key": "Content-Type", 19 | "value": "application/json" 20 | } 21 | ], 22 | "body": { 23 | "mode": "raw", 24 | "raw": "{\n \"username\": \"jose\",\n \"password\": \"1234\"\n}" 25 | }, 26 | "url": { 27 | "raw": "{{server_address}}/register", 28 | "host": [ 29 | "{{server_address}}" 30 | ], 31 | "path": [ 32 | "register" 33 | ] 34 | } 35 | }, 36 | "response": [] 37 | }, 38 | { 39 | "name": "get user by id", 40 | "request": { 41 | "method": "GET", 42 | "header": [], 43 | "body": { 44 | "mode": "raw", 45 | "raw": "{\n \"username\": \"jose\",\n \"password\": \"1234\"\n}" 46 | }, 47 | "url": { 48 | "raw": "{{server_address}}/user/1", 49 | "host": [ 50 | "{{server_address}}" 51 | ], 52 | "path": [ 53 | "user", 54 | "1" 55 | ] 56 | } 57 | }, 58 | "response": [] 59 | }, 60 | { 61 | "name": "delete user by id", 62 | "request": { 63 | "method": "DELETE", 64 | "header": [], 65 | "body": { 66 | "mode": "raw", 67 | "raw": "{\n \"username\": \"jose\",\n \"password\": \"1234\"\n}" 68 | }, 69 | "url": { 70 | "raw": "{{server_address}}/user/2", 71 | "host": [ 72 | "{{server_address}}" 73 | ], 74 | "path": [ 75 | "user", 76 | "2" 77 | ] 78 | } 79 | }, 80 | "response": [] 81 | }, 82 | { 83 | "name": "login", 84 | "event": [ 85 | { 86 | "listen": "test", 87 | "script": { 88 | "id": "8c0c0ed6-c206-4c88-9349-429e024e312b", 89 | "type": "text/javascript", 90 | "exec": [ 91 | "var jsonData = pm.response.json();", 92 | "pm.test(\"access_token not empty\", function () {", 93 | " pm.expect(jsonData.access_token).not.eql(undefined);", 94 | "});", 95 | "", 96 | "pm.test(\"refresh token not empty\", function () {", 97 | " pm.expect(jsonData.refresh_token).not.eql(undefined);", 98 | "});", 99 | "// set access token as environement variable", 100 | "if (jsonData.access_token !== undefined) {", 101 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 102 | "} else {", 103 | " postman.setEnvironmentVariable(\"access_token\", null);", 104 | "}", 105 | "// set refresh token as environement variable", 106 | "if (jsonData.refresh_token !== undefined) {", 107 | " postman.setEnvironmentVariable(\"refresh_token\", jsonData.refresh_token);", 108 | "} else {", 109 | " postman.setEnvironmentVariable(\"refresh_token\", null);", 110 | "}" 111 | ] 112 | } 113 | } 114 | ], 115 | "request": { 116 | "method": "POST", 117 | "header": [ 118 | { 119 | "key": "Content-Type", 120 | "value": "application/json" 121 | } 122 | ], 123 | "body": { 124 | "mode": "raw", 125 | "raw": "{\n \"username\" : \"jose\",\n \"password\" : \"1234\"\n}" 126 | }, 127 | "url": { 128 | "raw": "{{server_address}}/login", 129 | "host": [ 130 | "{{server_address}}" 131 | ], 132 | "path": [ 133 | "login" 134 | ] 135 | } 136 | }, 137 | "response": [] 138 | }, 139 | { 140 | "name": "logout", 141 | "event": [ 142 | { 143 | "listen": "test", 144 | "script": { 145 | "id": "dc763e9b-e6c7-4ff3-9766-637976a5c64b", 146 | "type": "text/javascript", 147 | "exec": [ 148 | "" 149 | ] 150 | } 151 | } 152 | ], 153 | "request": { 154 | "method": "POST", 155 | "header": [ 156 | { 157 | "key": "Authorization", 158 | "value": "Bearer {{access_token}}" 159 | } 160 | ], 161 | "body": { 162 | "mode": "raw", 163 | "raw": "" 164 | }, 165 | "url": { 166 | "raw": "{{server_address}}/logout", 167 | "host": [ 168 | "{{server_address}}" 169 | ], 170 | "path": [ 171 | "logout" 172 | ] 173 | } 174 | }, 175 | "response": [] 176 | }, 177 | { 178 | "name": "refresh token", 179 | "event": [ 180 | { 181 | "listen": "test", 182 | "script": { 183 | "id": "ad818ea6-8f79-436e-b756-ad878666ae9e", 184 | "type": "text/javascript", 185 | "exec": [ 186 | "var jsonData = pm.response.json();", 187 | "pm.test(\"access_token not empty\", function () {", 188 | " pm.expect(jsonData.access_token).not.eql(undefined);", 189 | "});", 190 | "// set access token as environement variable", 191 | "if (jsonData.access_token !== undefined) {", 192 | " postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);", 193 | "} else {", 194 | " postman.setEnvironmentVariable(\"access_token\", null);", 195 | "}" 196 | ] 197 | } 198 | } 199 | ], 200 | "request": { 201 | "method": "POST", 202 | "header": [ 203 | { 204 | "key": "Content-Type", 205 | "value": "application/json" 206 | }, 207 | { 208 | "key": "Authorization", 209 | "value": "Bearer {{refresh_token}}" 210 | } 211 | ], 212 | "body": { 213 | "mode": "raw", 214 | "raw": "" 215 | }, 216 | "url": { 217 | "raw": "{{local_flask}}/refresh", 218 | "host": [ 219 | "{{local_flask}}" 220 | ], 221 | "path": [ 222 | "refresh" 223 | ] 224 | } 225 | }, 226 | "response": [] 227 | } 228 | ] 229 | }, 230 | { 231 | "name": "items", 232 | "item": [ 233 | { 234 | "name": "get item/name", 235 | "request": { 236 | "method": "GET", 237 | "header": [], 238 | "body": {}, 239 | "url": { 240 | "raw": "{{server_address}}/item/chair", 241 | "host": [ 242 | "{{server_address}}" 243 | ], 244 | "path": [ 245 | "item", 246 | "chair" 247 | ] 248 | } 249 | }, 250 | "response": [] 251 | }, 252 | { 253 | "name": "post item/name", 254 | "request": { 255 | "method": "POST", 256 | "header": [ 257 | { 258 | "key": "Authorization", 259 | "value": "Bearer {{access_token}}" 260 | }, 261 | { 262 | "key": "Content-Type", 263 | "value": "application/json" 264 | } 265 | ], 266 | "body": { 267 | "mode": "raw", 268 | "raw": "{\n \"price\": 12.99,\n \"store_id\": 1\n}" 269 | }, 270 | "url": { 271 | "raw": "{{server_address}}/item/chair", 272 | "host": [ 273 | "{{server_address}}" 274 | ], 275 | "path": [ 276 | "item", 277 | "chair" 278 | ] 279 | } 280 | }, 281 | "response": [] 282 | }, 283 | { 284 | "name": "put item/name", 285 | "request": { 286 | "method": "PUT", 287 | "header": [ 288 | { 289 | "key": "Content-Type", 290 | "value": "application/json" 291 | } 292 | ], 293 | "body": { 294 | "mode": "raw", 295 | "raw": "{\n \"price\": 20.99,\n \"store_id\": 1\n}" 296 | }, 297 | "url": { 298 | "raw": "{{server_address}}/item/chair", 299 | "host": [ 300 | "{{server_address}}" 301 | ], 302 | "path": [ 303 | "item", 304 | "chair" 305 | ] 306 | } 307 | }, 308 | "response": [] 309 | }, 310 | { 311 | "name": "delete item by name", 312 | "request": { 313 | "method": "DELETE", 314 | "header": [ 315 | { 316 | "key": "Authorization", 317 | "value": "Bearer {{access_token}}" 318 | }, 319 | { 320 | "key": "Content-Type", 321 | "value": "application/json" 322 | } 323 | ], 324 | "body": { 325 | "mode": "raw", 326 | "raw": "" 327 | }, 328 | "url": { 329 | "raw": "{{server_address}}/item/chair", 330 | "host": [ 331 | "{{server_address}}" 332 | ], 333 | "path": [ 334 | "item", 335 | "chair" 336 | ] 337 | } 338 | }, 339 | "response": [] 340 | }, 341 | { 342 | "name": "get all items", 343 | "request": { 344 | "method": "GET", 345 | "header": [], 346 | "body": { 347 | "mode": "raw", 348 | "raw": "{\n \"username\" : \"cristiano\",\n \"password\" : \"12345678\"\n}" 349 | }, 350 | "url": { 351 | "raw": "{{server_address}}/items", 352 | "host": [ 353 | "{{server_address}}" 354 | ], 355 | "path": [ 356 | "items" 357 | ] 358 | } 359 | }, 360 | "response": [] 361 | } 362 | ] 363 | }, 364 | { 365 | "name": "stores", 366 | "item": [ 367 | { 368 | "name": "create a new store", 369 | "request": { 370 | "method": "POST", 371 | "header": [], 372 | "body": {}, 373 | "url": { 374 | "raw": "{{server_address}}/store/My Wonderful Store", 375 | "host": [ 376 | "{{server_address}}" 377 | ], 378 | "path": [ 379 | "store", 380 | "My Wonderful Store" 381 | ] 382 | } 383 | }, 384 | "response": [] 385 | }, 386 | { 387 | "name": "get store by name", 388 | "request": { 389 | "method": "GET", 390 | "header": [], 391 | "body": {}, 392 | "url": { 393 | "raw": "{{server_address}}/store/My Wonderful Store", 394 | "host": [ 395 | "{{server_address}}" 396 | ], 397 | "path": [ 398 | "store", 399 | "My Wonderful Store" 400 | ] 401 | } 402 | }, 403 | "response": [] 404 | }, 405 | { 406 | "name": "delete a new store by name", 407 | "request": { 408 | "method": "DELETE", 409 | "header": [], 410 | "body": {}, 411 | "url": { 412 | "raw": "{{server_address}}/store/My Wonderful Store", 413 | "host": [ 414 | "{{server_address}}" 415 | ], 416 | "path": [ 417 | "store", 418 | "My Wonderful Store" 419 | ] 420 | } 421 | }, 422 | "response": [] 423 | }, 424 | { 425 | "name": "get all stores", 426 | "request": { 427 | "method": "GET", 428 | "header": [], 429 | "body": {}, 430 | "url": { 431 | "raw": "{{server_address}}/stores", 432 | "host": [ 433 | "{{server_address}}" 434 | ], 435 | "path": [ 436 | "stores" 437 | ] 438 | } 439 | }, 440 | "response": [] 441 | } 442 | ] 443 | }, 444 | { 445 | "name": "orders", 446 | "item": [ 447 | { 448 | "name": "place new order", 449 | "request": { 450 | "method": "POST", 451 | "header": [ 452 | { 453 | "key": "Authorization", 454 | "value": "Bearer {{access_token}}", 455 | "type": "text", 456 | "disabled": true 457 | }, 458 | { 459 | "key": "Content-Type", 460 | "name": "Content-Type", 461 | "value": "application/json", 462 | "type": "text" 463 | } 464 | ], 465 | "body": { 466 | "mode": "raw", 467 | "raw": "{\n\t\"token\": \"tok_1DRkXcAIihGGMS6NVbJiDgig\",\n\t\"item_ids\": [1, 1]\n}" 468 | }, 469 | "url": { 470 | "raw": "{{url}}/order", 471 | "host": [ 472 | "{{url}}" 473 | ], 474 | "path": [ 475 | "order" 476 | ] 477 | } 478 | }, 479 | "response": [] 480 | }, 481 | { 482 | "name": "get all orders", 483 | "request": { 484 | "method": "GET", 485 | "header": [], 486 | "body": { 487 | "mode": "raw", 488 | "raw": "" 489 | }, 490 | "url": { 491 | "raw": "{{url}}/order", 492 | "host": [ 493 | "{{url}}" 494 | ], 495 | "path": [ 496 | "order" 497 | ] 498 | } 499 | }, 500 | "response": [] 501 | } 502 | ] 503 | } 504 | ] 505 | } -------------------------------------------------------------------------------- /S09/New Text Document.txt: -------------------------------------------------------------------------------- 1 | https://dashboard.stripe.com/login?redirect=%2Faccount%2Fapikeys -------------------------------------------------------------------------------- /S09/SQLAlchemy Many to many relationships.txt: -------------------------------------------------------------------------------- 1 | https://docs.sqlalchemy.org/en/13/orm/basic_relationships.html#many-to-many -------------------------------------------------------------------------------- /S09/SQLAlchemy_Assossiation object.txt: -------------------------------------------------------------------------------- 1 | https://docs.sqlalchemy.org/en/13/orm/basic_relationships.html#association-object -------------------------------------------------------------------------------- /S09/SQLAlchemy_backref.txt: -------------------------------------------------------------------------------- 1 | https://stackoverflow.com/questions/39869793/when-do-i-need-to-use-sqlalchemy-back-populates/39870250#39870250 -------------------------------------------------------------------------------- /S09/Stripe API Keys.txt: -------------------------------------------------------------------------------- 1 | https://dashboard.stripe.com/login?redirect=%2Faccount%2Fapikeys -------------------------------------------------------------------------------- /S09/Stripe Card Payments for Quick start.txt: -------------------------------------------------------------------------------- 1 | https://stripe.com/docs/payments#collecting-payment-information -------------------------------------------------------------------------------- /S09/Stripe_Card Payments Quickstart.txt: -------------------------------------------------------------------------------- 1 | https://stripe.com/docs/payments#collecting-payment-information -------------------------------------------------------------------------------- /S09/end-code_ Creating our OrderModel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/end-code_ Creating our OrderModel.zip -------------------------------------------------------------------------------- /S09/end-code_After payment receiving order data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/end-code_After payment receiving order data.zip -------------------------------------------------------------------------------- /S09/end-code_Calculating the amount and description.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/end-code_Calculating the amount and description.zip -------------------------------------------------------------------------------- /S09/end-code_Charging orders with Stripe.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/end-code_Charging orders with Stripe.zip -------------------------------------------------------------------------------- /S09/end-code_Creating a way to view existing orders.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/end-code_Creating a way to view existing orders.zip -------------------------------------------------------------------------------- /S09/end-code_Many-to-many relationships with SQLAlchemy.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/end-code_Many-to-many relationships with SQLAlchemy.zip -------------------------------------------------------------------------------- /S09/end-code_Using the Association Object in our Resourcee.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/end-code_Using the Association Object in our Resourcee.zip -------------------------------------------------------------------------------- /S09/end-code_When things go wrong error handling in Stripe.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/end-code_When things go wrong error handling in Stripe.zip -------------------------------------------------------------------------------- /S09/order.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | from flask import request 3 | from flask_restful import Resource 4 | 5 | from stripe import error 6 | from libs.strings import gettext 7 | from models.item import ItemModel 8 | from models.order import OrderModel, ItemsInOrder 9 | from schemas.order import OrderSchema 10 | 11 | order_schema = OrderSchema() 12 | 13 | 14 | class Order(Resource): 15 | @classmethod 16 | def get(cls): 17 | return order_schema.dump(OrderModel.find_all(), many=True), 200 18 | 19 | @classmethod 20 | def post(cls): 21 | """ 22 | Expect a token and a list of item ids from the request body. 23 | Construct an order and talk to the Strip API to make a charge. 24 | """ 25 | data = request.get_json() # token + list of item ids [1, 2, 3, 5, 5, 5] 26 | items = [] 27 | item_id_quantities = Counter(data["item_ids"]) 28 | 29 | # Iterate over items and retrieve them from the database 30 | for _id, count in item_id_quantities.most_common(): 31 | item = ItemModel.find_by_id(_id) 32 | if not item: 33 | return {"message": gettext("order_item_by_id_not_found").format(_id)}, 404 34 | 35 | items.append(ItemsInOrder(item_id=_id, quantity=count)) 36 | 37 | order = OrderModel(items=items, status="pending") 38 | order.save_to_db() # this does not submit to Stripe 39 | 40 | try: 41 | order.set_status("failed") # assume the order would fail until it's completed 42 | order.charge_with_stripe(data["token"]) 43 | order.set_status("complete") # charge succeeded 44 | return order_schema.dump(order), 200 45 | # the following error handling is advised by Stripe, although the handling implementations are identical, 46 | # we choose to specify them separately just to give the students a better idea what we can expect 47 | except error.CardError as e: 48 | # Since it's a decline, stripe.error.CardError will be caught 49 | return e.json_body, e.http_status 50 | except error.RateLimitError as e: 51 | # Too many requests made to the API too quickly 52 | return e.json_body, e.http_status 53 | except error.InvalidRequestError as e: 54 | # Invalid parameters were supplied to Stripe's API 55 | return e.json_body, e.http_status 56 | except error.AuthenticationError as e: 57 | # Authentication with Stripe's API failed 58 | # (maybe you changed API keys recently) 59 | return e.json_body, e.http_status 60 | except error.APIConnectionError as e: 61 | # Network communication with Stripe failed 62 | return e.json_body, e.http_status 63 | except error.StripeError as e: 64 | # Display a very generic error to the user, and maybe send 65 | # yourself an email 66 | return e.json_body, e.http_status 67 | except Exception as e: 68 | # Something else happened, completely unrelated to Stripe 69 | print(e) 70 | return {"message": gettext("order_error")}, 500 71 | -------------------------------------------------------------------------------- /S09/start-code_ Creating our OrderModel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/start-code_ Creating our OrderModel.zip -------------------------------------------------------------------------------- /S09/start-code_After payment receiving order data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/start-code_After payment receiving order data.zip -------------------------------------------------------------------------------- /S09/start-code_Calculating the amount and description.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/start-code_Calculating the amount and description.zip -------------------------------------------------------------------------------- /S09/start-code_Charging orders with Stripe.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/start-code_Charging orders with Stripe.zip -------------------------------------------------------------------------------- /S09/start-code_Creating a way to view existing orders.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/start-code_Creating a way to view existing orders.zip -------------------------------------------------------------------------------- /S09/start-code_Many-to-many relationships with SQLAlchemy.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/start-code_Many-to-many relationships with SQLAlchemy.zip -------------------------------------------------------------------------------- /S09/start-code_Using the Association Object in our Resourcee.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/start-code_Using the Association Object in our Resourcee.zip -------------------------------------------------------------------------------- /S09/start-code_When things go wrong error handling in Stripe.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-REST-APIs-with-Flask-and-Python/320dc746dc81d1a56a322b168c3742b6711d0c96/S09/start-code_When things go wrong error handling in Stripe.zip --------------------------------------------------------------------------------