├── Chapter01 ├── .gitkeep └── server.py ├── Chapter02 ├── .gitkeep └── booktracker │ ├── alt1 │ ├── myapp │ │ ├── __init__.py │ │ ├── bootstrap.py │ │ ├── server.py │ │ └── listener.py │ └── run.py │ ├── src │ ├── blueprints │ │ ├── __init__.py │ │ ├── v1 │ │ │ ├── __init__.py │ │ │ ├── author │ │ │ │ ├── __init__.py │ │ │ │ └── view.py │ │ │ └── book │ │ │ │ ├── __init__.py │ │ │ │ └── view.py │ │ └── v2 │ │ │ ├── __init__.py │ │ │ ├── book │ │ │ ├── __init__.py │ │ │ └── view.py │ │ │ └── group.py │ ├── server.py │ └── utilities │ │ ├── app_factory.py │ │ └── autodiscovery.py │ ├── .pdm.toml │ └── pyproject.toml ├── Chapter04 ├── .gitkeep └── requeststream │ ├── somefile.txt │ ├── client.py │ ├── upload.py │ └── server.py ├── Chapter05 ├── .gitkeep ├── html │ ├── templates │ │ └── index.html │ └── server.py ├── websockets │ ├── index.html │ └── server.py └── sse │ ├── index.html │ └── server.py ├── Chapter06 ├── .gitkeep ├── inprocess-queue │ ├── job │ │ ├── __init__.py │ │ ├── operations │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── hello.py │ │ │ └── registry.py │ │ ├── worker.py │ │ ├── blueprint.py │ │ ├── model.py │ │ ├── startup.py │ │ ├── view.py │ │ └── job.py │ ├── server.py │ └── db ├── request-middleware │ └── server.py └── response-middleware │ └── server.py ├── Chapter07 ├── .gitkeep ├── accesstoken │ └── auth │ │ ├── __init__.py │ │ ├── refresh_token.py │ │ ├── user.py │ │ ├── cookie.py │ │ ├── decorator.py │ │ └── access_token.py ├── corsissue │ ├── server2 │ │ ├── favicon.ico │ │ └── index.html │ └── server1 │ │ └── server.py ├── corsresponse │ ├── access-control-expose-headers │ │ ├── test.html │ │ └── server.py │ ├── access-control-allow-methods │ │ └── server.py │ ├── server2.py │ └── server.py └── apitoken │ └── server.py ├── Chapter08 ├── .gitkeep ├── paas │ ├── requirements.txt │ ├── Procfile │ └── server.py └── k8s │ ├── Dockerfile │ ├── issuer.yml │ ├── server.py │ ├── app.yml │ ├── load-balancer.yml │ └── ingress.yml ├── Chapter09 ├── .gitkeep ├── loggingapp0 │ ├── Dockerfile │ ├── tests │ │ └── .gitkeep │ └── myapp │ │ ├── common │ │ ├── __init__.py │ │ └── log.py │ │ └── server.py ├── loggingapp1 │ ├── Dockerfile │ ├── tests │ │ └── .gitkeep │ └── myapp │ │ ├── common │ │ ├── __init__.py │ │ └── log.py │ │ └── server.py ├── testing2 │ ├── __init__.py │ ├── path │ │ ├── __init__.py │ │ └── to │ │ │ ├── __init__.py │ │ │ └── some_blueprint.py │ └── tests │ │ ├── __init__.py │ │ └── conftest.py ├── testing3 │ ├── __init__.py │ ├── path │ │ ├── __init__.py │ │ └── to │ │ │ ├── __init__.py │ │ │ ├── some_db_connection.py │ │ │ ├── some_startup.py │ │ │ ├── some_registration_service.py │ │ │ └── some_blueprint.py │ └── tests │ │ ├── __init__.py │ │ ├── conftest.py │ │ └── test_some_blueprint.py ├── testing4 │ ├── __init__.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_2.py │ │ ├── conftest.py │ │ └── test_1.py │ └── server.py ├── tracing │ └── myapp │ │ ├── __init__.py │ │ ├── common │ │ └── __init__.py │ │ ├── middleware │ │ └── request_context.py │ │ └── server.py ├── hikingapp │ ├── application │ │ ├── hiking │ │ │ ├── __init__.py │ │ │ ├── common │ │ │ │ ├── __init__.py │ │ │ │ ├── dao │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── hydrator.py │ │ │ │ │ ├── decorator.py │ │ │ │ │ └── executor.py │ │ │ │ ├── base_model.py │ │ │ │ └── cache.py │ │ │ ├── worker │ │ │ │ ├── __init__.py │ │ │ │ ├── redis.py │ │ │ │ └── postgres.py │ │ │ ├── blueprints │ │ │ │ ├── __init__.py │ │ │ │ ├── hikes │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── queries │ │ │ │ │ │ ├── get_hikes_by_user.sql │ │ │ │ │ │ └── get_hikes_by_user_by_name.sql │ │ │ │ │ ├── models.py │ │ │ │ │ ├── hydrator.py │ │ │ │ │ └── executor.py │ │ │ │ ├── slow │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── view.py │ │ │ │ ├── trails │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── queries │ │ │ │ │ │ ├── get_all_trails.sql │ │ │ │ │ │ └── get_trail_by_name.sql │ │ │ │ │ ├── models.py │ │ │ │ │ ├── executor.py │ │ │ │ │ └── view.py │ │ │ │ ├── users │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── queries │ │ │ │ │ │ ├── get_all_users.sql │ │ │ │ │ │ └── get_user_by_name.sql │ │ │ │ │ ├── models.py │ │ │ │ │ ├── executor.py │ │ │ │ │ └── view.py │ │ │ │ └── view.py │ │ │ ├── middleware │ │ │ │ └── request_context.py │ │ │ └── server.py │ │ ├── requirements.txt │ │ └── Dockerfile │ ├── postgres │ │ ├── Dockerfile │ │ └── initial.sql │ ├── README.md │ └── docker-compose.yml ├── testing0 │ ├── test_sample.py │ ├── server.py │ └── conftest.py └── testing1 │ ├── server.py │ ├── conftest.py │ └── test_sample.py ├── Chapter10 ├── .gitkeep ├── pwa │ └── my-svelte-project │ │ ├── src │ │ ├── foo │ │ ├── dummy.txt │ │ ├── main.js │ │ └── App.svelte │ │ ├── .gitignore │ │ ├── public │ │ ├── favicon.png │ │ ├── index.html │ │ └── global.css │ │ ├── package.json │ │ └── rollup.config.js ├── graphql │ ├── application │ │ ├── world │ │ │ ├── __init__.py │ │ │ ├── blueprints │ │ │ │ ├── __init__.py │ │ │ │ ├── cities │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── queries │ │ │ │ │ │ ├── get_city_by_id.sql │ │ │ │ │ │ ├── get_all_cities.sql │ │ │ │ │ │ ├── get_city_by_name.sql │ │ │ │ │ │ └── get_cities_by_country_code.sql │ │ │ │ │ ├── schema.gql │ │ │ │ │ ├── models.py │ │ │ │ │ ├── executor.py │ │ │ │ │ └── integrator.py │ │ │ │ ├── countries │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── queries │ │ │ │ │ │ ├── get_all_countries.sql │ │ │ │ │ │ └── get_country_by_name.sql │ │ │ │ │ ├── schema.gql │ │ │ │ │ ├── models.py │ │ │ │ │ └── executor.py │ │ │ │ ├── graphql │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── query.py │ │ │ │ │ └── view.py │ │ │ │ ├── languages │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── schema.gql │ │ │ │ │ ├── queries │ │ │ │ │ │ └── get_by_country_code.sql │ │ │ │ │ ├── integrator.py │ │ │ │ │ ├── models.py │ │ │ │ │ └── executor.py │ │ │ │ └── view.py │ │ │ ├── common │ │ │ │ ├── __init__.py │ │ │ │ ├── dao │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── hydrator.py │ │ │ │ │ └── executor.py │ │ │ │ └── base_model.py │ │ │ ├── middleware │ │ │ │ ├── __init__.py │ │ │ │ └── request_context.py │ │ │ ├── worker │ │ │ │ ├── __init__.py │ │ │ │ └── postgres.py │ │ │ └── server.py │ │ ├── requirements.txt │ │ └── Dockerfile │ └── docker-compose.yml ├── httpredirect │ └── wadsworth │ │ ├── __init__.py │ │ ├── applications │ │ ├── __init__.py │ │ ├── server.py │ │ └── redirect.py │ │ ├── blueprints │ │ ├── __init__.py │ │ ├── hello │ │ │ ├── __init__.py │ │ │ └── view.py │ │ ├── info │ │ │ ├── __init__.py │ │ │ └── view.py │ │ ├── redirect │ │ │ ├── __init__.py │ │ │ └── view.py │ │ └── view.py │ │ └── certs │ │ ├── cert.pem │ │ └── key.pem ├── wsfeed │ ├── application │ │ ├── feeder │ │ │ ├── __init__.py │ │ │ ├── blueprints │ │ │ │ ├── __init__.py │ │ │ │ ├── feed │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── client.py │ │ │ │ │ └── view.py │ │ │ │ └── view.py │ │ │ ├── common │ │ │ │ └── __init__.py │ │ │ ├── middleware │ │ │ │ ├── __init__.py │ │ │ │ └── request_context.py │ │ │ ├── worker │ │ │ │ ├── __init__.py │ │ │ │ └── redis.py │ │ │ └── server.py │ │ ├── requirements.txt │ │ └── Dockerfile │ ├── README.md │ └── docker-compose.yml └── wdsbot │ ├── from_sanic │ ├── bot.py │ └── server.py │ └── from_bot │ ├── server.py │ └── bot.py ├── Chapter11 ├── .gitkeep └── booktracker │ ├── application │ ├── booktracker │ │ ├── __init__.py │ │ ├── blueprints │ │ │ ├── __init__.py │ │ │ ├── book │ │ │ │ ├── __init__.py │ │ │ │ ├── queries │ │ │ │ │ ├── create_book_to_user.sql │ │ │ │ │ ├── get_all_series.sql │ │ │ │ │ ├── get_book_series_by_eid.sql │ │ │ │ │ ├── get_series_by_name.sql │ │ │ │ │ ├── create_book_series.sql │ │ │ │ │ ├── update_book_state.sql │ │ │ │ │ ├── create_book.sql │ │ │ │ │ ├── update_toggle_book_is_loved.sql │ │ │ │ │ ├── get_book_by_eid.sql │ │ │ │ │ ├── get_all_books.sql │ │ │ │ │ ├── get_books_by_title.sql │ │ │ │ │ ├── get_book_by_eid_for_user.sql │ │ │ │ │ └── get_all_books_for_user.sql │ │ │ │ ├── hydrator.py │ │ │ │ └── model.py │ │ │ ├── user │ │ │ │ ├── __init__.py │ │ │ │ ├── queries │ │ │ │ │ ├── get_by_eid.sql │ │ │ │ │ ├── get_by_login.sql │ │ │ │ │ └── create_user.sql │ │ │ │ ├── model.py │ │ │ │ └── executor.py │ │ │ ├── author │ │ │ │ ├── __init__.py │ │ │ │ ├── queries │ │ │ │ │ ├── create_author.sql │ │ │ │ │ ├── get_author_by_eid.sql │ │ │ │ │ ├── get_all_authors.sql │ │ │ │ │ └── get_authors_by_name.sql │ │ │ │ ├── model.py │ │ │ │ ├── executor.py │ │ │ │ └── view.py │ │ │ ├── frontend │ │ │ │ ├── __init__.py │ │ │ │ └── view.py │ │ │ └── view.py │ │ ├── common │ │ │ ├── __init__.py │ │ │ ├── dao │ │ │ │ ├── __init__.py │ │ │ │ ├── hydrator.py │ │ │ │ └── executor.py │ │ │ ├── auth │ │ │ │ ├── __init__.py │ │ │ │ ├── model.py │ │ │ │ ├── startup.py │ │ │ │ └── endpoint.py │ │ │ ├── eid.py │ │ │ ├── cookie.py │ │ │ ├── pagination.py │ │ │ └── cache.py │ │ ├── middleware │ │ │ ├── __init__.py │ │ │ └── request_context.py │ │ ├── worker │ │ │ ├── __init__.py │ │ │ ├── request.py │ │ │ ├── module.py │ │ │ ├── redis.py │ │ │ └── postgres.py │ │ └── server.py │ ├── ui │ │ ├── .prettierrc.json │ │ ├── .prettierignore │ │ ├── src │ │ │ ├── stores │ │ │ │ ├── book.js │ │ │ │ └── user.js │ │ │ ├── utils │ │ │ │ ├── time.js │ │ │ │ ├── debounce.js │ │ │ │ ├── cookie.js │ │ │ │ ├── account.js │ │ │ │ └── actions.js │ │ │ ├── main.js │ │ │ ├── layouts │ │ │ │ ├── Main.svelte │ │ │ │ ├── Footer.svelte │ │ │ │ └── Header.svelte │ │ │ ├── components │ │ │ │ ├── Reading.svelte │ │ │ │ ├── AddPyWebDev.svelte │ │ │ │ ├── Love.svelte │ │ │ │ ├── Clipboard.svelte │ │ │ │ └── BookState.svelte │ │ │ └── App.svelte │ │ └── public │ │ │ ├── favicon.png │ │ │ └── index.html │ ├── requirements.txt │ ├── Makefile │ ├── Dockerfile │ ├── package.json │ └── rollup.config.js │ ├── README.md │ ├── postgres │ ├── Dockerfile │ └── initial.sql │ └── docker-compose.yml ├── Chapter03 ├── serving-static-content-with-nginx │ ├── static │ │ └── foo.txt │ ├── docker-compose.yml │ └── nginx │ │ └── default.conf └── ip-address-pattern.py └── LICENSE /Chapter01/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter02/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter04/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter05/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter06/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter07/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter08/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter11/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/loggingapp0/Dockerfile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/loggingapp1/Dockerfile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/testing2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/testing3/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/testing4/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter07/accesstoken/auth/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/loggingapp0/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/loggingapp1/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/testing2/path/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/testing2/path/to/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/testing2/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/testing3/path/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/testing3/path/to/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/testing3/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/testing4/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/tracing/myapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter06/inprocess-queue/job/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter08/paas/requirements.txt: -------------------------------------------------------------------------------- 1 | sanic 2 | -------------------------------------------------------------------------------- /Chapter09/tracing/myapp/common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/pwa/my-svelte-project/src/foo: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter02/booktracker/alt1/myapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/blueprints/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/loggingapp0/myapp/common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/loggingapp1/myapp/common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/pwa/my-svelte-project/src/dummy.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/feeder/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/blueprints/v1/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/blueprints/v2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter06/inprocess-queue/job/operations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/blueprints/v1/author/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/blueprints/v1/book/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/blueprints/v2/book/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/worker/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/common/dao/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/middleware/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/worker/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/applications/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/blueprints/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/feeder/blueprints/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/feeder/common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/feeder/middleware/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/feeder/worker/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/common/dao/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/blueprints/hello/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/blueprints/info/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/feeder/blueprints/feed/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/hikes/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/slow/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/trails/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/users/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/cities/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/countries/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/graphql/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/languages/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/blueprints/redirect/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/requirements.txt: -------------------------------------------------------------------------------- 1 | aioredis 2 | sanic 3 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/common/dao/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/middleware/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/worker/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter02/booktracker/.pdm.toml: -------------------------------------------------------------------------------- 1 | [python] 2 | path = "/usr/bin/python" 3 | -------------------------------------------------------------------------------- /Chapter03/serving-static-content-with-nginx/static/foo.txt: -------------------------------------------------------------------------------- 1 | hello... 2 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/book/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/user/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/common/auth/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter08/paas/Procfile: -------------------------------------------------------------------------------- 1 | web: sanic server:app --host=0.0.0.0 --port=$PORT 2 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/author/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/frontend/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter04/requeststream/somefile.txt: -------------------------------------------------------------------------------- 1 | 1111222233334444555566667777888899990000 2 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4 3 | } 4 | -------------------------------------------------------------------------------- /Chapter02/booktracker/alt1/run.py: -------------------------------------------------------------------------------- 1 | from myapp.bootstrap import app 2 | 3 | 4 | app.run() 5 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/requirements.txt: -------------------------------------------------------------------------------- 1 | aioredis 2 | databases[postgresql] 3 | sanic 4 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/requirements.txt: -------------------------------------------------------------------------------- 1 | ariadne 2 | databases[postgresql] 3 | sanic 4 | -------------------------------------------------------------------------------- /Chapter10/pwa/my-svelte-project/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /public/build/ 3 | 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore artifacts: 2 | build 3 | coverage 4 | -------------------------------------------------------------------------------- /Chapter02/booktracker/alt1/myapp/bootstrap.py: -------------------------------------------------------------------------------- 1 | from .server import * # noqa 2 | from .listener import * # noqa 3 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/users/queries/get_all_users.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM users; 3 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/trails/queries/get_all_trails.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM trails; 3 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/graphql/query.py: -------------------------------------------------------------------------------- 1 | from ariadne import QueryType 2 | 3 | query = QueryType() 4 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/certs/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | SOMECERTHERE 3 | -----END CERTIFICATE----- 4 | -------------------------------------------------------------------------------- /Chapter02/booktracker/alt1/myapp/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic 2 | 3 | app = Sanic(__file__) 4 | 5 | 6 | app.route("/")(lambda x: None) 7 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/certs/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | SOMEKEYHERE 3 | -----END ENCRYPTED PRIVATE KEY----- 4 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/README.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | ``` 4 | docker-compose build 5 | ``` 6 | 7 | ``` 8 | docker-compose up 9 | ``` 10 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/cities/queries/get_city_by_id.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM city c 3 | WHERE id = :city_id; 4 | -------------------------------------------------------------------------------- /Chapter11/booktracker/README.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | ``` 4 | $ docker-compose build 5 | ``` 6 | 7 | ``` 8 | $ docker-compose up 9 | ``` 10 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/requirements.txt: -------------------------------------------------------------------------------- 1 | aioredis 2 | cryptography 3 | databases[postgresql] 4 | httpx 5 | sanic 6 | sanic-ext 7 | sanic-jwt 8 | -------------------------------------------------------------------------------- /Chapter07/corsissue/server2/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Web-Development-with-Sanic/HEAD/Chapter07/corsissue/server2/favicon.ico -------------------------------------------------------------------------------- /Chapter09/testing0/test_sample.py: -------------------------------------------------------------------------------- 1 | def test_sample(test_client): 2 | request, response = test_client.get("/") 3 | 4 | assert response.status == 200 5 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/src/stores/book.js: -------------------------------------------------------------------------------- 1 | import { writable } from "svelte/store"; 2 | 3 | const books = writable([]); 4 | export { books }; 5 | -------------------------------------------------------------------------------- /Chapter09/testing2/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from sanic import Sanic 3 | 4 | 5 | @pytest.fixture 6 | def dummy_app(): 7 | return Sanic("DummyApp") 8 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/cities/queries/get_all_cities.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM city 3 | LIMIT :limit 4 | OFFSET :offset; 5 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/cities/queries/get_city_by_name.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM city c 3 | WHERE LOWER(name) = LOWER(:name); 4 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/trails/queries/get_trail_by_name.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM trails 3 | WHERE LOWER(name) = LOWER(:name); 4 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/Makefile: -------------------------------------------------------------------------------- 1 | black: 2 | black booktracker -l 79 3 | 4 | isort: 5 | isort booktracker -l 79 --profile=black 6 | 7 | pretty: black isort 8 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/blueprints/v2/group.py: -------------------------------------------------------------------------------- 1 | from .book.view import bp as book_bp 2 | from sanic import Blueprint 3 | 4 | group = Blueprint.group(book_bp, version=2) 5 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/countries/queries/get_all_countries.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM country 3 | LIMIT :limit 4 | OFFSET :offset; 5 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/countries/queries/get_country_by_name.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM country c 3 | WHERE LOWER(name) = LOWER(:name); 4 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/book/queries/create_book_to_user.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO book_to_user (book_id, user_id) 2 | VALUES (:book_id, :user_id); 3 | -------------------------------------------------------------------------------- /Chapter02/booktracker/alt1/myapp/listener.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic 2 | 3 | app = Sanic.get_app() 4 | 5 | 6 | @app.before_server_start 7 | def _(*__): 8 | print("...") 9 | -------------------------------------------------------------------------------- /Chapter09/testing0/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic, text 2 | 3 | app = Sanic(__name__) 4 | 5 | 6 | @app.get("/") 7 | async def handler(request): 8 | return text("...") 9 | -------------------------------------------------------------------------------- /Chapter09/testing1/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic, text 2 | 3 | app = Sanic(__name__) 4 | 5 | 6 | @app.get("/") 7 | async def handler(request): 8 | return text("...") 9 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/blueprints/view.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint 2 | 3 | from .hello.view import bp as hello_bp 4 | 5 | bp = Blueprint.group(hello_bp, version=1) 6 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/feeder/blueprints/view.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint 2 | 3 | from .feed.view import bp as feed_bp 4 | 5 | bp = Blueprint.group(feed_bp, version=1) 6 | -------------------------------------------------------------------------------- /Chapter06/inprocess-queue/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic 2 | from job.blueprint import bp 3 | 4 | app = Sanic(__name__) 5 | app.config.NUM_TASK_WORKERS = 3 6 | app.blueprint(bp) 7 | -------------------------------------------------------------------------------- /Chapter09/testing1/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from server import app as application_instance 4 | 5 | 6 | @pytest.fixture 7 | def app(): 8 | return application_instance 9 | -------------------------------------------------------------------------------- /Chapter09/testing3/path/to/some_db_connection.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | 4 | class FakeDBConnection: 5 | async def execute(self, query: str, *params: Any): 6 | ... 7 | -------------------------------------------------------------------------------- /Chapter10/pwa/my-svelte-project/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Web-Development-with-Sanic/HEAD/Chapter10/pwa/my-svelte-project/public/favicon.png -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/view.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint 2 | 3 | from .graphql.view import bp as graphql_bp 4 | 5 | bp = Blueprint.group(graphql_bp, version=1) 6 | -------------------------------------------------------------------------------- /Chapter08/k8s/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM sanicframework/sanic:3.9-latest 2 | 3 | COPY . /srv 4 | WORKDIR /srv 5 | EXPOSE 7777 6 | 7 | ENTRYPOINT ["sanic", "server:app", "--port=7777", "--host=0.0.0.0"] 8 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Web-Development-with-Sanic/HEAD/Chapter11/booktracker/application/ui/public/favicon.png -------------------------------------------------------------------------------- /Chapter09/testing1/test_sample.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic 2 | 3 | 4 | def test_sample(app: Sanic): 5 | request, response = app.test_client.get("/") 6 | 7 | assert response.status == 200 8 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/languages/schema.gql: -------------------------------------------------------------------------------- 1 | type Language { 2 | countrycode: String 3 | language: String 4 | isofficial: Boolean 5 | percentage: Float 6 | } 7 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/src/utils/time.js: -------------------------------------------------------------------------------- 1 | async function sleep(seconds = 1) { 2 | await new Promise((resolve) => setTimeout(resolve, seconds * 1000)); 3 | } 4 | export { sleep }; 5 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | WORKDIR /app 4 | 5 | COPY ./requirements.txt /app/requirements.txt 6 | RUN pip install -r requirements.txt 7 | 8 | COPY ./world /app/world 9 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | WORKDIR /app 4 | 5 | COPY ./requirements.txt /app/requirements.txt 6 | RUN pip install -r requirements.txt 7 | 8 | COPY ./feeder /app/feeder 9 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/cities/queries/get_cities_by_country_code.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM city 3 | WHERE countrycode = :code 4 | LIMIT :limit 5 | OFFSET :offset; 6 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/hikes/queries/get_hikes_by_user.sql: -------------------------------------------------------------------------------- 1 | SELECT t.*, h.date 2 | FROM hikes h 3 | JOIN trails t ON h.trail_id = t.trail_id 4 | WHERE h.user_id = :user_id 5 | -------------------------------------------------------------------------------- /Chapter10/pwa/my-svelte-project/src/main.js: -------------------------------------------------------------------------------- 1 | import App from './App.svelte'; 2 | 3 | const app = new App({ 4 | target: document.body, 5 | props: { 6 | name: 'world' 7 | } 8 | }); 9 | 10 | export default app; 11 | -------------------------------------------------------------------------------- /Chapter09/testing0/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from sanic_testing.testing import SanicTestClient 3 | 4 | from server import app 5 | 6 | 7 | @pytest.fixture 8 | def test_client(): 9 | return SanicTestClient(app) 10 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/cities/schema.gql: -------------------------------------------------------------------------------- 1 | type City { 2 | id: Int 3 | name: String 4 | countrycode: String 5 | district: String 6 | population: Int 7 | languages: [Language] 8 | } 9 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/languages/queries/get_by_country_code.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | FROM countrylanguage 3 | WHERE countrycode = :country_code 4 | LIMIT :limit 5 | OFFSET :offset; 6 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/book/queries/get_all_series.sql: -------------------------------------------------------------------------------- 1 | SELECT e.eid, 2 | s.series_id, 3 | s.name 4 | FROM series s 5 | JOIN eids e ON s.ref_id = e.ref_id 6 | LIMIT :limit OFFSET :offset; 7 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/book/queries/get_book_series_by_eid.sql: -------------------------------------------------------------------------------- 1 | SELECT s.series_id, 2 | s.name, 3 | e.eid 4 | FROM series s 5 | JOIN eids e ON s.ref_id = e.ref_id 6 | WHERE e.eid = :eid; 7 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/src/main.js: -------------------------------------------------------------------------------- 1 | import App from "./App.svelte"; 2 | 3 | const app = new App({ 4 | target: document.body, 5 | props: { baseURL: "http://localhost:7777" }, 6 | }); 7 | 8 | export default app; 9 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | RUN mkdir /app 4 | WORKDIR /app 5 | 6 | COPY ./requirements.txt /app/requirements.txt 7 | RUN pip install -r requirements.txt 8 | 9 | COPY ./hiking /app/hiking 10 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/postgres/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres 2 | WORKDIR /docker-entrypoint-initdb.d 3 | ADD initial.sql /docker-entrypoint-initdb.d 4 | EXPOSE 5432 5 | CMD ["postgres", "-c", "log_statement=all", "-c", "log_destination=stderr"] 6 | -------------------------------------------------------------------------------- /Chapter11/booktracker/postgres/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres 2 | WORKDIR /docker-entrypoint-initdb.d 3 | ADD initial.sql /docker-entrypoint-initdb.d 4 | EXPOSE 5432 5 | CMD ["postgres", "-c", "log_statement=all", "-c", "log_destination=stderr"] 6 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/languages/integrator.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from world.common.dao.integrator import BaseIntegrator 4 | 5 | 6 | class LanguageIntegrator(BaseIntegrator): 7 | name = "language" 8 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/book/queries/get_series_by_name.sql: -------------------------------------------------------------------------------- 1 | SELECT e.eid, 2 | s.series_id, 3 | s.name 4 | FROM series s 5 | JOIN eids e ON s.ref_id = e.ref_id 6 | WHERE s.name % :name 7 | LIMIT :limit OFFSET :offset; 8 | -------------------------------------------------------------------------------- /Chapter06/inprocess-queue/job/operations/base.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from abc import ABC, abstractmethod 4 | 5 | 6 | class Operation(ABC): 7 | @abstractmethod 8 | async def run(self, **_): 9 | raise NotImplementedError 10 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/src/utils/debounce.js: -------------------------------------------------------------------------------- 1 | export default function debounce(func, timeout = 300){ 2 | let timer; 3 | return (...args) => { 4 | clearTimeout(timer); 5 | timer = setTimeout(() => { func.apply(this, args); }, timeout); 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /Chapter09/testing3/path/to/some_startup.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic 2 | from .some_db_connection import FakeDBConnection 3 | 4 | app = Sanic.get_app() 5 | 6 | 7 | @app.before_server_start 8 | async def setup_db_connection(app, _): 9 | app.ctx.db = FakeDBConnection() 10 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/user/queries/get_by_eid.sql: -------------------------------------------------------------------------------- 1 | SELECT e.eid, 2 | u.user_id, 3 | u.login, 4 | u.name, 5 | u.avatar, 6 | u.profile 7 | FROM users u 8 | JOIN eids e ON u.ref_id = e.ref_id 9 | WHERE e.eid = :eid; 10 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/hikes/queries/get_hikes_by_user_by_name.sql: -------------------------------------------------------------------------------- 1 | SELECT t.*, h.date 2 | FROM hikes h 3 | JOIN trails t ON h.trail_id = t.trail_id 4 | JOIN users u ON h.user_id = u.user_id 5 | WHERE LOWER(u.name) = LOWER(:name); 6 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/view.py: -------------------------------------------------------------------------------- 1 | from .users.view import bp as users_bp 2 | from .trails.view import bp as trails_bp 3 | from .slow.view import bp as slow_bp 4 | from sanic import Blueprint 5 | 6 | bp = Blueprint.group(users_bp, trails_bp, slow_bp, version=1) 7 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/user/queries/get_by_login.sql: -------------------------------------------------------------------------------- 1 | SELECT e.eid, 2 | u.user_id, 3 | u.login, 4 | u.name, 5 | u.avatar, 6 | u.profile 7 | FROM users u 8 | JOIN eids e ON u.ref_id = e.ref_id 9 | WHERE u.login = :login; 10 | -------------------------------------------------------------------------------- /Chapter03/serving-static-content-with-nginx/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | client: 5 | image: nginx:alpine 6 | ports: 7 | - 8888:80 8 | volumes: 9 | - ./nginx/default.conf:/etc/nginx/conf.d/default.conf 10 | - ./static:/var/www 11 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/trails/models.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from hiking.common.base_model import BaseModel 3 | from decimal import Decimal 4 | 5 | 6 | @dataclass 7 | class Trail(BaseModel): 8 | trail_id: int 9 | name: str 10 | distance: Decimal 11 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/users/models.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass, field 2 | from hiking.common.base_model import BaseModel 3 | 4 | 5 | @dataclass 6 | class User(BaseModel): 7 | user_id: int 8 | name: str 9 | total_distance_hiked: float = field(default=0) 10 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/blueprints/v1/author/view.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint, Request, HTTPResponse, json 2 | 3 | bp = Blueprint("Author", url_prefix="/author") 4 | 5 | 6 | @bp.get("/") 7 | async def get_all_books(request: Request) -> HTTPResponse: 8 | return json(["Mark Twain", "Robert Louis Stevenson"]) 9 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/blueprints/v1/book/view.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint, Request, HTTPResponse, json 2 | 3 | bp = Blueprint("Book", url_prefix="/book") 4 | 5 | 6 | @bp.get("/") 7 | async def get_all_books(request: Request) -> HTTPResponse: 8 | return json(["The Adventures of Tom Sawyer", "Treasure Island"]) 9 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/cities/models.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from world.common.base_model import BaseModel 4 | 5 | 6 | @dataclass 7 | class City(BaseModel): 8 | id: int 9 | name: str 10 | countrycode: str 11 | district: str 12 | population: int 13 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/languages/models.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from world.common.base_model import BaseModel 4 | 5 | 6 | @dataclass 7 | class Language(BaseModel): 8 | countrycode: str 9 | language: str 10 | isofficial: bool 11 | percentage: float 12 | -------------------------------------------------------------------------------- /Chapter09/testing4/tests/test_2.py: -------------------------------------------------------------------------------- 1 | def test_reusable_fixture(test_client): 2 | _, response = test_client.get("/") 3 | assert response.json == 3 4 | 5 | _, response = test_client.get("/") 6 | assert response.json == 4 7 | 8 | _, response = test_client.get("/") 9 | assert response.json == 5 10 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/worker/request.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from sanic import Request 4 | 5 | from booktracker.common.eid import generate 6 | 7 | 8 | class BooktrackerRequest(Request): 9 | @classmethod 10 | def generate_id(*_: Any) -> str: 11 | return generate() 12 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/blueprints/v2/book/view.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint, Request, HTTPResponse, json 2 | 3 | bp = Blueprint("Bookv2", url_prefix="/book") 4 | 5 | 6 | @bp.get("/") 7 | async def get_all_books(request: Request) -> HTTPResponse: 8 | return json({"books": ["The Adventures of Tom Sawyer", "Treasure Island"]}) 9 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/common/auth/model.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class GitHubAuthCode: 6 | code: str 7 | 8 | 9 | @dataclass 10 | class RefreshTokenKey: 11 | eid: str 12 | 13 | def __str__(self) -> str: 14 | return f"refresh_token:{self.eid}" 15 | -------------------------------------------------------------------------------- /Chapter03/ip-address-pattern.py: -------------------------------------------------------------------------------- 1 | IP_ADDRESS_PATTERN = ( 2 | r"(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}" 3 | r"(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" 4 | ) 5 | 6 | 7 | @app.get(f"/") 8 | async def get_ip_details(request: Request, ip: str): 9 | return text(f"type={type(ip)} {ip=}") 10 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/hikes/models.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from hiking.common.base_model import BaseModel 3 | from datetime import date 4 | 5 | from hiking.blueprints.trails.models import Trail 6 | 7 | 8 | @dataclass 9 | class Hike(BaseModel): 10 | trail: Trail 11 | date: date 12 | -------------------------------------------------------------------------------- /Chapter04/requeststream/client.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | import httpx 4 | 5 | 6 | def gen(): 7 | for _ in range(1): 8 | print("waiting") 9 | time.sleep(1) 10 | yield b'{"foo": "bar"}' 11 | 12 | 13 | r = httpx.post("http://localhost:7777/transaction", data=gen()) 14 | print(r.status_code) 15 | print(r.content) 16 | -------------------------------------------------------------------------------- /Chapter06/inprocess-queue/job/operations/hello.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from .base import Operation 3 | 4 | 5 | class Hello(Operation): 6 | async def run(self, name="world"): 7 | message = f"Hello, {name}" 8 | print(message) 9 | await asyncio.sleep(10) 10 | print("Done.") 11 | return message 12 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/user/model.py: -------------------------------------------------------------------------------- 1 | from booktracker.common.base_model import BaseModel 2 | 3 | 4 | class User(BaseModel): 5 | user_id: int 6 | eid: str 7 | login: str 8 | name: str 9 | avatar: str 10 | profile: str 11 | 12 | class Meta: 13 | pk_field = "user_id" 14 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/server.py: -------------------------------------------------------------------------------- 1 | from .utilities.app_factory import create_app 2 | from sanic.log import logger 3 | 4 | app = create_app() 5 | 6 | 7 | @app.main_process_start 8 | def display_routes(app, _): 9 | logger.info("Registered routes:") 10 | for route in app.router.routes: 11 | logger.info(f"> /{route.path}") 12 | -------------------------------------------------------------------------------- /Chapter09/testing4/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from sanic_testing.reusable import ReusableClient 3 | 4 | from ..server import app 5 | 6 | 7 | @pytest.fixture(scope="session") 8 | def test_client(): 9 | client = ReusableClient(app, host="localhost", port=1234) 10 | client.run() 11 | yield client 12 | client.stop() 13 | -------------------------------------------------------------------------------- /Chapter01/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic, text, Request 2 | 3 | app = Sanic(__name__) 4 | 5 | @app.post("/") 6 | async def handler(request: Request): 7 | message = ( 8 | request.head + b"\n\n" + request.body 9 | ).decode("utf-8") 10 | print(message) 11 | return text("Done") 12 | 13 | app.run(port=9999, debug=True) -------------------------------------------------------------------------------- /Chapter09/testing4/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic, Request, json 2 | from itertools import count 3 | 4 | 5 | app = Sanic("test") 6 | 7 | 8 | @app.before_server_start 9 | def setup(app, _): 10 | app.ctx.counter = count() 11 | 12 | 13 | @app.get("") 14 | async def handler(request: Request): 15 | return json(next(request.app.ctx.counter)) 16 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/author/queries/create_author.sql: -------------------------------------------------------------------------------- 1 | WITH ref as ( 2 | INSERT INTO eids (eid, type) 3 | VALUES (:eid, 'authors') 4 | RETURNING ref_id 5 | ) 6 | INSERT INTO authors (ref_id, name) 7 | SELECT ref_id, 8 | :name 9 | FROM ref 10 | RETURNING author_id, 11 | name, 12 | :eid as eid; 13 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/book/queries/create_book_series.sql: -------------------------------------------------------------------------------- 1 | WITH ref as ( 2 | INSERT INTO eids (eid, type) 3 | VALUES (:eid, 'series') 4 | RETURNING ref_id 5 | ) 6 | INSERT INTO series (ref_id, name) 7 | SELECT ref_id, 8 | :name 9 | FROM ref 10 | RETURNING series_id, 11 | name, 12 | :eid as eid; 13 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/view.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint 2 | 3 | from .author.view import bp as author_bp 4 | from .book.view import bp as book_bp 5 | from .frontend.view import bp as frontend_bp 6 | 7 | api = Blueprint.group(author_bp, book_bp, version=1, version_prefix="/api/v") 8 | bp = Blueprint.group(frontend_bp, api) 9 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/author/queries/get_author_by_eid.sql: -------------------------------------------------------------------------------- 1 | SELECT e.eid, 2 | a.author_id, 3 | a.name, 4 | ( 5 | SELECT count(1) 6 | FROM books b 7 | WHERE b.author_id = a.author_id 8 | ) as num_books 9 | FROM authors a 10 | JOIN eids e ON a.ref_id = e.ref_id 11 | WHERE e.eid = :eid; 12 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/book/queries/update_book_state.sql: -------------------------------------------------------------------------------- 1 | UPDATE book_to_user bu 2 | SET state = :state 3 | FROM ( 4 | SELECT book_id 5 | FROM books b 6 | JOIN eids e ON b.ref_id = e.ref_id 7 | WHERE e.eid = :eid 8 | ) q 9 | WHERE bu.book_id = q.book_id 10 | AND bu.user_id = :user_id; 11 | -------------------------------------------------------------------------------- /Chapter05/html/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Adam's Top Songs 5 | 6 | 7 |

