{"id":15374129,"url":"https://github.com/mtnbarreto/flask-base-api","last_synced_at":"2025-04-15T11:31:54.612Z","repository":{"id":39848278,"uuid":"134873589","full_name":"mtnbarreto/flask-base-api","owner":"mtnbarreto","description":"A complete boilerplate Flask RESTful API code. ","archived":false,"fork":false,"pushed_at":"2024-01-11T20:53:54.000Z","size":1229,"stargazers_count":63,"open_issues_count":2,"forks_count":25,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-28T20:51:20.732Z","etag":null,"topics":["flask","flask-backend","rest-api","restful-api"],"latest_commit_sha":null,"homepage":"https://xmartlabs.com","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/mtnbarreto.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":"2018-05-25T15:25:08.000Z","updated_at":"2025-03-10T16:50:49.000Z","dependencies_parsed_at":"2024-11-08T11:00:52.012Z","dependency_job_id":"5fe0d7d9-3072-4fea-8be8-f4a31931d9b4","html_url":"https://github.com/mtnbarreto/flask-base-api","commit_stats":{"total_commits":103,"total_committers":5,"mean_commits":20.6,"dds":0.3786407766990292,"last_synced_commit":"6b9657bd9c22f583798bb99e9fd007c7e9032325"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtnbarreto%2Fflask-base-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtnbarreto%2Fflask-base-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtnbarreto%2Fflask-base-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtnbarreto%2Fflask-base-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mtnbarreto","download_url":"https://codeload.github.com/mtnbarreto/flask-base-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249061069,"owners_count":21206447,"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":["flask","flask-backend","rest-api","restful-api"],"created_at":"2024-10-01T13:57:21.139Z","updated_at":"2025-04-15T11:31:54.241Z","avatar_url":"https://github.com/mtnbarreto.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Docker Image CI](https://github.com/mtnbarreto/flask-base-api/actions/workflows/docker-image.yml/badge.svg)](https://github.com/mtnbarreto/flask-base-api/actions/workflows/docker-image.yml)\r\n\r\n# Flask Base API\r\n\r\nThis repository aims to create a starting point to develop a REST API using Python and Flask framework as main technologies.\r\n\r\n**Features:**\r\n* Development environment with Docker that supports Test-Driven Development (TDD).\r\n* Staging, Testing, and Production environments.\r\n* RESTful API powered by Python, Flask web framework, Postgres DB, rabbitmq, and other technologies.\r\n* Unit tests covering the REST API services.\r\n* Code coverage.\r\n* RESTful API documentation via Swagger.\r\n* Easily visualize and consume RESTful API via Swagger UI.\r\n* RabbitMQ message broker and RabbitMQ management plugin integration.\r\n* Supports RESTful API versioning.\r\n* JWT authentication.\r\n* Google authentication.\r\n* Facebook login.\r\n* Firebase Cloud Messaging integration to send push notifications.\r\n* SQLAlchemy ORM integration and modeling of base db entities.\r\n* pgAdmin db administration and development platform for PostgreSQL.\r\n* Nginx reverse proxy and load balancer.\r\n## Contents\r\n\r\n* [Quick start guide](#quick-start-guide)\r\n* [Commands](#commands)\r\n* [Dependencies](#dependencies)\r\n* [RESTful endpoints](#restful-endpoints)\r\n* [FAQ](#faq)\r\n\r\n## Quick start guide\r\n\r\n \r\n#### 1 - Create a folder to clone all projects.\r\n\r\n```bash\r\n  mkdir \u003cmy_folder\u003e \u0026\u0026 cd \u003cmyfolder\u003e\r\n```\r\n\r\n#### 2 - Clone the project from \u003cmyfolder\u003e folder.\r\n\r\n```bash\r\n  git clone git@github.com:mtnbarreto/flask-base-api.git\r\n```\r\n\r\n\r\n#### 3 - Set up environment variables\r\n\r\nBefore putting up and running the app containers, we need to set up some environment variables, mainly user services accounts like Firebase and Twilio. To do so, create a file named `set_local_env_vars.sh` and add the following content replacing the values.\r\n\r\n```bash\r\n#!/usr/bin/env bash\r\n\r\nexport APP_SETTINGS=\"project.config.DevelopmentConfig\"\r\nexport FLASK_APP=project/__init__.py\r\nexport SECRET_KEY=\"mysecret\"\r\nexport MAIL_SERVER=\"smtp.googlemail.com\"\r\nexport MAIL_PORT=\"465\"\r\nexport MAIL_USERNAME=\"my_email@my_email_domain.com\"\r\nexport MAIL_PASSWORD=\"my_email_password\"\r\nexport MAIL_DEFAULT_SENDER=\"my_email@my_email_domain.com\"\r\nexport TWILIO_ACCOUNT_SID=\"1234qwer\"\r\nexport TWILIO_AUTH_TOKEN=\"qwer1234\"\r\nexport TWILIO_FROM_NUMBER=\"+123456789\"\r\nexport CELLPHONE_VALIDATION_CODE_EXP_SECS=\"600\"\r\nexport MAIL_USE_TLS=\"False\"\r\nexport MAIL_USE_SSL=\"True\"\r\nexport FCM_SERVER_KEY=\"9876oiuy\"\r\nexport GOOGLE_CLIENT_ID=\"my-google-client-id.apps.googleusercontent.com\"\r\n```  \r\n\r\nTo set up the env variables, execute:\r\n\r\n```bash\r\nsource ../set_local_env_vars.sh\r\n```\r\n#### 4 - Move to `flask-main`.\r\n\r\n```bash\r\ncd flask-main\r\n```\r\n\r\n\r\n#### 5 - Now let's build the images and run the containers. `flask-base-api` requires docker 20.10.1 or newer. \r\n\r\n```bash\r\ndocker-compose build --no-cache\r\ndocker-compose up -d\r\n```\r\n\r\n\u003e `docker-compose build` build the images. `--no-cache` arg indicates the cache should not be used. Docker caches the result of the build and use it in the subsequent builds. Remove this arg to build the images faster.\r\n\u003e `docker-compose up` fires up the containers. The `-d` flag is used to run the containers in the background.\r\n\r\n`docker-compose up -d` should output something like ...\r\n\r\n```bash\r\nCreating network \"flask-main_default\" with the default driver\r\nCreating pgadmin       ... done\r\nCreating redis         ... done\r\nCreating postgres-db   ... done\r\nCreating rabbitmq      ... done\r\nCreating celery-worker ... done\r\nCreating flask-api     ... done\r\nCreating swagger       ... done\r\nCreating nginx         ... done\r\n```\r\n\r\nAfter running the previous commands, let see the list of container by running:\r\n\r\n```bash\r\ndocker-compose ps\r\n```\r\n\r\n```bash\r\nName                       Command                  State                                                 Ports                                           \r\n-------------------------------------------------------------------------------------------------------------------------------------------------------------------\r\nflask-api             /bin/sh -c bash -c 'while  ...   Up             0.0.0.0:5001-\u003e5000/tcp, 0.0.0.0:5678-\u003e5678/tcp                                                 \r\ncelery-worker         /bin/sh -c celery -A proje ...   Up                                                                                                            \r\npostgres-db           docker-entrypoint.sh postgres    Up (healthy)   0.0.0.0:5435-\u003e5432/tcp                                                                         \r\nnginx                 /docker-entrypoint.sh ngin ...   Up             0.0.0.0:80-\u003e80/tcp                                                                             \r\npgadmin               /entrypoint.sh                   Up             443/tcp, 0.0.0.0:5050-\u003e80/tcp                                                                  \r\nrabbitmq              docker-entrypoint.sh rabbi ...   Up             15671/tcp, 0.0.0.0:15675-\u003e15672/tcp, 15691/tcp, 15692/tcp, 25672/tcp, 4369/tcp, 5671/tcp,      \r\n                                                                      0.0.0.0:5675-\u003e5672/tcp                                                                         \r\nredis           docker-entrypoint.sh redis ...   Up             0.0.0.0:6375-\u003e6379/tcp                                                                         \r\nswagger         sh /usr/share/nginx/docker ...   Up             0.0.0.0:8080-\u003e8080/tcp \r\n```\r\n\r\nMake sure all services started properly. `State` should be `Up`.  \r\n\r\n#### 6 - Set up database\r\n\r\nBy running the following command, we recreate all development db tables:\r\n\r\n```bash\r\ndocker-compose exec flask-api python manage.py recreate_db\r\n```\r\n\r\nthen you can populate the db by executing the following command:\r\n\r\n```bash\r\ndocker-compose exec flask-api python manage.py seed_db\r\n```\r\n\r\nFinally, test that everything works by executing the following curl command that tries to logged in using a user created by the seed_db command:\r\n\r\n```bash\r\ncurl -X POST \"http://0.0.0.0/v1/auth/login\" -H \"accept: application/json\" -H \"Content-Type: application/json\" -d \"{\\\"email\\\":\\\"a@a.com\\\",\\\"password\\\":\\\"password\\\"}\"\r\n```\r\n\r\nit should output something like this:\r\n\r\n```json\r\n{\r\n    \"status\":\"success\",\r\n    \"message\":\"Successfully logged in.\",\r\n    \"auth_token\":\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2ODk5NjQyNDgsImlhdCI6MTY4NzM3MjI0OCwic3ViIjoxfQ.RyYsShoPiDAXyb0q72TOWMFZFVfTpWrHQmxIwTIU1Y8\",\r\n    \"email\":\"a@a.com\",\r\n    \"username\":null,\r\n    \"given_name\":null,\r\n    \"family_name\":null\r\n}\r\n```\r\n\r\n## Commands\r\n\r\n### Debugging\r\n\r\n| Command | Result |\r\n|:---|---|\r\n|`docker-compose logs`| Shows logs of all docker-compose related containers.|\r\n|`docker exec -ti postgres-db psql -U postgres`| Runs psql.|\r\n|`docker-compose exec \u003ccontainer_name\u003e bash`| Runs bash in container_name container. See the example below.|\r\n\r\n\u003e `docker-compose logs -f \u003ccontainer_name\u003e` shows only the logs of the \u003ccontainer_name\u003e container. For example, `docker-compose logs -f flask-api` shows flask web service logs while `docker-compose logs -f postgres-db` shows  PostgreSQL db container logs.\r\n\r\n```bash\r\nbarreto$ docker-compose exec postgres-db bash\r\nroot@ceeb60f9aea8:/# psql -U postgres\r\npsql (10.0)\r\nType \"help\" for help.\r\n\r\npostgres=# \\c db_dev\r\nYou are now connected to database \"db_dev\" as user \"postgres\".\r\n\r\ndb_dev=#\r\n```\r\n\r\n\r\n\r\n### Base commands\r\n\r\n| Command | Result |\r\n|:---|---|\r\n| `docker-compose exec flask-api flask routes` | Shows the app's endpoints list |\r\n| `docker-compose exec flask-api flask shell` | Runs a shell in the app context |\r\n\r\n### DB Creation\r\n\r\n| Command | Result |\r\n|:---|---|\r\n| `docker-compose exec flask-api python manage.py recreate_db` | Recreates database by dropping and creating tables.|\r\n| `docker-compose exec flask-api python manage.py seed_db` | Seeds the database |\r\n\r\n\r\n### DB Migrations\r\n\r\n| Command | Result |\r\n|:---|---|\r\n|`docker-compose exec flask-api flask db [OPTIONS] COMMAND [ARGS]...`| Perform database migrations. |\r\n\r\n| COMMAND | Result |\r\n|:---|---|\r\n|`branches [OPTIONS]`  |Show current branch points.|\r\n|`current [OPTIONS]`  |Display the current revision for each database.|\r\n|`downgrade [OPTIONS] [REVISION]`  |Revert to a previous version.|\r\n|`edit [OPTIONS] [REVISION]`  |Edit a revision file.|\r\n|`heads [OPTIONS]`  |Show current available heads in the script directory.|\r\n|`history [OPTIONS]`  |List changeset scripts in chronological order.|\r\n|`init  [OPTIONS]`  |Creates a new migration repository.|\r\n|`merge [OPTIONS] [REVISIONS]...`  |Merge two revisions together, creating a new revision file|\r\n|`migrate [OPTIONS]`  |Autogenerate a new revision file (Alias for `revision --autogenerate`)|\r\n|`revision [OPTIONS]`  |Create a new revision file.|\r\n|`show [OPTIONS] [REVISION]`  |Show the revision denoted by the given symbol|\r\n|`stamp [OPTIONS] [REVISION]`  |'stamp' the revision table with the given  revision; don't run any migrations|\r\n|`upgrade [OPTIONS] [REVISION]` |Upgrade to a later version|\r\n\r\n\u003e you can see all DB migration commands documentation by executing `docker-compose run flask-api flask db --help`\r\n\u003e For a particular command documentation you can execute `docker-compose run flask-api flask db [COMMAND] --help`\r\n\r\n### Run Tests\r\n\r\n| Command | Result |\r\n|:---|---|\r\n|`docker-compose exec flask-api python manage.py test`| Runs all integration tests|\r\n|`docker-compose exec flask-api python manage.py test \u003cfile-name or pattern\u003e`| Runs all integration tests that matches the file-name or pattern |\r\n\r\n\u003e Make sure you run tests on the `development` target. It does not work on `debug` target, which uses debugpy library.\r\n\u003e There are more than 54 integration test covering the REST endpoints. Check out test implementations inside [test](/flask-api/tests/) folder.\r\n\r\nThe most convenient way to run tests on demand is by using VSCode UI. \r\n\r\n![vs-code UI testing](.github/files/ui-tests.gif)\r\n\r\n\r\n## Dependencies\r\n\r\n* Python 3.11.3\r\n* Docker 20.10.11+\r\n* Docker Compose 1.29.2+\r\n* Flask v2.3.2\r\n\r\nFor a complete list of Python dependencies, check out [requiremets.txt](/flask-api/requirements.txt) file.\r\n\r\n\r\n## RESTful endpoints\r\n\r\nRun `docker-compose exec flask-api flask routes` to see the REST API endpoints list.\r\n\r\n```bash\r\nEndpoint                                    Methods  Rule                                 \r\n------------------------------------------  -------  -------------------------------------\r\nauth.facebook_login                         POST     /v1/auth/facebook/login              \r\nauth.get_user_status                        GET      /v1/auth/status                      \r\nauth.login_user                             POST     /v1/auth/login                       \r\nauth.logout_user                            GET      /v1/auth/logout                      \r\nauth.password_change                        PUT      /v1/auth/password_change             \r\nauth.password_recovery                      POST     /v1/auth/password_recovery           \r\nauth.password_reset                         PUT      /v1/auth/password                    \r\nauth.register_user                          POST     /v1/auth/register                    \r\nauth.set_standalone_user                    PUT      /v1/auth/facebook/set_standalone_user\r\ndevices.connect_device_with_logged_in_user  PUT      /v1/devices/\u003cdevice_id\u003e              \r\ndevices.register_device                     POST     /v1/devices                          \r\nemail_validation.email_verification         PUT      /v1/email_verification               \r\nemail_validation.verify_email               GET      /v1/email_verification/\u003ctoken\u003e       \r\nphone_validation.register_user_cellphone    POST     /v1/cellphone                        \r\nphone_validation.verify_user_cellphone      PUT      /v1/cellphone/verify                 \r\nstatic                                      GET      /static/\u003cpath:filename\u003e              \r\nusers.add_user                              POST     /v1/users                            \r\nusers.get_all_users                         GET      /v1/users                            \r\nusers.get_single_user                       GET      /v1/users/\u003cuser_id\u003e                  \r\nusers.ping_pong                             GET      /v1/ping                             \r\nusers.push_echo                             POST     /v1/push_echo      \r\n```\r\n\r\n### Sanity Check\r\n\r\n| Endpoint | HTTP Method | Result |\r\n|:---|:---:|---|\r\n| `/ping`  | `GET` | Sanity check  |\r\n\r\n### Authentication\r\n\r\n| Endpoint | HTTP Method | Result |\r\n|:---|:---:|---|\r\n| `/auth/register`  | `POST`  | Registers a new user  |\r\n| `/auth/login`  | `POST`  | Login the user  |\r\n| `/auth/logout`  | `GET`  | User logout  |\r\n| `/auth/status`  | `GET`  | Returns the logged in user's status  |\r\n| `/auth/password_recovery`  | `POST`  | Creates a password_recovery_hash and sends email to user |\r\n| `/auth/password`  | `PUT`  | Reset user password  |\r\n| `/auth/password_change`  | `PUT`  | Changes user password  |\r\n| `/auth/facebook/login`  | `POST`  | Logs in user using fb_access_token returning the corresponding JWT. if the user does not exist registers/creates a new one  |\r\n| `/auth/facebook/set_standalone_user`  | `PUT`  | Sets username and password to work directly on the system without Facebook  |\r\n\r\n\u003e Endpoints implementation can be found under [/project/api/v1/auth.py](project/api/v1/auth.py).\r\n\r\n### Cell phone number validation\r\n\r\n| Endpoint | HTTP Method | Result |\r\n|:---|:---:|---|\r\n| `/cellphone`  | `POST`  | Generates cellphone_validation_code, idempotent (could be used for resend cellphone_validation_code) allows just 1 user per cellphone validation! |\r\n| `/cellphone/verify` | `PUT` | Verifies cellphone_validation_code, idempotent (could be used many times) |\r\n\r\n\u003e Endpoints implementation can be found under [/project/api/v1/phone_validation.py](project/api/v1/phone_validation.py).\r\n\r\n### Devices (Push notifications support)\r\n\r\n| Endpoint | HTTP Method | Result |\r\n|:---|:---:|---|\r\n| `/devices`  | `POST`  | Creates or updates the device in the system |\r\n| `/devices/\u003cdevice_id\u003e` | `PUT` | creates/updates and associates the device device_id to the user logged_in_user_id |\r\n\r\n\u003e Endpoints implementation can be found under [/project/api/v1/devices.py](project/api/v1/devices.py).\r\n\r\n### Email validation\r\n\r\n|Endpoint| HTTP Method | Result |\r\n|:---|:---:|---|\r\n| `/email_verification`  | `PUT`  | Creates a email_token_hash and sends email with token to user (assumes login=email), idempotent (could be use for resend) |\r\n| `/email_verification/\u003ctoken\u003e` | `GET` | Sets email verified date |\r\n\r\n\u003e Endpoints implementation can be found under [/project/api/v1/email_validation.py](project/api/v1/email_validation.py).\r\n\r\n\r\n## FAQ\r\n\r\n### How do I add a new API endpoint version..?\r\n\r\n`flask-base-api` supports backwards compatibility, which is crucial for mobile api development. API services are added under [/v1](/flask-api/project/api/v1/) url prefix by default. \r\n\r\nIn order to update endpoints and still support v1, simply regist blueprints with url-prefix `/v2` and do not change `/v1` endpoints. Whenever an endpoint needs to be updated, copy `v1` version and paste it in `v2` project folder, then make necesarry changes over `v2`. \r\n\r\n```python\r\n    app.register_blueprint(auth_blueprint, url_prefix='/v1')\r\n    app.register_blueprint(auth_blueprint2, url_prefix='/v2')\r\n    ...\r\n    ..\r\n    .\r\n```\r\n\r\n### How do I change/add app configs?\r\n\r\n`flask-base-api` support multiple environments. Check out config values at [/flask-api/project/config.py](/flask-api/project/config.py).\r\n\r\n### How does error handling works?\r\n\r\n`flask-base-api` registers multiple error handlers for most common exceptions types.\r\n\r\n```python\r\n    # register error handlers\r\n    from project.api.common.utils import exceptions\r\n    from project.api.common import error_handlers\r\n    InvalidPayload, error_handlers.handle_exception)\r\n    app.register_error_handler(exceptions.BusinessException, error_handlers.handle_exception)\r\n    app.register_error_handler(exceptions.UnauthorizedException, error_handlers.handle_exception)\r\n    app.register_error_handler(exceptions.ForbiddenException, error_handlers.handle_exception)\r\n    app.register_error_handler(exceptions.NotFoundException, error_handlers.handle_exception)\r\n    app.register_error_handler(exceptions.ServerErrorException, error_handlers.handle_exception)\r\n    app.register_error_handler(Exception, error_handlers.handle_general_exception)\r\n```\r\n\r\n You can raise `InvalidPayload`, `BusinessException`, `UnauthorizedException`, `ForbiddenException`, `NotFoundException`, `ServerErrorException` from within endpoint implementations, which is formatted into JSON  format by error handlers. For instance: \r\n\r\n ```python\r\n  raise UnauthorizedException(message='Something went wrong. Please contact us.')\r\n ```\r\n\r\nand the error handler returns \r\n\r\n\u003e 401 Unauthorized\r\n\r\n```json\r\n{\"message\":\"Something went wrong. Please contact us.\",\"status\":\"error\"}\r\n```\r\n\r\nYou can easily implement a custom exception by extending the `APIException` type, the same type that `flask-base-api` exceptions extend.\r\n\r\n```python\r\nclass APIException(Exception):\r\n\r\n    def __init__(self, message, status_code, payload):\r\n        super().__init__()\r\n        self.message = message\r\n        self.status_code = status_code\r\n        self.payload = payload\r\n\r\n    def to_dict(self):\r\n        rv = dict(self.payload or ())\r\n        rv['message'] = self.message\r\n        rv['status'] = 'error'\r\n        return rv\r\n```\r\n\r\nWe can return a response message for the new exception type by registering a handler like:\r\n\r\n```python\r\napp.register_error_handler(MyNewException, error_handlers.handle_general_exception)\r\n``` \r\n\r\n### How do I implement an authenticated service?\r\n\r\n`flask-base-api` use JWT authentication. \r\n\r\nBy using `@authenticate` decorator you can easily force JWT check and authentication for the endpoint like the following method indicates. If authentication goes well, `user_id` is passed as argument to the endpoint function. If something goes wrong, it raises `UnauthorizedException()` and the server responds with a 401 Unauthorized response.\r\n\r\n```python\r\n@phone_validation_blueprint.route('/cellphone/verify', methods=['PUT'])\r\n@accept('application/json')\r\n@authenticate\r\ndef verify_user_cellphone(user_id: int):\r\n    ''' verifies cellphone_validation_code, idempotent (could be used many times) '''\r\n    post_data = request.get_json()\r\n    if not post_data:\r\n        raise InvalidPayload()\r\n    validation_code = post_data.get('validation_code')\r\n    user = User.get(user_id)\r\n    ...\r\n    ..\r\n    .\r\n```\r\n\r\nCurious about how the `@authenticate`  decorator is implemented?\r\n\r\n```python\r\ndef authenticate(f):\r\n    @wraps(f)\r\n    def decorated_function(*args, **kwargs):\r\n        auth_header = request.headers.get('Authorization')\r\n        if not auth_header:\r\n            raise UnauthorizedException()\r\n        auth_token = auth_header.split(\" \")[1]\r\n        user_id = User.decode_auth_token(auth_token)\r\n        user = User.get(user_id)\r\n        if not user or not user.active:\r\n            raise UnauthorizedException(message='Something went wrong. Please contact us.')\r\n        return f(user_id, *args, **kwargs)\r\n    return decorated_function\r\n```\r\n\r\n\r\n### How do I test an endpoint?\r\n\r\nTests are implemented using [Flask-Testing](https://github.com/jarus/flask-testing) library. All testing files are placed under [/tests](tests). There are more than 50 test cases already implemented.\r\n\r\nYou can create a new test case class in a new file which must start with `test_`, and ideally, it should extend to the `BaseTestCase` class which loads testing configuration and clean up db state after each test case execution. Test case method name must be prefixed with `test`.\r\n\r\nAfter implementing the new test case, you can run it. Go to [here](#run-tests) to see how.\r\n\r\n### How do I use Swagger to play with the API?\r\n\r\n\r\nNow you can check swagger RESTful API documentation by visiting http://localhost:8080.\r\n\r\n![swagger](.github/files/swagger.png)\r\n\r\nRESTful API is available under http://localhost:5001/v1. You can also use port 80 since Nginx was also set up. [http://localhost/v1/ping](http://localhost/v1/ping) should return `{\"status\":\"success\",\"message\":\"pong!\"}`.\r\n\r\n\r\n### How do I use pgAdmin?\r\n\r\nFirst, get the Postgres db ip address by executing\r\n\r\n```bash\r\ndocker inspect postgres-db | grep \"IPAddress\"\r\n```\r\n\r\nwhich outputs the `IPAddress`\r\n\r\n```bash\r\n  \"SecondaryIPAddresses\": null,\r\n  \"IPAddress\": \"\",\r\n          \"IPAddress\": \"192.168.224.3\",\r\n```\r\n\r\nThen open `pgAdmin` in your browser `http://0.0.0.0:5050/`, and log in  by using email: `admin@admin.com`, password: `password` credentials.\r\n\r\nThen connect to db server using the ip address retrieved above and  using the following Postgres credentials: user: `postgres`, password: `postgres`.\r\n\r\n![pgAdmin](.github/files/pgAdmin.png)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtnbarreto%2Fflask-base-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmtnbarreto%2Fflask-base-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtnbarreto%2Fflask-base-api/lists"}