{"id":13682986,"url":"https://github.com/Nikolay-Lysenko/servifier","last_synced_at":"2025-04-30T10:30:32.353Z","repository":{"id":53661788,"uuid":"183671850","full_name":"Nikolay-Lysenko/servifier","owner":"Nikolay-Lysenko","description":"An easy-to-use tool for making web service with API from your own Python functions.","archived":false,"fork":false,"pushed_at":"2024-01-11T21:18:12.000Z","size":28,"stargazers_count":8,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-04T16:55:01.725Z","etag":null,"topics":["api-maker","apify","ml-engineering","model-to-production","web-service"],"latest_commit_sha":null,"homepage":null,"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/Nikolay-Lysenko.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":"2019-04-26T17:50:06.000Z","updated_at":"2023-08-27T17:29:03.000Z","dependencies_parsed_at":"2024-01-14T16:09:31.401Z","dependency_job_id":"3d51c52f-4844-4070-ae5f-fc8cbe7b480a","html_url":"https://github.com/Nikolay-Lysenko/servifier","commit_stats":{"total_commits":21,"total_committers":2,"mean_commits":10.5,"dds":0.04761904761904767,"last_synced_commit":"6d51f0904edf650e178a95e2f5424c8ebafabb83"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nikolay-Lysenko%2Fservifier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nikolay-Lysenko%2Fservifier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nikolay-Lysenko%2Fservifier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nikolay-Lysenko%2Fservifier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nikolay-Lysenko","download_url":"https://codeload.github.com/Nikolay-Lysenko/servifier/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224206354,"owners_count":17273443,"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":["api-maker","apify","ml-engineering","model-to-production","web-service"],"created_at":"2024-08-02T13:01:56.874Z","updated_at":"2025-04-30T10:30:32.334Z","avatar_url":"https://github.com/Nikolay-Lysenko.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"[![Build Status](https://github.com/Nikolay-Lysenko/servifier/actions/workflows/main.yml/badge.svg)](https://github.com/Nikolay-Lysenko/servifier/actions/workflows/main.yml)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/b9203957727d2ea2d808/test_coverage)](https://codeclimate.com/github/Nikolay-Lysenko/servifier/test_coverage)\n[![Maintainability](https://api.codeclimate.com/v1/badges/b9203957727d2ea2d808/maintainability)](https://codeclimate.com/github/Nikolay-Lysenko/servifier/maintainability)\n[![PyPI version](https://badge.fury.io/py/servifier.svg)](https://badge.fury.io/py/servifier)\n\n# Servifier\n\n## Overview\n\nIt is an easy-to-use tool for making web service with API from your own Python functions.\n\nThe list of the features is as follows:\n* fault tolerance,\n* customizable requests validation,\n* concise error messages for end user,\n* authentication.\n\nAs of 2023-08-27, [FastAPI](https://github.com/tiangolo/fastapi) is a way more advanced alternative to this package. \n\n## Minimal Example\n\nSuppose that you have a file named `simple_service.py` that looks like this:\n\n```python\nfrom servifier import HandleSpec, create_app\n\n\ndef add_numbers(first: int, second: int) -\u003e int:\n    \"\"\"Add two numbers.\"\"\"\n    return first + second\n\n\ndef subtract_numbers(first: int, second: int) -\u003e int:\n    \"\"\"Subtract two numbers.\"\"\"\n    return first - second\n\n\nhandle_spec_for_adding = HandleSpec(add_numbers, '/add')\nhandle_spec_for_subtraction = HandleSpec(subtract_numbers, '/subtract')\n\nhandle_specs = [handle_spec_for_adding, handle_spec_for_subtraction]\n\napp = create_app(handle_specs)\napp.run()\n```\n\nRun this script. A demo server starts and after that you can send requests to it:\n\n```bash\n\u003e\u003e\u003e curl -X POST -H \"Content-Type: application/json\" -d '{\"first\": 1, \"second\": 3}' http://127.0.0.1:5000/add\n{\"response\":4,\"status\":200}\n\u003e\u003e\u003e curl -X POST -H \"Content-Type: application/json\" -d '{\"first\": 1, \"second\": 3}' http://127.0.0.1:5000/subtract\n{\"response\":-2,\"status\":200}\n```\n\n## Installation\n\nA stable version of the package can be collected from PyPI:\n\n```pip install servifier```\n\n## Tips on Usage\n\n#### Deployment on a Production Server\n\nIn the above minimal example, the development server provided by `Flask` is used. It is not suitable for production usage.\n\nThere are [plenty of ways](http://flask.pocoo.org/docs/1.0/deploying/) to deploy a Flask application on a production server. For example, you can use [Waitress](http://flask.pocoo.org/docs/1.0/tutorial/deploy/#run-with-a-production-server) or uWSGI.\n\nLet us discuss uWSGI a bit more. You can create `uwsgi.ini` config:\n\n```\n[uwsgi]\n# {Python module}:{Flask app from there}\nmodule = simple_service:app\n# If it is true, there is a master process, not only workers.\nmaster = true\n# Number of workers.\nprocesses = 4\n# Host and port for API, '0.0.0.0' means to use web address.\nhttp = 0.0.0.0:7070\n# Directory with code to be imported.\npythonpath = ./venv/lib/python3.6/site-packages/\n# If it is not set, logs are printed. If it is set, logs are written to this file.\nlogto = /tmp/servifier.log\n```\n\nTo use it, you need to install `uWSGI` Python package:\n```\npip install uwsgi\n```\n\nTo start a production server, delete `app.run()` line from `simple_service.py` (it launches demo server) and run:\n```\nuwsgi --ini uwsgi.ini\n```\n\nIt may be enough to have just uWSGI. However, you can also add Nginx in front of uWSGI as a load balancer and a reverse proxy.\n\n#### Input Data Validation\n\nIt is possible to configure `servifier` so that requests with invalid data are rejected with a proper error code before your function is called.\n\nThe minimal example with a simple service can be modified in the following manner:\n\n```python\nfrom servifier import HandleSpec, create_app\nfrom servifier.validation import IntegerField\n\n\ndef add_numbers(first: int, second: int) -\u003e int:\n    \"\"\"Add two numbers.\"\"\"\n    return first + second\n\n\ndef subtract_numbers(first: int, second: int) -\u003e int:\n    \"\"\"Subtract two numbers.\"\"\"\n    return first - second\n    \n    \nclass IntegerPair:\n    \"\"\"A pair of two integers.\"\"\"\n    \n    first = IntegerField(required=True)\n    second = IntegerField(required=True)\n    \n    def __init__(self, first: int, second: int):\n        \"\"\"Initialize an instance with parameters validation.\"\"\"\n        self.first = first\n        self.second = second\n\n\nhandle_spec_for_adding = HandleSpec(\n    add_numbers, '/add', IntegerPair\n)\nhandle_spec_for_subtraction = HandleSpec(\n    subtract_numbers, '/subtract', IntegerPair\n)\n\nhandle_specs = [handle_spec_for_adding, handle_spec_for_subtraction]\n\napp = create_app(handle_specs)\napp.run()\n```\n\nBehavior of the service is demonstrated below:\n\n```bash\n\u003e\u003e\u003e curl -X POST -H \"Content-Type: application/json\" -d '{\"first\": \"1\", \"second\": 3}' http://127.0.0.1:5000/add\n{\"error\":\"Invalid Request: check your JSON\",\"status\":422}\n```\n\nComparing to the minimal example, this service returns \"Invalid Request\" status instead of \"Internal Error\" status which is harder to debug for end user.\n\nIf you need more info about how this example works, read about [Python descriptors](https://www.codevoila.com/post/69/python-descriptors-example).\n\n#### Authentication\n\nIt is possible to deny requests that does not include login and token where proper value of token is defined by login and arbitrary salt.\n\nMinimal example with authentication enabled looks like this:\n\n```python\nfrom servifier import HandleSpec, create_app\n\n\ndef add_numbers(first: int, second: int) -\u003e int:\n    \"\"\"Add two numbers.\"\"\"\n    return first + second\n\n\ndef subtract_numbers(first: int, second: int) -\u003e int:\n    \"\"\"Subtract two numbers.\"\"\"\n    return first - second\n\n\nhandle_spec_for_adding = HandleSpec(\n    add_numbers, '/add', auth_salt='abcd'\n)\nhandle_spec_for_subtraction = HandleSpec(\n    subtract_numbers, '/subtract', auth_salt='1234'\n)\n\nhandle_specs = [handle_spec_for_adding, handle_spec_for_subtraction]\n\napp = create_app(handle_specs)\napp.run()\n```\n\nFor a particular login, you can generate its token with `servifier.auth.generate_token` function and tell this value to someone sending requests under this login. JSON attachment from a request must include two additional fields ('login' and 'token') besides fields with arguments for a Python function.\n\n```bash\n\u003e\u003e\u003e curl -X POST -H \"Content-Type: application/json\" -d '{\"login\": \"a\", \"token\": \"6491cacf01b2e1c6d08a5609d2f570ea57d71ae7f06e0391276d70d935d29aa51888d566751aa36dc5e12e18da693ece36427c167e2a7a67e48aca8928ba3979\", \"first\": 1, \"second\": 3}' http://127.0.0.1:5000/subtract\n{\"result\":-2,\"status\":200}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNikolay-Lysenko%2Fservifier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNikolay-Lysenko%2Fservifier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNikolay-Lysenko%2Fservifier/lists"}