{"id":15898921,"url":"https://github.com/acroz/data-science-apis","last_synced_at":"2025-07-06T08:36:20.957Z","repository":{"id":79484450,"uuid":"108633881","full_name":"acroz/data-science-apis","owner":"acroz","description":"An example Flask application showcasing the recipes from my talk at PyCon UK 2017.","archived":false,"fork":false,"pushed_at":"2017-11-03T00:01:08.000Z","size":8,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-28T07:29:46.350Z","etag":null,"topics":["data-science","flask","machine-learning","python","python-rq"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/acroz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2017-10-28T08:49:24.000Z","updated_at":"2021-04-24T18:06:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"a1d3eb29-06c5-4beb-83b7-ddfb7f20ac7b","html_url":"https://github.com/acroz/data-science-apis","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acroz%2Fdata-science-apis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acroz%2Fdata-science-apis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acroz%2Fdata-science-apis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acroz%2Fdata-science-apis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/acroz","download_url":"https://codeload.github.com/acroz/data-science-apis/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229821752,"owners_count":18129424,"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":["data-science","flask","machine-learning","python","python-rq"],"created_at":"2024-10-06T10:10:16.483Z","updated_at":"2024-12-15T12:41:28.409Z","avatar_url":"https://github.com/acroz.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Data Science API Example\n\nThis repository accompanies my talk at PyCon UK 2017, where I gave a tutorial\nproviding some tips for effective deployment of data science APIs using Flask.\n\nSpecifically, my talk demonstrated:\n\n* Flask\n* JSON-encoding error handlers\n* Authentication with API keys and the `before_request` decorator\n* Flask-SQLAlchemy\n* Avoiding SQL injection by using SQLAlchmemy's query interpolator\n* Worker queues with python-rq\n* Deployment with gunicorn\n\nAll of these recommendations have been implemented together in this project. In\nthe near future I will write a blog post or series of posts covering the same\nmaterial as my talk - once completed it will be linked here.\n\n## Installation\n\n```sh\n$ pip install .\n```\n\nTo generate the sqlite database:\n\n```sh\n$ python gendb.py\n```\n\nYou will also need to install redis and have it running for the app to function\nproperly.\n\nWith homebrew:\n\n```sh\n$ brew install redis\n$ brew tap homebrew/services  # If not done previously\n$ brew services start redis\n```\n\n## Running the Server\n\nRun the api server with:\n\n```sh\n$ gunicorn --workers 4 dsapi:app\n```\n\nIn a separate terminal(s), run one or more python-rq workers:\n\n```sh\nrq worker\n```\n\nAlso make sure that redis-server is running.\n\n## Calling the API\n\nWith the server and worker running, the API can be called externally with any\nHTTP client. From Python, I recommend using the requests library, available\nfrom PyPI:\n\n```sh\n$ pip install requests\n```\n\n### Simple Endpoint and Authentication\n\nYou can then query the `/predict` endpoint using one of the valid keys in the\n`api_keys` table:\n\n```python\n\u003e\u003e\u003e import requests\n\u003e\u003e\u003e response = requests.get(\n\u003e\u003e\u003e     'http://localhost:8000/predict/feature_a/1.0/feature_b/1.0',\n\u003e\u003e\u003e     headers={'X-API-Key': 'PE1tlZti1TXJ9nTIri30OnPcquDUpjVrayieAAzY'}\n\u003e\u003e\u003e )\n\u003e\u003e\u003e response.status_code\n200\n\u003e\u003e\u003e response.json()\n{'class': 1, 'class_probabilities': [0.0961415144762564, 0.9038584855237436]})\n```\n\nNote how missing or invalid API keys will return a `401 UNAUTHORIZED` response:\n\n```python\n\u003e\u003e\u003e response = requests.get(\n\u003e\u003e\u003e     'http://localhost:8000/predict/feature_a/1.0/feature_b/1.0',\n\u003e\u003e\u003e     headers={'X-API-Key': 'invalid-key'}\n\u003e\u003e\u003e )\n\u003e\u003e\u003e response.status_code\n401\n\u003e\u003e\u003e response.json()\n{'error': True, 'message': 'Invalid API Key'}\n```\n\n### Slow Task Endpoints\n\nThe `/predict-slow` endpoint accepts a `POST` request with the features in the\nbody and returns an ID field that can be redeemed later for the result:\n\n```python\n\u003e\u003e\u003e response = requests.post(\n\u003e\u003e\u003e     'http://localhost:8000/predict-slow',\n\u003e\u003e\u003e     json={'feature_a': 1.3, 'feature_b': -3.2},\n\u003e\u003e\u003e     headers={'X-API-Key': 'PE1tlZti1TXJ9nTIri30OnPcquDUpjVrayieAAzY'}\n\u003e\u003e\u003e )\n\u003e\u003e\u003e response.status_code\n202\n\u003e\u003e\u003e response.json()\n{'id': 'a779fb1a-8811-48f2-b79e-00f223bb9f43'}\n```\n\nTo check for the result:\n\n```python\n\u003e\u003e\u003e id = response.json()['id']\n\u003e\u003e\u003e response = requests.get(\n\u003e\u003e\u003e     f'http://localhost:8000/predict-slow/{id}',\n\u003e\u003e\u003e     headers={'X-API-Key': 'PE1tlZti1TXJ9nTIri30OnPcquDUpjVrayieAAzY'}\n\u003e\u003e\u003e )\n```\n\nBefore the result is ready this will yield a `404 NOT FOUND`:\n\n```python\n\u003e\u003e\u003e response.status_code\n404\n```\n\nOnce ready, the result will be returned with a `200 OK` response:\n\n```python\n\u003e\u003e\u003e response.status_code\n200\n\u003e\u003e\u003e response.json()\n{'class': 0}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facroz%2Fdata-science-apis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Facroz%2Fdata-science-apis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facroz%2Fdata-science-apis/lists"}