From 90aee96caeef3d013408c194aff5547c8bcaa489 Mon Sep 17 00:00:00 2001 From: Daniel Tiesling Date: Thu, 15 Feb 2024 06:13:57 -0800 Subject: [PATCH] docs: updates and adds to examples folder. --- examples/00_quickstart/README.md | 22 +- examples/01_authentication/README.md | 4 + examples/02_pydantic/README.md | 26 +- examples/02_pydantic/app.py | 11 +- examples/03_add_to_existing_api/Pipfile | 18 + examples/03_add_to_existing_api/Pipfile.lock | 447 +++++++++++++++++++ examples/03_add_to_existing_api/README.md | 93 ++++ examples/03_add_to_existing_api/app.py | 64 +++ 8 files changed, 654 insertions(+), 31 deletions(-) create mode 100644 examples/03_add_to_existing_api/Pipfile create mode 100644 examples/03_add_to_existing_api/Pipfile.lock create mode 100644 examples/03_add_to_existing_api/README.md create mode 100644 examples/03_add_to_existing_api/app.py diff --git a/examples/00_quickstart/README.md b/examples/00_quickstart/README.md index f6339f9..e68c286 100644 --- a/examples/00_quickstart/README.md +++ b/examples/00_quickstart/README.md @@ -23,7 +23,7 @@ Go to [http://127.0.0.1:5000/apidocs/](http://127.0.0.1:5000/apidocs/) in a brow ### Create a ToDo item ``` -curl -X POST --location "http://127.0.0.1:5000/todos" \ +curl -X POST --location "http://127.0.0.1:5000/todos/" \ -H "Content-Type: application/json" \ -d "{ \"text\": \"take out garbage again\" @@ -32,44 +32,44 @@ curl -X POST --location "http://127.0.0.1:5000/todos" \ ### List all ToDo items (flat) ``` -curl -X GET --location "http://127.0.0.1:5000/todos" \ +curl -X GET --location "http://127.0.0.1:5000/todos/" \ -d "Accept: application/json" ``` ### List all ToDo items (paginated) ``` -curl -X GET --location "http://127.0.0.1:5000/todos?limit=2&offset=1" \ +curl -X GET --location "http://127.0.0.1:5000/todos/?limit=2&offset=1" \ -d "Accept: application/json" ``` ### Search ToDo items ``` -curl -X GET --location "http://127.0.0.1:5000/todos?search=garbage" \ +curl -X GET --location "http://127.0.0.1:5000/todos/?search=garbage" \ -d "Accept: application/json" ``` ### Filter ToDo items ``` -curl -X GET --location "http://127.0.0.1:5000/todos?filters=%7B%22text%22%3A+%22take+out+garbage+again%22%7D" \ +curl -X GET --location "http://127.0.0.1:5000/todos/?filters=%7B%22text%22%3A+%22take+out+garbage+again%22%7D" \ -d "Accept: application/json" ``` _querystring urldecodes to `filters={"text": "take out garbage again"}`_ ### Sort ToDo items ``` -curl -X GET --location "http://127.0.0.1:5000/todos?sort=text" \ +curl -X GET --location "http://127.0.0.1:5000/todos/?sort=text" \ -d "Accept: application/json" ``` ### Fetch ToDo item ``` -curl -X GET --location "http://127.0.0.1:5000/todos/1" \ +curl -X GET --location "http://127.0.0.1:5000/todos/1/" \ -d "Accept: application/json" ``` ### Update ToDo item ``` -curl -X PUT --location "http://127.0.0.1:5000/todos/1" \ +curl -X PUT --location "http://127.0.0.1:5000/todos/1/" \ -H "Content-Type: application/json" \ -d "{ \"text\": \"Updated todo item\" @@ -78,7 +78,7 @@ curl -X PUT --location "http://127.0.0.1:5000/todos/1" \ ### Patch ToDo item ``` -curl -X PATCH --location "http://127.0.0.1:5000/todos/1" \ +curl -X PATCH --location "http://127.0.0.1:5000/todos/1/" \ -H "Content-Type: application/json" \ -d "{ \"text\": \"Updated todo item\" @@ -87,7 +87,5 @@ curl -X PATCH --location "http://127.0.0.1:5000/todos/1" \ ### Delete ToDo Item ``` -curl -X DELETE --location "http://127.0.0.1:5000/todos/1" +curl -X DELETE --location "http://127.0.0.1:5000/todos/1/" ``` - - diff --git a/examples/01_authentication/README.md b/examples/01_authentication/README.md index 3327f22..3a6d8a9 100644 --- a/examples/01_authentication/README.md +++ b/examples/01_authentication/README.md @@ -22,6 +22,10 @@ curl to store/use cookies in order to test authenticated requests. `pipenv run python3 app.py` +## Swagger UI + +Go to [http://127.0.0.1:5000/apidocs/](http://127.0.0.1:5000/apidocs/) in a browser. + ## CURL Commands ### Login diff --git a/examples/02_pydantic/README.md b/examples/02_pydantic/README.md index 23bf380..aa0b73e 100644 --- a/examples/02_pydantic/README.md +++ b/examples/02_pydantic/README.md @@ -14,11 +14,15 @@ generated by Flask-Muck. `pipenv run python3 app.py` +## Swagger UI + +Go to [http://127.0.0.1:5000/apidocs/](http://127.0.0.1:5000/apidocs/) in a browser. + ## CURL Commands ### Create a ToDo item ``` -curl -X POST --location "http://127.0.0.1:5000/api/v1/todos" \ +curl -X POST --location "http://127.0.0.1:5000/todos/" \ -H "Content-Type: application/json" \ -d "{ \"text\": \"take out garbage again\" @@ -27,44 +31,44 @@ curl -X POST --location "http://127.0.0.1:5000/api/v1/todos" \ ### List all ToDo items (flat) ``` -curl -X GET --location "http://127.0.0.1:5000/api/v1/todos" \ +curl -X GET --location "http://127.0.0.1:5000/todos/" \ -d "Accept: application/json" ``` ### List all ToDo items (paginated) ``` -curl -X GET --location "http://127.0.0.1:5000/api/v1/todos?limit=2&offset=1" \ +curl -X GET --location "http://127.0.0.1:5000/todos/?limit=2&offset=1" \ -d "Accept: application/json" ``` ### Search ToDo items ``` -curl -X GET --location "http://127.0.0.1:5000/api/v1/todos?search=garbage" \ +curl -X GET --location "http://127.0.0.1:5000/todos/?search=garbage" \ -d "Accept: application/json" ``` ### Filter ToDo items ``` -curl -X GET --location "http://127.0.0.1:5000/api/v1/todos?filters=%7B%22text%22%3A+%22take+out+garbage+again%22%7D" \ +curl -X GET --location "http://127.0.0.1:5000/todos/?filters=%7B%22text%22%3A+%22take+out+garbage+again%22%7D" \ -d "Accept: application/json" ``` _querystring urldecodes to `filters={"text": "take out garbage again"}`_ ### Sort ToDo items ``` -curl -X GET --location "http://127.0.0.1:5000/api/v1/todos?sort=text" \ +curl -X GET --location "http://127.0.0.1:5000/todos/?sort=text" \ -d "Accept: application/json" ``` ### Fetch ToDo item ``` -curl -X GET --location "http://127.0.0.1:5000/api/v1/todos/1" \ +curl -X GET --location "http://127.0.0.1:5000/todos/1/" \ -d "Accept: application/json" ``` ### Update ToDo item ``` -curl -X PUT --location "http://127.0.0.1:5000/api/v1/todos/1" \ +curl -X PUT --location "http://127.0.0.1:5000/todos/1/" \ -H "Content-Type: application/json" \ -d "{ \"text\": \"Updated todo item\" @@ -73,7 +77,7 @@ curl -X PUT --location "http://127.0.0.1:5000/api/v1/todos/1" \ ### Patch ToDo item ``` -curl -X PATCH --location "http://127.0.0.1:5000/api/v1/todos/1" \ +curl -X PATCH --location "http://127.0.0.1:5000/todos/1/" \ -H "Content-Type: application/json" \ -d "{ \"text\": \"Updated todo item\" @@ -82,7 +86,5 @@ curl -X PATCH --location "http://127.0.0.1:5000/api/v1/todos/1" \ ### Delete ToDo Item ``` -curl -X DELETE --location "http://127.0.0.1:5000/api/v1/todos/1" +curl -X DELETE --location "http://127.0.0.1:5000/todos/1/" ``` - - diff --git a/examples/02_pydantic/app.py b/examples/02_pydantic/app.py index 5210735..f02adae 100644 --- a/examples/02_pydantic/app.py +++ b/examples/02_pydantic/app.py @@ -3,9 +3,11 @@ from pydantic import BaseModel from sqlalchemy.orm import DeclarativeBase -from flask_muck import FlaskMuckApiView +from flask_muck import FlaskMuckApiView, FlaskMuck app = Flask(__name__) +muck = FlaskMuck() +muck.init_app(app) class Base(DeclarativeBase): @@ -31,9 +33,6 @@ class TodoPayloadSchema(BaseModel): text: str -api_blueprint = Blueprint("v1_api", __name__, url_prefix="/api/v1/") - - class TodoApiView(FlaskMuckApiView): session = db.session api_name = "todos" @@ -45,10 +44,8 @@ class TodoApiView(FlaskMuckApiView): searchable_columns = [TodoModel.text] -TodoApiView.add_rules_to_blueprint(api_blueprint) -app.register_blueprint(api_blueprint) - if __name__ == "__main__": with app.app_context(): db.create_all() + muck.register_muck_views([TodoApiView]) app.run(debug=True) diff --git a/examples/03_add_to_existing_api/Pipfile b/examples/03_add_to_existing_api/Pipfile new file mode 100644 index 0000000..e0b6f7c --- /dev/null +++ b/examples/03_add_to_existing_api/Pipfile @@ -0,0 +1,18 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +flask = "*" +flask-sqlalchemy = "*" +pipenv = "*" +install = "*" +flask-muck = {file = "../.."} +webargs = "*" +pydantic = "*" + +[dev-packages] + +[requires] +python_version = "3.11" diff --git a/examples/03_add_to_existing_api/Pipfile.lock b/examples/03_add_to_existing_api/Pipfile.lock new file mode 100644 index 0000000..cf56cf2 --- /dev/null +++ b/examples/03_add_to_existing_api/Pipfile.lock @@ -0,0 +1,447 @@ +{ + "_meta": { + "hash": { + "sha256": "a137446d4a93a2481cf52fe6b24e256ac5d82a1f5aa88e7f4a04d08411175cca" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "annotated-types": { + "hashes": [ + "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43", + "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d" + ], + "markers": "python_version >= '3.8'", + "version": "==0.6.0" + }, + "blinker": { + "hashes": [ + "sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9", + "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182" + ], + "markers": "python_version >= '3.8'", + "version": "==1.7.0" + }, + "certifi": { + "hashes": [ + "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1", + "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" + ], + "markers": "python_version >= '3.6'", + "version": "==2023.11.17" + }, + "click": { + "hashes": [ + "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.7" + }, + "distlib": { + "hashes": [ + "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784", + "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64" + ], + "version": "==0.3.8" + }, + "filelock": { + "hashes": [ + "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e", + "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c" + ], + "markers": "python_version >= '3.8'", + "version": "==3.13.1" + }, + "flask": { + "hashes": [ + "sha256:21128f47e4e3b9d597a3e8521a329bf56909b690fcc3fa3e477725aa81367638", + "sha256:cfadcdb638b609361d29ec22360d6070a77d7463dcb3ab08d2c2f2f168845f58" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==3.0.0" + }, + "flask-muck": { + "file": "../..", + "markers": "python_version >= '3.9'" + }, + "flask-sqlalchemy": { + "hashes": [ + "sha256:4ba4be7f419dc72f4efd8802d69974803c37259dd42f3913b0dcf75c9447e0a0", + "sha256:e4b68bb881802dda1a7d878b2fc84c06d1ee57fb40b874d3dc97dabfa36b8312" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==3.1.1" + }, + "importlib-metadata": { + "hashes": [ + "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7", + "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67" + ], + "markers": "python_version < '3.10'", + "version": "==7.0.0" + }, + "install": { + "hashes": [ + "sha256:0d3fadf4aa62c95efe8d34757c8507eb46177f86c016c21c6551eafc6a53d5a9", + "sha256:e67c8a0be5ccf8cb4ffa17d090f3a61b6e820e6a7e21cd1d2c0f7bc59b18e647" + ], + "index": "pypi", + "markers": "python_version >= '2.7'", + "version": "==1.3.5" + }, + "itsdangerous": { + "hashes": [ + "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", + "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a" + ], + "markers": "python_version >= '3.7'", + "version": "==2.1.2" + }, + "jinja2": { + "hashes": [ + "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", + "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==3.1.3" + }, + "markupsafe": { + "hashes": [ + "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", + "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", + "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", + "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", + "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c", + "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", + "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", + "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb", + "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939", + "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", + "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", + "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", + "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", + "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", + "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", + "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", + "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd", + "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", + "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", + "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", + "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", + "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", + "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", + "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", + "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", + "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007", + "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", + "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", + "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", + "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", + "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", + "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", + "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", + "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1", + "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", + "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", + "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c", + "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", + "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823", + "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", + "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", + "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", + "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", + "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", + "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", + "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", + "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", + "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", + "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", + "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", + "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", + "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", + "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", + "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", + "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", + "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", + "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", + "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc", + "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2", + "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11" + ], + "markers": "python_version >= '3.7'", + "version": "==2.1.3" + }, + "marshmallow": { + "hashes": [ + "sha256:5d2371bbe42000f2b3fb5eaa065224df7d8f8597bc19a1bbfa5bfe7fba8da889", + "sha256:684939db93e80ad3561392f47be0230743131560a41c5110684c16e21ade0a5c" + ], + "markers": "python_version >= '3.8'", + "version": "==3.20.1" + }, + "packaging": { + "hashes": [ + "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", + "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + ], + "markers": "python_version >= '3.7'", + "version": "==23.2" + }, + "pipenv": { + "hashes": [ + "sha256:6eb537da5a27671f71dc596ea96a5b341aae9a1695413beeb95364467409bb3d", + "sha256:f587ffff47e8aa76f17803d571f64cf5a24b2bdfb9334435e6528b22ad5e304f" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2023.11.15" + }, + "platformdirs": { + "hashes": [ + "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380", + "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420" + ], + "markers": "python_version >= '3.8'", + "version": "==4.1.0" + }, + "pydantic": { + "hashes": [ + "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0", + "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==2.5.2" + }, + "pydantic-core": { + "hashes": [ + "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b", + "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b", + "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d", + "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8", + "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124", + "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189", + "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c", + "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d", + "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f", + "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520", + "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4", + "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6", + "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955", + "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3", + "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b", + "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a", + "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68", + "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3", + "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd", + "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de", + "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b", + "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634", + "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7", + "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459", + "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7", + "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3", + "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331", + "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf", + "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d", + "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36", + "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59", + "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937", + "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc", + "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093", + "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753", + "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706", + "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca", + "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260", + "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997", + "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588", + "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71", + "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb", + "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e", + "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69", + "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5", + "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07", + "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1", + "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0", + "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd", + "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8", + "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944", + "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26", + "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda", + "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4", + "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9", + "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00", + "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe", + "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6", + "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada", + "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4", + "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7", + "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325", + "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4", + "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b", + "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88", + "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04", + "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863", + "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0", + "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911", + "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b", + "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e", + "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144", + "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5", + "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720", + "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab", + "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d", + "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789", + "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec", + "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2", + "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db", + "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f", + "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef", + "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3", + "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209", + "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc", + "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651", + "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8", + "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e", + "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66", + "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7", + "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550", + "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd", + "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405", + "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27", + "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093", + "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077", + "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113", + "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3", + "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6", + "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf", + "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed", + "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88", + "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe", + "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18", + "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867" + ], + "markers": "python_version >= '3.7'", + "version": "==2.14.5" + }, + "setuptools": { + "hashes": [ + "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2", + "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6" + ], + "markers": "python_version >= '3.8'", + "version": "==69.0.2" + }, + "sqlalchemy": { + "hashes": [ + "sha256:0666031df46b9badba9bed00092a1ffa3aa063a5e68fa244acd9f08070e936d3", + "sha256:0a8c6aa506893e25a04233bc721c6b6cf844bafd7250535abb56cb6cc1368884", + "sha256:0e680527245895aba86afbd5bef6c316831c02aa988d1aad83c47ffe92655e74", + "sha256:14aebfe28b99f24f8a4c1346c48bc3d63705b1f919a24c27471136d2f219f02d", + "sha256:1e018aba8363adb0599e745af245306cb8c46b9ad0a6fc0a86745b6ff7d940fc", + "sha256:227135ef1e48165f37590b8bfc44ed7ff4c074bf04dc8d6f8e7f1c14a94aa6ca", + "sha256:31952bbc527d633b9479f5f81e8b9dfada00b91d6baba021a869095f1a97006d", + "sha256:3e983fa42164577d073778d06d2cc5d020322425a509a08119bdcee70ad856bf", + "sha256:42d0b0290a8fb0165ea2c2781ae66e95cca6e27a2fbe1016ff8db3112ac1e846", + "sha256:42ede90148b73fe4ab4a089f3126b2cfae8cfefc955c8174d697bb46210c8306", + "sha256:4895a63e2c271ffc7a81ea424b94060f7b3b03b4ea0cd58ab5bb676ed02f4221", + "sha256:4af79c06825e2836de21439cb2a6ce22b2ca129bad74f359bddd173f39582bf5", + "sha256:5f94aeb99f43729960638e7468d4688f6efccb837a858b34574e01143cf11f89", + "sha256:616fe7bcff0a05098f64b4478b78ec2dfa03225c23734d83d6c169eb41a93e55", + "sha256:62d9e964870ea5ade4bc870ac4004c456efe75fb50404c03c5fd61f8bc669a72", + "sha256:638c2c0b6b4661a4fd264f6fb804eccd392745c5887f9317feb64bb7cb03b3ea", + "sha256:63bfc3acc970776036f6d1d0e65faa7473be9f3135d37a463c5eba5efcdb24c8", + "sha256:6463aa765cf02b9247e38b35853923edbf2f6fd1963df88706bc1d02410a5577", + "sha256:64ac935a90bc479fee77f9463f298943b0e60005fe5de2aa654d9cdef46c54df", + "sha256:683ef58ca8eea4747737a1c35c11372ffeb84578d3aab8f3e10b1d13d66f2bc4", + "sha256:75eefe09e98043cff2fb8af9796e20747ae870c903dc61d41b0c2e55128f958d", + "sha256:787af80107fb691934a01889ca8f82a44adedbf5ef3d6ad7d0f0b9ac557e0c34", + "sha256:7c424983ab447dab126c39d3ce3be5bee95700783204a72549c3dceffe0fc8f4", + "sha256:7e0dc9031baa46ad0dd5a269cb7a92a73284d1309228be1d5935dac8fb3cae24", + "sha256:87a3d6b53c39cd173990de2f5f4b83431d534a74f0e2f88bd16eabb5667e65c6", + "sha256:89a01238fcb9a8af118eaad3ffcc5dedaacbd429dc6fdc43fe430d3a941ff965", + "sha256:9585b646ffb048c0250acc7dad92536591ffe35dba624bb8fd9b471e25212a35", + "sha256:964971b52daab357d2c0875825e36584d58f536e920f2968df8d581054eada4b", + "sha256:967c0b71156f793e6662dd839da54f884631755275ed71f1539c95bbada9aaab", + "sha256:9ca922f305d67605668e93991aaf2c12239c78207bca3b891cd51a4515c72e22", + "sha256:a86cb7063e2c9fb8e774f77fbf8475516d270a3e989da55fa05d08089d77f8c4", + "sha256:aeb397de65a0a62f14c257f36a726945a7f7bb60253462e8602d9b97b5cbe204", + "sha256:b41f5d65b54cdf4934ecede2f41b9c60c9f785620416e8e6c48349ab18643855", + "sha256:bd45a5b6c68357578263d74daab6ff9439517f87da63442d244f9f23df56138d", + "sha256:c14eba45983d2f48f7546bb32b47937ee2cafae353646295f0e99f35b14286ab", + "sha256:c1bda93cbbe4aa2aa0aa8655c5aeda505cd219ff3e8da91d1d329e143e4aff69", + "sha256:c4722f3bc3c1c2fcc3702dbe0016ba31148dd6efcd2a2fd33c1b4897c6a19693", + "sha256:c80c38bd2ea35b97cbf7c21aeb129dcbebbf344ee01a7141016ab7b851464f8e", + "sha256:cabafc7837b6cec61c0e1e5c6d14ef250b675fa9c3060ed8a7e38653bd732ff8", + "sha256:cc1d21576f958c42d9aec68eba5c1a7d715e5fc07825a629015fe8e3b0657fb0", + "sha256:d0f7fb0c7527c41fa6fcae2be537ac137f636a41b4c5a4c58914541e2f436b45", + "sha256:d4041ad05b35f1f4da481f6b811b4af2f29e83af253bf37c3c4582b2c68934ab", + "sha256:d5578e6863eeb998980c212a39106ea139bdc0b3f73291b96e27c929c90cd8e1", + "sha256:e3b5036aa326dc2df50cba3c958e29b291a80f604b1afa4c8ce73e78e1c9f01d", + "sha256:e599a51acf3cc4d31d1a0cf248d8f8d863b6386d2b6782c5074427ebb7803bda", + "sha256:f3420d00d2cb42432c1d0e44540ae83185ccbbc67a6054dcc8ab5387add6620b", + "sha256:f48ed89dd11c3c586f45e9eec1e437b355b3b6f6884ea4a4c3111a3358fd0c18", + "sha256:f508ba8f89e0a5ecdfd3761f82dda2a3d7b678a626967608f4273e0dba8f07ac", + "sha256:fd54601ef9cc455a0c61e5245f690c8a3ad67ddb03d3b91c361d076def0b4c60" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.23" + }, + "typing-extensions": { + "hashes": [ + "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", + "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + ], + "markers": "python_version >= '3.8'", + "version": "==4.9.0" + }, + "virtualenv": { + "hashes": [ + "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3", + "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b" + ], + "markers": "python_version >= '3.7'", + "version": "==20.25.0" + }, + "webargs": { + "hashes": [ + "sha256:69d7ac874d746b6f4f47eac923c2abf6fc7788dfca2ebcfd9f4ac52ec9646446", + "sha256:cab207941b0686c4d086c823632ddcd4343151644341a32fcf50b8eaa71e31c7" + ], + "index": "pypi", + "markers": "python_full_version >= '3.7.2'", + "version": "==8.3.0" + }, + "werkzeug": { + "hashes": [ + "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc", + "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10" + ], + "markers": "python_version >= '3.8'", + "version": "==3.0.1" + }, + "zipp": { + "hashes": [ + "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31", + "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0" + ], + "markers": "python_version >= '3.8'", + "version": "==3.17.0" + } + }, + "develop": {} +} diff --git a/examples/03_add_to_existing_api/README.md b/examples/03_add_to_existing_api/README.md new file mode 100644 index 0000000..7374a30 --- /dev/null +++ b/examples/03_add_to_existing_api/README.md @@ -0,0 +1,93 @@ +# Adding Flask-Muck To An Existing API Example + +It's very likely you'll need to add Flask-Muck to an existing Flask API. This example shows how to use the utility +methods to incorporate Flask-Muck into existing api blueprints and bypass the extension. + +This example results in the same API as the Quickstart without initializing the extension. + +Below are instruction on running the sample app as well as a list of CURL commands demonstrating the endpoints +generated by Flask-Muck. + +## Prequisites + +- [Python 3.11](https://www.python.org/downloads/) +- [pipenv](https://pipenv.pypa.io/en/latest/#install-pipenv-today) + +## Start The REST API. + +`pipenv run python3 app.py` + +## Swagger UI + +Go to [http://127.0.0.1:5000/apidocs/](http://127.0.0.1:5000/apidocs/) in a browser. + +## CURL Commands + +### Create a ToDo item +``` +curl -X POST --location "http://127.0.0.1:5000/todos/" \ + -H "Content-Type: application/json" \ + -d "{ + \"text\": \"take out garbage again\" + }" +``` + +### List all ToDo items (flat) +``` +curl -X GET --location "http://127.0.0.1:5000/todos/" \ + -d "Accept: application/json" +``` + +### List all ToDo items (paginated) +``` +curl -X GET --location "http://127.0.0.1:5000/todos/?limit=2&offset=1" \ + -d "Accept: application/json" +``` + +### Search ToDo items +``` +curl -X GET --location "http://127.0.0.1:5000/todos/?search=garbage" \ + -d "Accept: application/json" +``` + +### Filter ToDo items +``` +curl -X GET --location "http://127.0.0.1:5000/todos/?filters=%7B%22text%22%3A+%22take+out+garbage+again%22%7D" \ + -d "Accept: application/json" +``` +_querystring urldecodes to `filters={"text": "take out garbage again"}`_ + +### Sort ToDo items +``` +curl -X GET --location "http://127.0.0.1:5000/todos/?sort=text" \ + -d "Accept: application/json" +``` + +### Fetch ToDo item +``` +curl -X GET --location "http://127.0.0.1:5000/todos/1/" \ + -d "Accept: application/json" +``` + +### Update ToDo item +``` +curl -X PUT --location "http://127.0.0.1:5000/todos/1/" \ + -H "Content-Type: application/json" \ + -d "{ + \"text\": \"Updated todo item\" + }" +``` + +### Patch ToDo item +``` +curl -X PATCH --location "http://127.0.0.1:5000/todos/1/" \ + -H "Content-Type: application/json" \ + -d "{ + \"text\": \"Updated todo item\" + }" +``` + +### Delete ToDo Item +``` +curl -X DELETE --location "http://127.0.0.1:5000/todos/1/" +``` diff --git a/examples/03_add_to_existing_api/app.py b/examples/03_add_to_existing_api/app.py new file mode 100644 index 0000000..7ebd743 --- /dev/null +++ b/examples/03_add_to_existing_api/app.py @@ -0,0 +1,64 @@ +import marshmallow as ma +from flask import Flask, Blueprint +from flask_sqlalchemy import SQLAlchemy +from marshmallow import fields as mf +from sqlalchemy.orm import DeclarativeBase + +from flask_muck import FlaskMuckApiView + +app = Flask(__name__) + + +class Base(DeclarativeBase): + pass + + +db = SQLAlchemy(model_class=Base) +app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///todo_example.db" +db.init_app(app) + + +class TodoModel(db.Model): + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + text = db.Column(db.String, nullable=False) + + +class TodoSchema(ma.Schema): + """ToDo model schema that can be used for CRUD operations.""" + + id = mf.Integer(required=True, dump_only=True) + text = mf.String(required=True) + + +class BaseApiView(FlaskMuckApiView): + """Base view to inherit from. Helpful for setting class variables shared with all API views such as "session" + and "decorators". + """ + + session = db.session + + +class TodoApiView(BaseApiView): + """ToDo API view that provides all RESTful CRUD operations.""" + + api_name = "todos" + Model = TodoModel + ResponseSchema = TodoSchema + CreateSchema = TodoSchema + PatchSchema = TodoSchema + UpdateSchema = TodoSchema + searchable_columns = [TodoModel.text] + + +# This is the existing api blueprint where all other routes are registered. +api_blueprint = Blueprint("v1_api", __name__, url_prefix="/") + +# Use add_rules_to_blueprint classmethod on the FlaskMuckApiView to add all the CRUD route rules to the existing blueprint. +TodoApiView.add_rules_to_blueprint(api_blueprint) + +app.register_blueprint(api_blueprint) + +if __name__ == "__main__": + with app.app_context(): + db.create_all() + app.run(debug=True)