Adam's Top Songs

8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/author/queries/get_all_authors.sql: -------------------------------------------------------------------------------- 1 | SELECT e.eid, 2 | a.author_id, 3 | a.name, 4 | ( 5 | SELECT count(1) 6 | FROM books b 7 | WHERE b.author_id = a.author_id 8 | ) as num_books 9 | FROM authors a 10 | JOIN eids e ON a.ref_id = e.ref_id 11 | LIMIT :limit OFFSET :offset; 12 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/book/queries/create_book.sql: -------------------------------------------------------------------------------- 1 | WITH ref as ( 2 | INSERT INTO eids (eid, type) 3 | VALUES (:eid, 'books') 4 | RETURNING ref_id 5 | ) 6 | INSERT INTO books (ref_id, title, author_id, series_id) 7 | SELECT ref_id, 8 | :title, 9 | :author_id, 10 | :series_id 11 | FROM ref 12 | RETURNING book_id; 13 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/blueprints/info/view.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint, HTTPResponse, Request, json 2 | from sanic.views import HTTPMethodView 3 | 4 | bp = Blueprint("Info", url_prefix="/info") 5 | 6 | 7 | class InfoView(HTTPMethodView, attach=bp): 8 | async def get(self, request: Request) -> HTTPResponse: 9 | return json({"server": request.app.name}) 10 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/user/queries/create_user.sql: -------------------------------------------------------------------------------- 1 | WITH ref as ( 2 | INSERT INTO eids (eid, type) 3 | VALUES (:eid, 'users') 4 | RETURNING ref_id 5 | ) 6 | INSERT INTO users (login, ref_id, name, avatar, profile) 7 | SELECT :login, 8 | ref_id, 9 | :name, 10 | :avatar, 11 | :profile 12 | FROM ref 13 | RETURNING user_id; 14 | -------------------------------------------------------------------------------- /Chapter10/wdsbot/from_sanic/bot.py: -------------------------------------------------------------------------------- 1 | from nextcord.client import Client 2 | from nextcord.message import Message 3 | 4 | client = Client() 5 | 6 | 7 | @client.event 8 | async def on_message(message: Message) -> None: 9 | if message.author == client.user: 10 | return 11 | 12 | if message.content.startswith("$hello"): 13 | await message.channel.send("Hello!") 14 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/book/queries/update_toggle_book_is_loved.sql: -------------------------------------------------------------------------------- 1 | UPDATE book_to_user bu 2 | SET is_loved = NOT bu.is_loved 3 | FROM ( 4 | SELECT book_id 5 | FROM books b 6 | JOIN eids e ON b.ref_id = e.ref_id 7 | WHERE e.eid = :eid 8 | ) q 9 | WHERE bu.book_id = q.book_id 10 | AND bu.user_id = :user_id; 11 | -------------------------------------------------------------------------------- /Chapter06/inprocess-queue/db: -------------------------------------------------------------------------------- 1 | 187b765c-bd3e-49b8-b5e3-3efe79e24f55|hello|0|2022-01-02T09:11:35.158717|{}|null 2 | 187b765c-bd3e-49b8-b5e3-3efe79e24f55|hello|1|2022-01-02T09:11:45.166766|{}|"Hello, world" 3 | 910376d7-2eb7-44c9-9fdf-d8ccf9c9e53e|hello|0|2022-01-02T09:12:27.614149|{"name":"Adam"}|null 4 | 910376d7-2eb7-44c9-9fdf-d8ccf9c9e53e|hello|1|2022-01-02T09:12:37.617913|{"name":"Adam"}|"Hello, Adam" 5 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/blueprints/hello/view.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint, HTTPResponse, Request, json 2 | from sanic.views import HTTPMethodView 3 | 4 | bp = Blueprint("Hello", url_prefix="/hello") 5 | 6 | 7 | class HelloView(HTTPMethodView, attach=bp, uri="/"): 8 | async def get(self, request: Request, name: str) -> HTTPResponse: 9 | return json({"hello": name}) 10 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/author/queries/get_authors_by_name.sql: -------------------------------------------------------------------------------- 1 | SELECT e.eid, 2 | a.author_id, 3 | a.name, 4 | ( 5 | SELECT count(1) 6 | FROM books b 7 | WHERE b.author_id = a.author_id 8 | ) as num_books 9 | FROM authors a 10 | JOIN eids e ON a.ref_id = e.ref_id 11 | WHERE a.name % :name 12 | LIMIT :limit OFFSET :offset; 13 | -------------------------------------------------------------------------------- /Chapter08/k8s/issuer.yml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: ClusterIssuer 3 | metadata: 4 | name: letsencrypt-tls 5 | spec: 6 | acme: 7 | email: fake@email.com 8 | server: https://acme-v02.api.letsencrypt.org/directory 9 | privateKeySecretRef: 10 | name: letsencrypt-tls-private-key 11 | solvers: 12 | - http01: 13 | ingress: 14 | class: nginx 15 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/src/layouts/Main.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 |
9 | {#if $currentUser.me} 10 | 11 | {/if} 12 |
13 |
14 | -------------------------------------------------------------------------------- /Chapter07/corsissue/server1/server.py: -------------------------------------------------------------------------------- 1 | from sanic import HTTPResponse, Request, Sanic, text 2 | 3 | app = Sanic(__name__) 4 | 5 | 6 | @app.get("/") 7 | async def handler(request: Request, name: str) -> HTTPResponse: 8 | return text(f"Hi {name}") 9 | 10 | 11 | # DO NOT DO THIS 12 | # @app.on_response 13 | # async def cors(_, resp): 14 | # resp.headers["Access-Control-Allow-Origin"] = "*" 15 | -------------------------------------------------------------------------------- /Chapter09/tracing/myapp/middleware/request_context.py: -------------------------------------------------------------------------------- 1 | from contextvars import ContextVar 2 | 3 | from sanic import Request, Sanic 4 | 5 | app = Sanic.get_app() 6 | 7 | 8 | @app.after_server_start 9 | async def setup_request_context(app, _): 10 | app.ctx.request = ContextVar("request") 11 | 12 | 13 | @app.on_request 14 | async def attach_request(request: Request): 15 | request.app.ctx.request.set(request) 16 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/users/queries/get_user_by_name.sql: -------------------------------------------------------------------------------- 1 | SELECT *, 2 | ( 3 | SELECT SUM(distance) 4 | FROM trails t 5 | JOIN hikes h on t.trail_id = h.trail_id 6 | WHERE h.user_id = u.user_id 7 | ) total_distance_hiked 8 | FROM users u 9 | WHERE LOWER(name) = LOWER(:name); 10 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/worker/module.py: -------------------------------------------------------------------------------- 1 | from importlib import import_module 2 | 3 | from sanic import Sanic 4 | 5 | 6 | def setup_modules(app: Sanic, *module_names: str) -> None: 7 | """ 8 | Load some modules 9 | """ 10 | for module_name in module_names: 11 | module = import_module(module_name) 12 | if bp := getattr(module, "bp", None): 13 | app.blueprint(bp) 14 | -------------------------------------------------------------------------------- /Chapter07/accesstoken/auth/refresh_token.py: -------------------------------------------------------------------------------- 1 | from secrets import token_urlsafe 2 | from bcrypt import hashpw, gensalt 3 | from .user import User 4 | 5 | 6 | def generate_token(): 7 | api_key = token_urlsafe() 8 | hashed_key = hashpw(api_key.encode("utf-8"), gensalt()) 9 | return api_key, hashed_key 10 | 11 | 12 | async def store_refresh_token(user: User, hashed_key: str) -> None: 13 | user.refresh_hash = hashed_key 14 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/middleware/request_context.py: -------------------------------------------------------------------------------- 1 | from contextvars import ContextVar 2 | 3 | from sanic import Request, Sanic 4 | 5 | app = Sanic.get_app() 6 | 7 | 8 | @app.after_server_start 9 | async def setup_request_context(app, _): 10 | app.ctx.request = ContextVar("request") 11 | 12 | 13 | @app.on_request 14 | async def attach_request(request: Request): 15 | request.app.ctx.request.set(request) 16 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 9 - Full Hiking App 2 | 3 | ## Getting started 4 | 5 | ``` 6 | docker-compose build 7 | ``` 8 | 9 | ``` 10 | docker-compose up 11 | ``` 12 | 13 | ## Checkout some endpoints: 14 | 15 | ``` 16 | curl localhost:7777/v1/trails 17 | curl localhost:7777/v1/users/alice/hikes 18 | curl localhost:7777/v1/slow 19 | ``` 20 | 21 | _Make sure to hit `curl localhost:7777/v1/slow` multiple times to see the difference_ 22 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic 2 | 3 | from world.common.log import setup_logging 4 | 5 | 6 | def create_app() -> Sanic: 7 | app = Sanic("GraphQLApp") 8 | setup_logging(app) 9 | 10 | from world.blueprints.view import bp # noqa 11 | from world.middleware import request_context # noqa 12 | from world.worker import postgres # noqa 13 | 14 | app.blueprint(bp) 15 | 16 | return app 17 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/feeder/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic 2 | 3 | from feeder.common.log import setup_logging 4 | 5 | 6 | def create_app() -> Sanic: 7 | app = Sanic("feeder") 8 | setup_logging(app) 9 | 10 | from feeder.middleware import request_context # noqa 11 | from feeder.blueprints.view import bp # noqa 12 | from feeder.worker import redis # noqa 13 | 14 | app.blueprint(bp) 15 | 16 | return app 17 | -------------------------------------------------------------------------------- /Chapter09/testing3/path/to/some_registration_service.py: -------------------------------------------------------------------------------- 1 | from .some_db_connection import FakeDBConnection 2 | 3 | 4 | class RegistrationService: 5 | def __init__(self, connection: FakeDBConnection) -> None: 6 | self.connection = connection 7 | 8 | async def register_user(self, username: str, email: str) -> None: 9 | query = "INSERT INTO users VALUES ($1, $2);" 10 | await self.connection.execute(query, username, email) 11 | -------------------------------------------------------------------------------- /Chapter04/requeststream/upload.py: -------------------------------------------------------------------------------- 1 | import httpx 2 | 3 | 4 | def gen(filename, f, size=4): 5 | yield filename 6 | while True: 7 | data = f.read(size) 8 | if not data: 9 | break 10 | yield data.encode("utf-8") 11 | 12 | 13 | with open("./file.txt", "r") as f: 14 | r = httpx.post("http://localhost:7777/upload", data=gen(b"somefile.txt", f)) 15 | print(r.status_code) 16 | for line in r.text.split("\n"): 17 | print(line) 18 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/blueprints/author/model.py: -------------------------------------------------------------------------------- 1 | from dataclasses import field 2 | from typing import Optional 3 | 4 | from booktracker.common.base_model import BaseModel 5 | 6 | 7 | class Author(BaseModel): 8 | author_id: int 9 | eid: str 10 | name: str 11 | num_books: Optional[int] = field(default=None) 12 | 13 | class Meta: 14 | pk_field = "author_id" 15 | 16 | 17 | class CreateAuthorBody(BaseModel): 18 | name: str 19 | -------------------------------------------------------------------------------- /Chapter08/k8s/server.py: -------------------------------------------------------------------------------- 1 | from sanic import HTTPResponse, Request, Sanic, text 2 | from sanic.log import logger 3 | 4 | app = Sanic(__name__) 5 | app.config.REAL_IP_HEADER = "x-real-ip" 6 | 7 | 8 | @app.get("/") 9 | async def handler(request: Request) -> HTTPResponse: 10 | logger.info(request.headers) 11 | return text(f"Hello from {request.remote_addr}") 12 | 13 | 14 | @app.get("/healthz") 15 | async def healthz(request: Request) -> HTTPResponse: 16 | return text("OK") 17 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/countries/schema.gql: -------------------------------------------------------------------------------- 1 | type Country { 2 | code: String 3 | name: String 4 | continent: String 5 | region: String 6 | surfacearea: Int 7 | indepyear: Int 8 | population: Int 9 | lifeexpectancy: Int 10 | gnp: Float 11 | gnpold: Float 12 | localname: String 13 | governmentform: String 14 | headofstate: String 15 | capital: City 16 | code2: String 17 | languages: [Language] 18 | } 19 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/middleware/request_context.py: -------------------------------------------------------------------------------- 1 | from contextvars import ContextVar 2 | from typing import Any 3 | 4 | from sanic import Request, Sanic 5 | 6 | app = Sanic.get_app() 7 | 8 | 9 | @app.after_server_start 10 | async def setup_request_context(app: Sanic, _: Any) -> None: 11 | app.ctx.request = ContextVar("request") 12 | 13 | 14 | @app.on_request 15 | async def attach_request(request: Request) -> None: 16 | request.app.ctx.request.set(request) 17 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/feeder/middleware/request_context.py: -------------------------------------------------------------------------------- 1 | from contextvars import ContextVar 2 | from typing import Any 3 | 4 | from sanic import Request, Sanic 5 | 6 | app = Sanic.get_app() 7 | 8 | 9 | @app.after_server_start 10 | async def setup_request_context(app: Sanic, _: Any) -> None: 11 | app.ctx.request = ContextVar("request") 12 | 13 | 14 | @app.on_request 15 | async def attach_request(request: Request) -> None: 16 | request.app.ctx.request.set(request) 17 | -------------------------------------------------------------------------------- /Chapter06/inprocess-queue/job/worker.py: -------------------------------------------------------------------------------- 1 | from .job import Job 2 | 3 | 4 | async def worker(name, queue, backend): 5 | while True: 6 | job = await queue.get() 7 | if not job: 8 | break 9 | 10 | size = queue.qsize() 11 | print(f"[{name}] Running {job}. {size} in queue.") 12 | 13 | job_instance = await Job.create(job, backend) 14 | 15 | async with job_instance as operation: 16 | await job_instance.execute(operation) 17 | -------------------------------------------------------------------------------- /Chapter08/paas/server.py: -------------------------------------------------------------------------------- 1 | from sanic import HTTPResponse, Request, Sanic, text 2 | from sanic.log import logger 3 | 4 | app = Sanic(__name__) 5 | app.config.REAL_IP_HEADER = "do-connecting-ip" 6 | 7 | 8 | @app.get("/") 9 | async def handler(request: Request) -> HTTPResponse: 10 | logger.info(request.headers) 11 | return text(f"Hello from {request.remote_addr}") 12 | 13 | 14 | @app.get("/healthz") 15 | async def healthz(request: Request) -> HTTPResponse: 16 | return text("OK") 17 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic 2 | 3 | from hiking.common.log import setup_logging 4 | 5 | 6 | def create_app(): 7 | app = Sanic("HikingApp") 8 | setup_logging(app) 9 | 10 | from hiking.blueprints.view import bp # noqa 11 | from hiking.middleware import request_context # noqa 12 | from hiking.worker import postgres # noqa 13 | from hiking.worker import redis # noqa 14 | 15 | app.blueprint(bp) 16 | 17 | return app 18 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/applications/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic 2 | 3 | from wadsworth.applications.redirect import attach_redirect_app 4 | from wadsworth.blueprints.info.view import bp as info_view 5 | from wadsworth.blueprints.view import bp 6 | 7 | 8 | def create_app(): 9 | app = Sanic("MainApp") 10 | app.config.SERVER_NAME = "localhost:8443" 11 | app.blueprint(bp) 12 | app.blueprint(info_view) 13 | 14 | attach_redirect_app(app) 15 | 16 | return app 17 | -------------------------------------------------------------------------------- /Chapter02/booktracker/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "" 3 | version = "" 4 | description = "" 5 | authors = [ 6 | {name = "Adam Hopkins", email = "adam@amhopkins.com"}, 7 | ] 8 | dependencies = [ 9 | "sanic~=21.3", 10 | ] 11 | requires-python = ">=3.9" 12 | dynamic = ["classifiers"] 13 | license = {text = "NOLICENSE"} 14 | 15 | [project.urls] 16 | homepage = "" 17 | 18 | [build-system] 19 | requires = ["pdm-pep517"] 20 | build-backend = "pdm.pep517.api" 21 | 22 | [tool] 23 | [tool.pdm] 24 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/users/executor.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | from hiking.blueprints.users.models import User 3 | from hiking.common.dao.executor import BaseExecutor 4 | 5 | 6 | class UserExecutor(BaseExecutor): 7 | async def get_all_users(self, *, exclude: Optional[List[str]] = None) -> List[User]: 8 | ... 9 | 10 | async def get_user_by_name( 11 | self, name: str, *, exclude: Optional[List[str]] = None 12 | ) -> User: 13 | ... 14 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/middleware/request_context.py: -------------------------------------------------------------------------------- 1 | from contextvars import ContextVar 2 | from typing import Any 3 | 4 | from sanic import Request, Sanic 5 | 6 | app = Sanic.get_app("BooktrackerApp") 7 | 8 | 9 | @app.after_server_start 10 | async def setup_request_context(app: Sanic, _) -> None: 11 | app.ctx.request = ContextVar("request") 12 | 13 | 14 | @app.on_request 15 | async def attach_request(request: Request) -> None: 16 | request.app.ctx.request.set(request) 17 | -------------------------------------------------------------------------------- /Chapter10/pwa/my-svelte-project/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Svelte app 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Chapter10/wdsbot/from_bot/server.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from sanic import HTTPResponse, Request, Sanic, json 4 | 5 | app = Sanic("WDSApp") 6 | 7 | 8 | @app.get("/") 9 | async def handler(request: Request) -> HTTPResponse: 10 | await request.app.ctx.general.send("Someone sent a message") 11 | return json({"foo": "bar"}) 12 | 13 | 14 | @app.before_server_start 15 | async def before_server_start(app: Sanic, _: Any) -> None: 16 | await app.ctx.general.send("Wadsworth, reporting for duty") 17 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/languages/executor.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | from world.blueprints.languages.models import Language 4 | from world.common.dao.executor import BaseExecutor 5 | 6 | 7 | class LanguageExecutor(BaseExecutor): 8 | async def get_by_country_code( 9 | self, 10 | *, 11 | country_code: str, 12 | exclude: Optional[List[str]] = None, 13 | limit: int = 15, 14 | offset: int = 0, 15 | ) -> List[Language]: 16 | ... 17 | -------------------------------------------------------------------------------- /Chapter06/inprocess-queue/job/blueprint.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint 2 | from job.startup import ( 3 | setup_task_executor, 4 | setup_job_fetch, 5 | register_operations, 6 | ) 7 | from job.view import JobListView, JobDetailView 8 | 9 | bp = Blueprint("JobQueue", url_prefix="/job") 10 | 11 | bp.after_server_start(setup_job_fetch) 12 | bp.after_server_start(setup_task_executor) 13 | bp.after_server_start(register_operations) 14 | bp.add_route(JobListView.as_view(), "") 15 | bp.add_route(JobDetailView.as_view(), "/") 16 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/trails/executor.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | from hiking.blueprints.trails.models import Trail 3 | from hiking.common.dao.executor import BaseExecutor 4 | 5 | 6 | class TrailExecutor(BaseExecutor): 7 | async def get_all_trails( 8 | self, *, exclude: Optional[List[str]] = None 9 | ) -> List[Trail]: 10 | ... 11 | 12 | async def get_trail_by_name( 13 | self, name: str, *, exclude: Optional[List[str]] = None 14 | ) -> Trail: 15 | ... 16 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/worker/redis.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic 2 | import aioredis 3 | 4 | app = Sanic.get_app() 5 | 6 | 7 | @app.before_server_start 8 | async def setup_redis(app, _): 9 | app.ctx.redis_pool = aioredis.BlockingConnectionPool.from_url( 10 | app.config.REDIS_DSN, max_connections=app.config.REDIS_MAX 11 | ) 12 | app.ctx.redis = aioredis.Redis(connection_pool=app.ctx.redis_pool) 13 | 14 | 15 | @app.after_server_stop 16 | async def shutdown_redis(app, _): 17 | await app.ctx.redis_pool.disconnect() 18 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/countries/models.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from world.common.base_model import BaseModel 4 | 5 | 6 | @dataclass 7 | class Country(BaseModel): 8 | code: str 9 | name: str 10 | continent: str 11 | region: str 12 | surfacearea: int 13 | indepyear: int 14 | population: int 15 | lifeexpectancy: int 16 | gnp: float 17 | gnpold: float 18 | localname: str 19 | governmentform: str 20 | headofstate: str 21 | capital: int 22 | code2: str 23 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/src/layouts/Footer.svelte: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | The source code is licensed 5 | MIT 6 |

7 |

8 | ~ Made with ❤️ and ☕️ by 9 | Adam Hopkins ~ 10 |

11 |
12 |
13 | 14 | 19 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/slow/view.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint, HTTPResponse, Request, text 2 | import random 3 | import asyncio 4 | from hiking.common.cache import cache_response 5 | 6 | 7 | bp = Blueprint("Slow", url_prefix="/slow") 8 | 9 | 10 | @bp.get("") 11 | @cache_response("tortoise") 12 | async def wow_super_slow(request: Request) -> HTTPResponse: 13 | wait_time = 0 14 | for _ in range(10): 15 | t = random.random() 16 | await asyncio.sleep(t) 17 | wait_time += t 18 | return text(f"Wow, that took {wait_time:.2f}s!") 19 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | app: 3 | build: ./application 4 | ports: 5 | - 7777:7777 6 | depends_on: 7 | - db-redis 8 | command: 9 | sanic 10 | --port=7777 11 | --host=0.0.0.0 12 | --workers=2 13 | --factory 14 | --debug 15 | feeder.server:create_app 16 | volumes: 17 | - ./application/feeder:/app/feeder 18 | environment: 19 | SANIC_REDIS_DSN: "redis://db-redis:6379" 20 | SANIC_REDIS_MAX: 12 21 | db-redis: 22 | image: redis:alpine 23 | ports: 24 | - 6379:6379 25 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/worker/redis.py: -------------------------------------------------------------------------------- 1 | import aioredis 2 | from sanic import Sanic 3 | 4 | app = Sanic.get_app("BooktrackerApp") 5 | 6 | 7 | @app.before_server_start 8 | async def setup_redis(app: Sanic, _) -> None: 9 | app.ctx.redis_pool = aioredis.BlockingConnectionPool.from_url( 10 | app.config.REDIS_DSN, max_connections=app.config.REDIS_MAX 11 | ) 12 | app.ctx.redis = aioredis.Redis(connection_pool=app.ctx.redis_pool) 13 | 14 | 15 | @app.after_server_stop 16 | async def shutdown_redis(app: Sanic, _) -> None: 17 | await app.ctx.redis_pool.disconnect() 18 | -------------------------------------------------------------------------------- /Chapter09/testing3/tests/conftest.py: -------------------------------------------------------------------------------- 1 | from importlib import import_module 2 | from unittest.mock import AsyncMock 3 | import pytest 4 | from sanic import Sanic 5 | import testing3.path.to.some_db_connection 6 | 7 | 8 | @pytest.fixture 9 | def mocked_execute(monkeypatch): 10 | execute = AsyncMock() 11 | monkeypatch.setattr( 12 | testing3.path.to.some_db_connection.FakeDBConnection, "execute", execute 13 | ) 14 | return execute 15 | 16 | 17 | @pytest.fixture 18 | def dummy_app(): 19 | app = Sanic("DummyApp") 20 | 21 | import_module("testing3.path.to.some_startup") 22 | return app 23 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10 2 | 3 | RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - 4 | RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list 5 | RUN apt-get update && apt-get install -y yarn wait-for-it 6 | 7 | WORKDIR /app 8 | 9 | COPY ./package.json /app/package.json 10 | COPY ./rollup.config.js /app/rollup.config.js 11 | RUN yarn install 12 | 13 | COPY ./requirements.txt /app/requirements.txt 14 | RUN pip install -r requirements.txt 15 | 16 | COPY ./booktracker /app/booktracker 17 | COPY ./ui /app/ui 18 | 19 | -------------------------------------------------------------------------------- /Chapter07/corsissue/server2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CORS issue 8 | 9 | 10 |

Loading...

11 | 18 | 19 | -------------------------------------------------------------------------------- /Chapter07/accesstoken/auth/user.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass, field 2 | from typing import Optional 3 | 4 | from sanic import Request 5 | 6 | 7 | @dataclass 8 | class User: 9 | user_id: int 10 | refresh_hash: Optional[str] = field(default=None) 11 | 12 | 13 | fake_database = { 14 | 1: User(1), 15 | } 16 | 17 | 18 | async def authenticate_login_credentials(username: str, password: str) -> User: 19 | # Do some fancy logic to validate the username and password 20 | return fake_database[1] 21 | 22 | 23 | async def get_user_from_request(request: Request) -> User: 24 | return fake_database[1] 25 | -------------------------------------------------------------------------------- /Chapter09/loggingapp0/myapp/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic, text 2 | 3 | from myapp.common.log import app_logger, setup_logging 4 | 5 | 6 | def create_app(): 7 | app = Sanic("logging_app") 8 | setup_logging(app) 9 | 10 | @app.route("") 11 | async def dummy(_): 12 | app_logger.debug("This is a DEBUG message") 13 | app_logger.info("This is a INFO message") 14 | app_logger.warning("This is a WARNING message") 15 | app_logger.error("This is a ERROR message") 16 | app_logger.critical("This is a CRITICAL message") 17 | return text("") 18 | 19 | return app 20 | -------------------------------------------------------------------------------- /Chapter09/loggingapp1/myapp/server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic, text 2 | 3 | from myapp.common.log import app_logger, setup_logging 4 | 5 | 6 | def create_app(): 7 | app = Sanic("logging_app") 8 | setup_logging(app) 9 | 10 | @app.route("") 11 | async def dummy(_): 12 | app_logger.debug("This is a DEBUG message") 13 | app_logger.info("This is a INFO message") 14 | app_logger.warning("This is a WARNING message") 15 | app_logger.error("This is a ERROR message") 16 | app_logger.critical("This is a CRITICAL message") 17 | return text("") 18 | 19 | return app 20 | -------------------------------------------------------------------------------- /Chapter02/booktracker/src/utilities/app_factory.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Sequence 2 | from sanic import Sanic 3 | 4 | 5 | from .autodiscovery import autodiscover 6 | 7 | DEFAULT_BLUEPRINTS = [ 8 | "src.blueprints.v1.book.view", 9 | "src.blueprints.v1.author.view", 10 | "src.blueprints.v2.group", 11 | ] 12 | 13 | 14 | def create_app( 15 | init_blueprints: Optional[Sequence[str]] = None, 16 | ) -> Sanic: 17 | app = Sanic("BookTracker") 18 | 19 | if not init_blueprints: 20 | init_blueprints = DEFAULT_BLUEPRINTS 21 | 22 | autodiscover(app, *init_blueprints) 23 | 24 | return app 25 | -------------------------------------------------------------------------------- /Chapter10/graphql/application/world/blueprints/countries/executor.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | from world.blueprints.countries.models import Country 4 | from world.common.dao.executor import BaseExecutor 5 | 6 | 7 | class CountryExecutor(BaseExecutor): 8 | async def get_all_countries( 9 | self, 10 | *, 11 | exclude: Optional[List[str]] = None, 12 | limit: int = 15, 13 | offset: int = 0, 14 | ) -> List[Country]: 15 | ... 16 | 17 | async def get_country_by_name( 18 | self, name: str, *, exclude: Optional[List[str]] = None 19 | ) -> Country: 20 | ... 21 | -------------------------------------------------------------------------------- /Chapter06/inprocess-queue/job/model.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from dataclasses import asdict, dataclass 4 | from datetime import datetime 5 | from typing import Any, Dict 6 | from uuid import UUID 7 | 8 | import ujson as json 9 | 10 | 11 | @dataclass 12 | class JobDetails: 13 | uid: UUID 14 | name: str 15 | complete: bool 16 | timestamp: datetime 17 | kwargs: Dict[str, Any] 18 | return_value: Any 19 | 20 | def __json__(self): 21 | output = asdict(self) 22 | output["uid"] = str(self.uid) 23 | output["timestamp"] = self.timestamp.isoformat() 24 | return json.dumps(output) 25 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/src/components/Reading.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | {#each $reading as book} 11 | {#if book.state === "reading"} 12 | 13 | {book.title} 14 | 15 | {/if} 16 | {:else} 17 | None! Time to go pick up a book. 18 | {/each} 19 |
20 | -------------------------------------------------------------------------------- /Chapter08/k8s/app.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: ch08-k8s-app 5 | spec: 6 | ports: 7 | - port: 80 8 | targetPort: 7777 9 | selector: 10 | app: ch08-k8s-app 11 | --- 12 | apiVersion: apps/v1 13 | kind: Deployment 14 | metadata: 15 | name: ch08-k8s-app 16 | spec: 17 | selector: 18 | matchLabels: 19 | app: ch08-k8s-app 20 | replicas: 2 21 | template: 22 | metadata: 23 | labels: 24 | app: ch08-k8s-app 25 | spec: 26 | containers: 27 | - name: ch08-k8s-app 28 | image: admhpkns/my-sanic-example-app:2 29 | ports: 30 | - containerPort: 7777 31 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/src/stores/user.js: -------------------------------------------------------------------------------- 1 | import { writable } from "svelte/store"; 2 | 3 | const nullUser = {}; 4 | 5 | function createCurrentUser() { 6 | const { subscribe, set, update } = writable(nullUser); 7 | return { 8 | subscribe, 9 | set, 10 | update, 11 | logout: () => { 12 | set(nullUser); 13 | }, 14 | login: (response) => { 15 | console.log(`Logged in as...`, response); 16 | set({ 17 | ...response, 18 | }); 19 | }, 20 | }; 21 | } 22 | 23 | const currentUser = createCurrentUser(); 24 | export { currentUser }; 25 | -------------------------------------------------------------------------------- /Chapter10/wsfeed/application/feeder/worker/redis.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | import aioredis 4 | from sanic import Sanic 5 | 6 | app = Sanic.get_app() 7 | 8 | 9 | @app.before_server_start 10 | async def setup_redis(app: Sanic, _: Any) -> None: 11 | app.ctx.redis_pool = aioredis.BlockingConnectionPool.from_url( 12 | app.config.REDIS_DSN, max_connections=app.config.REDIS_MAX 13 | ) 14 | app.ctx.redis = aioredis.Redis(connection_pool=app.ctx.redis_pool) 15 | app.ctx.pubsub = app.ctx.redis.pubsub() 16 | 17 | 18 | @app.after_server_stop 19 | async def shutdown_redis(app: Sanic, _: Any) -> None: 20 | await app.ctx.redis_pool.disconnect() 21 | -------------------------------------------------------------------------------- /Chapter08/k8s/load-balancer.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | annotations: 5 | service.beta.kubernetes.io/do-loadbalancer-hostname: example.com 6 | name: ingress-nginx-controller 7 | namespace: ingress-nginx 8 | spec: 9 | type: LoadBalancer 10 | externalTrafficPolicy: Local 11 | ports: 12 | - name: http 13 | port: 80 14 | protocol: TCP 15 | targetPort: http 16 | - name: https 17 | port: 443 18 | protocol: TCP 19 | targetPort: https 20 | selector: 21 | app.kubernetes.io/name: ingress-nginx 22 | app.kubernetes.io/instance: ingress-nginx 23 | app.kubernetes.io/component: controller 24 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/hikes/hydrator.py: -------------------------------------------------------------------------------- 1 | from typing import Any, List, Mapping, Optional, Type 2 | from hiking.common.dao.hydrator import Hydrator 3 | from hiking.common.base_model import BaseModel 4 | from hiking.blueprints.hikes.models import Hike 5 | from hiking.blueprints.trails.models import Trail 6 | 7 | 8 | class HikeHydrator(Hydrator): 9 | def do_hydration( 10 | self, 11 | record: Mapping[str, Any], 12 | model: Type[BaseModel], 13 | exclude: Optional[List[str]] = None, 14 | ): 15 | values = dict(record) 16 | date = values.pop("date") 17 | return Hike(Trail(**values), date) 18 | -------------------------------------------------------------------------------- /Chapter10/httpredirect/wadsworth/blueprints/redirect/view.py: -------------------------------------------------------------------------------- 1 | from sanic import Blueprint, HTTPResponse, Request, response 2 | from sanic.constants import HTTP_METHODS 3 | 4 | bp = Blueprint("Redirect") 5 | 6 | 7 | @bp.route("/", methods=HTTP_METHODS, name="redirection_proxy") 8 | async def proxy(request: Request, path: str) -> HTTPResponse: 9 | return response.redirect( 10 | request.app.url_for( 11 | "Redirect.redirection_proxy", 12 | path=path, 13 | _server=request.app.ctx.main_app.config.SERVER_NAME, 14 | _external=True, 15 | _scheme="https", 16 | ), 17 | status=301, 18 | ) 19 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/booktracker/common/eid.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | from string import ascii_letters, digits 3 | 4 | REQUEST_ID_ALPHABET = ascii_letters + digits 5 | REQUEST_ID_ALPHABET_LENGTH = len(REQUEST_ID_ALPHABET) 6 | 7 | 8 | def generate(width: int = 0, fillchar: str = "x") -> str: 9 | """ 10 | Generate a UUID and make is smaller 11 | """ 12 | output = "" 13 | uid = uuid.uuid4() 14 | num = uid.int 15 | while num: 16 | num, pos = divmod(num, REQUEST_ID_ALPHABET_LENGTH) 17 | output += REQUEST_ID_ALPHABET[pos] 18 | eid = output[::-1] 19 | if width: 20 | eid = eid.rjust(width, fillchar) 21 | return eid 22 | -------------------------------------------------------------------------------- /Chapter09/hikingapp/application/hiking/blueprints/hikes/executor.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from hiking.common.dao.executor import BaseExecutor 3 | from .models import Hike 4 | 5 | from hiking.blueprints.users.models import User 6 | 7 | 8 | class HikeExecutor(BaseExecutor): 9 | async def get_hikes_by_user(self, user: User) -> List[Hike]: 10 | query = self._queries["get_hikes_by_user"] 11 | records = await self.db.fetch_all(query, values={"user_id": user.user_id}) 12 | hikes = self.hydrator.hydrate(records, Hike, True) 13 | 14 | return hikes 15 | 16 | async def get_hikes_by_user_by_name(self, name: str) -> List[Hike]: 17 | ... 18 | -------------------------------------------------------------------------------- /Chapter10/pwa/my-svelte-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-app", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "rollup -c", 7 | "dev": "rollup -c -w", 8 | "start": "sirv public --no-clear" 9 | }, 10 | "devDependencies": { 11 | "@rollup/plugin-commonjs": "^17.0.0", 12 | "@rollup/plugin-node-resolve": "^11.0.0", 13 | "rollup": "^2.3.4", 14 | "rollup-plugin-css-only": "^3.1.0", 15 | "rollup-plugin-livereload": "^2.0.0", 16 | "rollup-plugin-svelte": "^7.0.0", 17 | "rollup-plugin-terser": "^7.0.0", 18 | "svelte": "^3.0.0" 19 | }, 20 | "dependencies": { 21 | "sirv-cli": "^1.0.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/src/utils/cookie.js: -------------------------------------------------------------------------------- 1 | function getCookie(name) { 2 | var match = document.cookie.match( 3 | RegExp("(?:^|;\\s*)" + name + "=([^;]*)") 4 | ); 5 | return match ? match[1] : null; 6 | } 7 | function deleteCookie(name, path, domain) { 8 | if ( 9 | document.cookie.split(";").some((c) => c.trim().startsWith(name + "=")) 10 | ) { 11 | document.cookie = 12 | name + 13 | "=" + 14 | (path ? ";path=" + path : "") + 15 | (domain ? ";domain=" + domain : "") + 16 | ";expires=Thu, 01 Jan 1970 00:00:01 GMT"; 17 | } 18 | } 19 | export { getCookie, deleteCookie }; 20 | -------------------------------------------------------------------------------- /Chapter07/accesstoken/auth/cookie.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | 5 | def set_cookie( 6 | response, 7 | key, 8 | value, 9 | httponly=False, 10 | samesite="lax", 11 | domain: Optional[str] = None, 12 | exp: Optional[datetime] = None, 13 | ): 14 | response.cookies[key] = value 15 | response.cookies[key]["httponly"] = httponly 16 | response.cookies[key]["path"] = "/" 17 | response.cookies[key]["secure"] = True 18 | response.cookies[key]["samesite"] = samesite 19 | 20 | if domain: 21 | response.cookies[key]["domain"] = domain 22 | 23 | if exp: 24 | response.cookies[key]["expires"] = exp 25 | -------------------------------------------------------------------------------- /Chapter08/k8s/ingress.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: ch08-k8s-app-ingress 5 | annotations: 6 | kubernetes.io/ingress.class: nginx 7 | # cert-manager.io/cluster-issuer: letsencrypt-tls 8 | # certmanager.k8s.io/acme-challenge-type: http01 9 | spec: 10 | # tls: 11 | # - hosts: 12 | # - example.com 13 | # secretName: ch08-k8s-tls 14 | rules: 15 | - host: "example.com" 16 | http: 17 | paths: 18 | - pathType: Prefix 19 | path: / 20 | backend: 21 | service: 22 | name: ch08-k8s-app 23 | port: 24 | number: 80 25 | -------------------------------------------------------------------------------- /Chapter06/inprocess-queue/job/startup.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from job.worker import worker 3 | from .backend import FileBackend 4 | from .operations.hello import Hello 5 | from .operations.registry import OperationRegistry 6 | 7 | 8 | async def setup_job_fetch(app, _): 9 | app.ctx.jobs = FileBackend("./db") 10 | 11 | 12 | async def setup_task_executor(app, _): 13 | app.ctx.queue = asyncio.Queue(maxsize=64) 14 | for x in range(app.config.NUM_TASK_WORKERS): 15 | name = f"Worker-{x}" 16 | print(f"Starting up executor: {name}") 17 | app.add_task(worker(name, app.ctx.queue, app.ctx.jobs)) 18 | 19 | 20 | async def register_operations(app, _): 21 | app.ctx.registry = OperationRegistry(Hello) 22 | -------------------------------------------------------------------------------- /Chapter11/booktracker/application/ui/src/App.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
15 |