{"id":13753737,"url":"https://github.com/frol/flask-restplus-server-example","last_synced_at":"2025-05-15T20:03:27.200Z","repository":{"id":47792430,"uuid":"46421329","full_name":"frol/flask-restplus-server-example","owner":"frol","description":"Real-life RESTful server example on Flask-RESTplus","archived":false,"fork":false,"pushed_at":"2023-11-27T02:17:27.000Z","size":1534,"stargazers_count":1342,"open_issues_count":20,"forks_count":337,"subscribers_count":61,"default_branch":"master","last_synced_at":"2025-05-15T20:03:24.457Z","etag":null,"topics":["database-migrations","docker","example-project","flask","flask-restplus","marshmallow","oauth2","openapi","password-flow","pyinvoke","python","rest-api","swagger"],"latest_commit_sha":null,"homepage":"http://flask-restplus-example-server.herokuapp.com/api/v1/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/frol.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-11-18T13:43:34.000Z","updated_at":"2025-04-29T15:26:03.000Z","dependencies_parsed_at":"2022-09-02T06:54:20.096Z","dependency_job_id":"43e91758-15c9-4232-a3f6-6894d446701b","html_url":"https://github.com/frol/flask-restplus-server-example","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frol%2Fflask-restplus-server-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frol%2Fflask-restplus-server-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frol%2Fflask-restplus-server-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frol%2Fflask-restplus-server-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/frol","download_url":"https://codeload.github.com/frol/flask-restplus-server-example/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254414493,"owners_count":22067271,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database-migrations","docker","example-project","flask","flask-restplus","marshmallow","oauth2","openapi","password-flow","pyinvoke","python","rest-api","swagger"],"created_at":"2024-08-03T09:01:28.468Z","updated_at":"2025-05-15T20:03:25.285Z","avatar_url":"https://github.com/frol.png","language":"Python","readme":"[![Build Status](https://travis-ci.org/frol/flask-restplus-server-example.svg)](https://travis-ci.org/frol/flask-restplus-server-example)\n[![Coverage Status](https://coveralls.io/repos/frol/flask-restplus-server-example/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/frol/flask-restplus-server-example?branch=master)\n[![Codacy Coverage Status](https://api.codacy.com/project/badge/coverage/b0fc91ce77d3437ea5f107c4b7ccfa26)](https://www.codacy.com/app/frolvlad/flask-restplus-server-example)\n[![Codacy Quality Status](https://api.codacy.com/project/badge/grade/b0fc91ce77d3437ea5f107c4b7ccfa26)](https://www.codacy.com/app/frolvlad/flask-restplus-server-example)\n[![Heroku](http://heroku-badge.herokuapp.com/?app=flask-restplus-example-server\u0026root=api/v1/\u0026style=flat\u0026svg=1)](http://flask-restplus-example-server.herokuapp.com/api/v1/)\n\n\nRESTful API Server Example\n==========================\n\nThis project showcases my vision on how the RESTful API server should be\nimplemented.\n\n\u003e **Author's vision update!**\n\u003e\n\u003e I used to use RESTful style APIs for quite a number of projects and this\n\u003e example was the finest foundation I ended up with, but I always felt\n\u003e limited by HTTP request-response nature and RESTful resources. Thus, I was\n\u003e looking for a new solution to the API problem space. I am currently happy\n\u003e with [WAMP-proto](https://wamp-proto.org/) specification\n\u003e ([here is my barebones demo](https://github.com/frol/wamp-demo)), so I can\n\u003e recommend it. I have also switched to Rust programming language. I am\n\u003e currently working on async/await-powered implementation of WAMP-proto in\n\u003e Rust. Stay tuned!\n\nThe goals that were achived in this example:\n\n* RESTful API server should be self-documented using OpenAPI (fka Swagger)\n  specifications, so interactive documentation UI is in place;\n* Authentication is handled with OAuth2 and using Resource Owner Password\n  Credentials Grant (Password Flow) for first-party clients makes it usable\n  not only for third-party \"external\" apps;\n* Permissions are handled (and automaticaly documented);\n* PATCH method can be handled accordingly to\n  [RFC 6902](http://tools.ietf.org/html/rfc6902);\n* Extensive testing with good code coverage.\n\nI had to patch Flask-RESTplus (see `flask_restplus_patched` folder), so it can\nhandle Marshmallow schemas and Webargs arguments.\n\nHere is how it looks at this point of time ([live demo](http://flask-restplus-example-server.herokuapp.com/api/v1/)):\n\n![Flask RESTplus Example API](https://raw.githubusercontent.com/frol/flask-restplus-server-example/master/docs/static/Flask_RESTplus_Example_API.png)\n\n\nSingle File Example\n-------------------\n\nThis example should give you a basic understanding of what you can get with\nFlask, SQLAlchemy, Marshmallow, Flask-RESTplus (+ my patched extension), and\nOpenAPI.\n\n```python\nfrom flask import Flask\nfrom flask_sqlalchemy import SQLAlchemy\nfrom flask_restplus_patched import Api, Namespace, Resource, ModelSchema\n\n# Extensions initialization\n# =========================\napp = Flask(__name__)\ndb = SQLAlchemy(app)\napi = Api(app)\n\n\n# Database table definition (SQLAlchemy)\n# ======================================\nclass User(db.Model):\n    id = db.Column(db.Integer, primary_key=True)\n    name = db.Column(db.String(), nullable=False)\n\n\n# Serialization/Deserialization schema definition\n# ===============================================\nclass UserSchema(ModelSchema):\n    class Meta:\n        model = User\n\n\n# \"Users\" resource RESTful API definitions\n# ========================================\nusers_api = Namespace('users')\napi.add_namespace(users_api)\n\n@users_api.route('/')\nclass UsersList(Resource):\n\n    @users_api.response(UserSchema(many=True))\n    def get(self):\n        return User.query.all()\n\n\n@users_api.route('/\u003cint:user_id\u003e')\n@users_api.resolve_object('user', lambda kwargs: User.query.get_or_404(kwargs.pop('user_id')))\nclass UserByID(Resource):\n\n    @users_api.response(UserSchema())\n    def get(self, user):\n        return user\n\n\n# Run the RESTful API server\n# ==========================\nif __name__ == '__main__':\n    db.create_all()\n    with db.session.begin(nested=True):\n        db.session.add(User(name='user1'))\n        db.session.add(User(name='user2'))\n    app.run()\n```\n\nSave it, install the dependencies, and run it:\n\n```\n$ pip install -r app/requirements.txt\n$ python server.py\n```\n\nOpen http://127.0.0.1:5000 and examine the interactive documentation for your\nnew RESTful API server! You can use any HTTP tools (e.g. `cURL`, `wget`,\nPython `requests`, or just a web browser) to communicate with it, or generate\nspecialized API client libraries for many programming languages using\n[Swagger Codegen](https://github.com/swagger-api/swagger-codegen) (learn more\nin the [API Integration](#api-integration) section).\n\nNote, this whole repo features much more than that; it demonstrates how I would\norganize a production-ready RESTful API server *project*, so stay tunned.\n\n\nProject Structure\n-----------------\n\n### Root folder\n\nFolders:\n\n* `app` - This RESTful API Server example implementation is here.\n* `flask_restplus_patched` - There are some patches for Flask-RESTPlus (read\n  more in *Patched Dependencies* section).\n* `migrations` - Database migrations are stored here (see `invoke --list` to\n  learn available commands, and learn more about PyInvoke usage below).\n* `tasks` - [PyInvoke](http://www.pyinvoke.org/) commands are implemented here.\n* `tests` - These are [pytest](http://pytest.org) tests for this RESTful API\n  Server example implementation.\n* `docs` - It contains just images for the README, so you can safely ignore it.\n* `deploy` - It contains some application stack examples.\n\nFiles:\n\n* `README.md`\n* `config.py` - This is a config file of this RESTful API Server example.\n* `conftest.py` - A top-most pytest config file (it is empty, but it [helps to\n  have a proper PYTHON PATH](http://stackoverflow.com/a/20972950/1178806)).\n* `.coveragerc` - [Coverage.py](http://coverage.readthedocs.org/) (code\n  coverage) config for code coverage reports.\n* `.travis.yml` - [Travis CI](https://travis-ci.org/) (automated continuous\n  integration) config for automated testing.\n* `.pylintrc` - [Pylint](https://www.pylint.org/) config for code quality\n  checking.\n* `Dockerfile` - Docker config file which is used to build a Docker image\n  running this RESTful API Server example.\n* `.dockerignore` - Lists files and file masks of the files which should be\n  ignored while Docker build process.\n* `.gitignore` - Lists files and file masks of the files which should not be\n  added to git repository.\n* `LICENSE` - MIT License, i.e. you are free to do whatever is needed with the\n  given code with no limits.\n\n### Application Structure\n\n```\napp/\n├── requirements.txt\n├── __init__.py\n├── extensions\n│   └── __init__.py\n└── modules\n    ├── __init__.py\n    ├── api\n    │   └── __init__.py\n    ├── auth\n    │   ├── __init__.py\n    │   ├── models.py\n    │   ├── parameters.py\n    │   └── views.py\n    ├── users\n    │   ├── __init__.py\n    │   ├── models.py\n    │   ├── parameters.py\n    │   ├── permissions.py\n    │   ├── resources.py\n    │   └── schemas.py\n    └── teams\n        ├── __init__.py\n        ├── models.py\n        ├── parameters.py\n        ├── resources.py\n        └── schemas.py\n```\n\n* `app/requirements.txt` - The list of Python (PyPi) requirements.\n* `app/__init__.py` - The entrypoint to this RESTful API Server example\n  application (Flask application is created here).\n* `app/extensions` - All extensions (e.g. SQLAlchemy, OAuth2) are initialized\n  here and can be used in the application by importing as, for example,\n  `from app.extensions import db`.\n* `app/modules` - All endpoints are expected to be implemented here in logicaly\n  separated modules. It is up to you how to draw the line to separate concerns\n  (e.g. you can implement a monolith `blog` module, or split it into\n  `topics`+`comments` modules).\n\n### Module Structure\n\nOnce you added a module name into `config.ENABLED_MODULES`, it is required to\nhave `your_module.init_app(app, **kwargs)` function. Everything else is\ncompletely optional. Thus, here is the required minimum:\n\n```\nyour_module/\n└── __init__.py\n```\n\n, where `__init__.py` will look like this:\n\n```python\ndef init_app(app, **kwargs):\n    pass\n```\n\nIn this example, however, `init_app` imports `resources` and registeres `api`\n(an instance of (patched) `flask_restplus.Namespace`). Learn more about the\n\"big picture\" in the next section.\n\n\nWhere to start reading the code?\n--------------------------------\n\nThe easiest way to start the application is by using PyInvoke command `app.run`\nimplemented in [`tasks/app/run.py`](tasks/app/run.py):\n\n```\n$ invoke app.run\n```\n\nThe command creates an application by running\n[`app/__init__.py:create_app()`](app/__init__.py) function, which in its turn:\n\n1. loads an application config;\n2. initializes extensions:\n   [`app/extensions/__init__.py:init_app()`](app/extensions/__init__.py);\n3. initializes modules:\n   [`app/modules/__init__.py:init_app()`](app/modules/__init__.py).\n\nModules initialization calls `init_app()` in every enabled module\n(listed in `config.ENABLED_MODULES`).\n\nLet's take `teams` module as an example to look further.\n[`app/modules/teams/__init__.py:init_app()`](app/modules/teams/__init__.py)\nimports and registers `api` instance of (patched) `flask_restplus.Namespace`\nfrom `.resources`. Flask-RESTPlus `Namespace` is designed to provide similar\nfunctionality as Flask `Blueprint`.\n\n[`api.route()`](app/modules/teams/resources.py) is used to bind a\nresource (classes inherited from `flask_restplus.Resource`) to a specific\nroute.\n\nLastly, every `Resource` should have methods which are lowercased HTTP method\nnames (i.e. `.get()`, `.post()`, etc). This is where users' requests end up.\n\n\nDependencies\n------------\n\n### Project Dependencies\n\n* [**Python**](https://www.python.org/) 2.7, 3.5+ / pypy2 (2.5.0)\n* [**flask-restplus**](https://github.com/noirbizarre/flask-restplus) (+\n  [*flask*](http://flask.pocoo.org/))\n* [**sqlalchemy**](http://www.sqlalchemy.org/) (+\n  [*flask-sqlalchemy*](http://flask-sqlalchemy.pocoo.org/)) - Database ORM.\n* [**sqlalchemy-utils**](https://sqlalchemy-utils.rtdf.org/) - for nice\n  custom fields (e.g., `PasswordField`).\n* [**alembic**](https://alembic.rtdf.org/) - for DB migrations.\n* [**marshmallow**](http://marshmallow.rtfd.org/) (+\n  [*marshmallow-sqlalchemy*](http://marshmallow-sqlalchemy.rtfd.org/),\n  [*flask-marshmallow*](http://flask-marshmallow.rtfd.org/)) - for\n  schema definitions. (*supported by the patched Flask-RESTplus*)\n* [**webargs**](http://webargs.rtfd.org/) - for parameters (input arguments).\n  (*supported by the patched Flask-RESTplus*)\n* [**apispec**](http://apispec.rtfd.org/) - for *marshmallow* and *webargs*\n  introspection. (*integrated into the patched Flask-RESTplus*)\n* [**oauthlib**](http://oauthlib.rtfd.org/) (+\n  [*flask-oauthlib*](http://flask-oauthlib.rtfd.org/)) - for authentication.\n* [**flask-login**](http://flask-login.rtfd.org/) - for `current_user`\n  integration only.\n* [**bcrypt**](https://github.com/pyca/bcrypt/) - for password hashing (used as\n  a backend by *sqlalchemy-utils.PasswordField*).\n* [**permission**](https://github.com/hustlzp/permission) - for authorization.\n* [**Swagger-UI**](https://github.com/swagger-api/swagger-ui) - for interactive\n  RESTful API documentation.\n\n### Build Dependencies\n\nI use [`pyinvoke`](http://pyinvoke.org) with custom tasks to maintain easy and\nnice command-line interface. Thus, it is required to have `invoke` Python\npackage installed, and optionally you may want to install `colorlog`, so your\nlife become colorful.\n\n### Patched Dependencies\n\n* **flask-restplus** is patched to handle marshmallow schemas and webargs\n  input parameters\n  ([GH #9](https://github.com/noirbizarre/flask-restplus/issues/9)).\n* **swagger-ui** (*the bundle is automatically downloaded on the first run*)\n  just includes a pull-request to support Resource Owner Password Credentials\n  Grant OAuth2 (aka Password Flow)\n  ([PR #1853](https://github.com/swagger-api/swagger-ui/pull/1853)).\n\n\nInstallation\n------------\n\n### Using Docker\n\nIt is very easy to start exploring the example using Docker:\n\n```bash\n$ docker run -it --rm --publish 5000:5000 frolvlad/flask-restplus-server-example\n```\n\n[![](https://images.microbadger.com/badges/image/frolvlad/flask-restplus-server-example.svg)](http://microbadger.com/images/frolvlad/flask-restplus-server-example \"Get your own image badge on microbadger.com\")\n\n\n### From sources\n\n#### Clone the Project\n\n```bash\n$ git clone https://github.com/frol/flask-restplus-server-example.git\n```\n\n#### Setup Environment\n\nIt is recommended to use virtualenv or Anaconda/Miniconda to manage Python\ndependencies. Please, learn details yourself.\n\nYou will need `invoke` package to work with everything related to this project.\n\n```bash\n$ pip install -r tasks/requirements.txt\n```\n\n\n#### Run Server\n\nNOTE: All dependencies and database migrations will be automatically handled,\nso go ahead and turn the server ON! (Read more details on this in Tips section)\n\n```bash\n$ invoke app.run\n```\n\n#### Deploy Server\n\nIn general, you deploy this app as any other Flask/WSGI application. There are\na few basic deployment strategies documented in the [`./deploy/`](./deploy/)\nfolder.\n\n\nQuickstart\n----------\n\nOpen online interactive API documentation:\n[http://127.0.0.1:5000/api/v1/](http://127.0.0.1:5000/api/v1/)\n\nAutogenerated swagger config is always available from\n[http://127.0.0.1:5000/api/v1/swagger.json](http://127.0.0.1:5000/api/v1/swagger.json)\n\n`example.db` (SQLite) includes 2 users:\n\n* Admin user `root` with password `q`\n* Regular user `user` with password `w`\n\nNOTE: Use On/Off switch in documentation to sign in.\n\n\nAuthentication Details\n----------------------\n\nThis example server features OAuth2 Authentication protocol support, but don't\nbe afraid of it! If you learn it, OAuth2 will save you from a lot of troubles.\n\n### Authentication with Login and Password (Resource Owner Password Credentials Grant)\n\nHere is how you authenticate with user login and password credentials using cURL:\n\n```\n$ curl 'http://127.0.0.1:5000/auth/oauth2/token?grant_type=password\u0026client_id=documentation\u0026username=root\u0026password=q'\n{\n    \"token_type\": \"Bearer\",\n    \"access_token\": \"oqvUpO4aKg5KgYK2EUY2HPsbOlAyEZ\",\n    \"refresh_token\": \"3UTjLPlnomJPx5FvgsC2wS7GfVNrfH\",\n    \"expires_in\": 3600,\n    \"scope\": \"auth:read auth:write users:read users:write teams:read teams:write\"\n}\n```\n\nThat is it!\n\nWell, the above request uses query parameters to pass client ID, user login and\npassword which is not recommended (even discouraged) for production use since\nmost of the web servers logs the requested URLs in plain text and we don't want\nto leak sensitive data this way.  Thus, in practice you would use form\nparameters to pass credentials:\n\n```\n$ curl 'http://127.0.0.1:5000/auth/oauth2/token?grant_type=password' -F 'client_id=documentation' -F 'username=root' -F 'password=q'\n```\n\n, or even pass `client_id` as Basic HTTP Auth:\n\n```\n$ curl 'http://127.0.0.1:5000/auth/oauth2/token?grant_type=password' --user 'documentation:' -F 'username=root' -F 'password=q'\n```\n\nYou grab the `access_token` and put it into `Authorization` header\nto request \"protected\" resources:\n\n```\n$ curl --header 'Authorization: Bearer oqvUpO4aKg5KgYK2EUY2HPsbOlAyEZ' 'http://127.0.0.1:5000/api/v1/users/me'\n{\n    \"id\": 1,\n    \"username\": \"root\",\n    \"email\": \"root@localhost\",\n    \"first_name\": \"\",\n    \"middle_name\": \"\",\n    \"last_name\": \"\",\n    \"is_active\": true,\n    \"is_regular_user\": true,\n    \"is_admin\": true,\n    \"created\": \"2016-10-20T14:00:35.912576+00:00\",\n    \"updated\": \"2016-10-20T14:00:35.912602+00:00\"\n}\n```\n\nOnce the access token expires, you can refresh it with `refresh_token`. To do\nthat, OAuth2 RFC defines Refresh Token Flow (notice that there is no need to\nstore user credentials to do the refresh procedure):\n\n```\n$ curl 'http://127.0.0.1:5000/auth/oauth2/token?grant_type=refresh_token' --user 'documentation:' -F 'refresh_token=3UTjLPlnomJPx5FvgsC2wS7GfVNrfH'\n{\n    \"token_type\": \"Bearer\",\n    \"access_token\": \"FwaS90XWwBpM1sLeAytaGGTubhHaok\",\n    \"refresh_token\": \"YD5Rc1FojKX1ZY9vltMSnFxhm9qpbb\",\n    \"expires_in\": 3600,\n    \"scope\": \"auth:read auth:write users:read users:write teams:read teams:write\"\n}\n```\n\n### Authentication with Client ID and Secret (Client Credentials Grant)\n\nHere is how you authenticate with user login and password credentials using cURL:\n\n```\n$ curl 'http://127.0.0.1:5000/auth/oauth2/token?grant_type=client_credentials' --user 'documentation:KQ()SWK)SQK)QWSKQW(SKQ)S(QWSQW(SJ*HQ\u0026HQW*SQ*^SSQWSGQSG'\n{\n    \"token_type\": \"Bearer\",\n    \"access_token\": \"oqvUpO4aKg5KgYK2EUY2HPsbOlAyEZ\",\n    \"expires_in\": 3600,\n    \"scope\": \"teams:read users:read users:write teams:write\"\n}\n```\n\nThe same way as in the previous section, you can grab the `access_token` and\naccess protected resources.\n\n\nAPI Integration\n---------------\n\nOne of the key point of using OpenAPI (Swagger) specification is that it\nenables automatic code generation.\n[Swagger Codegen project](https://github.com/swagger-api/swagger-codegen)\nimplements client library and server stub generators for over 18\nprogramming languages! There are also many other projects with OpenAPI\nspecification support, so if you lack anything in the official tooling,\nsearch for third-party solutions.\n\nI have had a need to work with my API servers from Python and JavaScript, so\nI started with Swagger Codegen Python and JavaScript generators. Very soon I\nrealized that most (if not all) Swagger Codegen generators lack OAuth2 support,\nbut other than that, the client libraries look fine (I have contributed a few\nchanges to Python and JavaScript generators over the time, and the nice thing\nall the clients benefit from contributions into a single project). Thus,\n@khorolets and I implemented hacky OAuth2 support for Python client and even\nmore hacky out-of-client helpers for JavaScript (hopefully, one day OAuth2\nsupport will be contributed into the Swagger Codegen upstream).\n\nTo use Swagger Codegen, you only need a `swagger.json` file describing your API\nserver. You can get one by accessing http://127.0.0.1:5000/api/v1/swagger.json,\nor by running an Invoke task:\n\n```bash\n$ invoke app.swagger\n```\n\nNOTE: Use stdout rediction to save the output into a file.\n\nTo further simplify the codegeneration, there is another Invoke task:\n\n```bash\n$ invoke app.swagger.codegen --language python --version 1.0.0\n```\n\nTo run that, however, you will need Docker installed on your machine since we\nuse Swagger Codegen as a Docker image. Once that is completed, you will have a\nPython client in the `clients/python/dist/` folder. The `javascript` client can\nbe generated just the same way. Read the generated `clients/*/dist/README.md`\nto learn how to use those clients.\n\nNOTE: As mentioned above, a slightly modified Swagger Codegen version is used\nto enable OAuth2 support in Python client.\n\n\nIntegrations with Flask-* Projects\n----------------------------------\n\nSince this project is only an extension to Flask, most (if not all) Flask\nplugins should work.\n\nVerified compatible projects:\n* flask-sqlalchemy\n* flask-login\n* flask-marshmallow\n* flask-oauthlib\n* flask-cors\n* flask-limiter\n\n### Example integration steps\n  \n#### flask-limiter\n\n1. Add `flask-limiter` to end of the `app/requirements.txt` file, so it gets\ninstalled when the application is deployed.\n2. Apply the relevant changes to `app/extensions/__init__.py`:\n\n    ```python\n    # ... other imports.\n\n    from flask_limiter import Limiter\n    from flask_limiter.util import get_remote_address\n\n    # change limiter configs per your project needs.\n    limiter = Limiter(key_func=get_remote_address, default_limits=[\"1 per minute\"])\n\n    from . import api\n\n    def init_app(app):\n        \"\"\"\n        Application extensions initialization.\n        \"\"\"\n        for extension in (\n                # ... other extensions.\n                limiter,  # Add this\n            ):\n            extension.init_app(app)\n    ```\n3. (Optional) Set endpoint-specific limits:\n\n    ```python\n    from app.extensions import limiter\n\n    @api.route('/account/verify')\n    class IdentityVerify(Resource):\n        \"\"\"\n        Handle identity verification.\n        \"\"\"\n        # Notice this is different from the simple example at the top of flask-limiter doc page.\n        # The reason is explained here: https://flask-limiter.readthedocs.io/en/stable/#using-flask-pluggable-views\n        decorators = [limiter.limit(\"10/second\")] # config as you need. \n\n        @api.parameters(parameters.SomeParameters())\n        @api.response(schemas.SomeSchema())\n        def post(self, args):\n            return {\"verified\": True}\n    ```\n\n\nTips\n----\n\nOnce you have invoke, you can learn all available commands related to this\nproject from:\n\n```bash\n$ invoke --list\n```\n\nLearn more about each command with the following syntax:\n\n```bash\n$ invoke --help \u003ctask\u003e\n```\n\nFor example:\n\n```bash\n$ invoke --help app.run\nUsage: inv[oke] [--core-opts] app.run [--options] [other tasks here ...]\n\nDocstring:\n  Run DDOTS RESTful API Server.\n\nOptions:\n  -d, --[no-]development\n  -h STRING, --host=STRING\n  -i, --[no-]install-dependencies\n  -p, --port\n  -u, --[no-]upgrade-db\n```\n\nUse the following command to enter ipython shell (`ipython` must be installed):\n\n```bash\n$ invoke app.env.enter\n```\n\n`app.run` and `app.env.enter` tasks automatically prepare all dependencies\n(using `pip install`) and migrate database schema to the latest version.\n\nDatabase schema migration is handled via `app.db.*` tasks group. The most\ncommon migration commands are `app.db.upgrade` (it is automatically run on\n`app.run`), and `app.db.migrate` (creates a new migration).\n\nYou can use [`better_exceptions`](https://github.com/Qix-/better-exceptions)\npackage to enable detailed tracebacks. Just add `better_exceptions` to the\n`app/requirements.txt` and `import better_exceptions` in the `app/__init__.py`.\n\n\nMarshmallow Tricks\n------------------\n\nThere are a few helpers already available in the `flask_restplus_patched`:\n\n* `flask_restplus_patched.parameters.Parameters` - base class, which is a thin\n  wrapper on top of Marshmallow Schema.\n* `flask_restplus_patched.parameters.PostFormParameters` - a helper class,\n  which automatically mark all the fields that has no explicitly defined\n  location to be form data parameters.\n* `flask_restplus_patched.parameters.PatchJSONParameters` - a helper class for\n  the common use-case of [RFC 6902](http://tools.ietf.org/html/rfc6902)\n  describing JSON PATCH.\n* `flask_restplus_patched.namespace.Namespace.parameters` - a helper decorator,\n  which automatically handles and documents the passed `Parameters`.\n\nYou can find the examples of the usage throughout the code base (in\n`/app/modules/*`).\n\n\n### JSON Parameters\n\nWhile there is an implementation for JSON PATCH Parameters, there are other\nuse-cases, where you may need to handle JSON as input parameters. Naturally,\nJSON input is just a form data body text which is treated as JSON on a server\nside, so you only need define a single variable called `body` with\n`location='json'`:\n\n```python\nclass UserSchema(Schema):\n    id = base_fields.Integer(required=False)\n    username = base_fields.String(required=True)\n\n\nclass MyObjectSchema(Schema):\n    id = base_fields.Integer(required=True)\n    priority = base_fields.String(required=True)\n    owner = base_fields.Nested(UserSchema, required=False)\n\n\nclass CreateMyObjectParameters(Parameters):\n    body = base_fields.Nested(MyObjectSchema, location='json', required=True)\n\n\napi = Namespace('my-objects-controller', description=\"My Objects Controller\", path='/my-objects')\n\n\n@api.route('/')\nclass MyObjects(Resource):\n    \"\"\"\n    Manipulations with My Objects.\n    \"\"\"\n\n    @api.parameters(CreateMyObjectParameters())\n    @api.response(MyObjectSchema())\n    @api.response(code=HTTPStatus.CONFLICT)\n    @api.doc(id='create_my_object')\n    def post(self, args):\n        \"\"\"\n        Create a new My Object.\n        \"\"\"\n        return create_my_object(args)\n```\n\n\nUseful Links\n============\n\n* [Q\u0026A about this project](https://github.com/frol/flask-restplus-server-example/issues?utf8=%E2%9C%93\u0026q=is%3Aissue+label%3Aquestion)\n* [Valuable extensions that didn't make into the upstream](https://github.com/frol/flask-restplus-server-example/issues?utf8=%E2%9C%93\u0026q=label%3Aextension)\n* \"[The big Picture](https://identityserver.github.io/Documentation/docsv2/overview/bigPicture.html)\" -\n  short yet complete idea about how the modern apps should talk.\n* \"[Please. Don't PATCH Like An Idiot.](http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/)\"\n* \"[A Concise RESTful API Design Guide](https://twincl.com/programming/*6af/rest-api-design)\"\n* \"[Best Practices for Designing a Pragmatic RESTful API](http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api)\"\n* \"[My take on RESTful authentication](https://facundoolano.wordpress.com/2013/12/23/my-take-on-restful-authentication/)\"\n* \"[Is it normal design to completely decouple backend and frontend web applications and allow them to communicate with (JSON) REST API?](http://softwareengineering.stackexchange.com/questions/337467/is-it-normal-design-to-completely-decouple-backend-and-frontend-web-applications)\"\n","funding_links":[],"categories":["swagger"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrol%2Fflask-restplus-server-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffrol%2Fflask-restplus-server-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrol%2Fflask-restplus-server-example/lists"}