{"id":13424983,"url":"https://github.com/smagafurov/fastapi-jsonrpc","last_synced_at":"2026-01-17T07:14:19.221Z","repository":{"id":35056401,"uuid":"201516795","full_name":"smagafurov/fastapi-jsonrpc","owner":"smagafurov","description":"JSON-RPC server based on fastapi","archived":false,"fork":false,"pushed_at":"2025-08-27T18:18:41.000Z","size":617,"stargazers_count":425,"open_issues_count":11,"forks_count":35,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-11-28T12:14:08.494Z","etag":null,"topics":["asgi","fastapi","json-rpc","json-rpc-server","openapi","pydantic","starlette","swagger"],"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/smagafurov.png","metadata":{"files":{"readme":"README.rst","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-08-09T17:56:48.000Z","updated_at":"2025-11-28T11:07:11.000Z","dependencies_parsed_at":"2023-01-15T12:53:50.407Z","dependency_job_id":"68e436f4-1892-4250-a61b-e2ea420ba2e0","html_url":"https://github.com/smagafurov/fastapi-jsonrpc","commit_stats":{"total_commits":155,"total_committers":12,"mean_commits":"12.916666666666666","dds":"0.20645161290322578","last_synced_commit":"1329be64ea635a844cdb529eaf31a1ac3055ae58"},"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/smagafurov/fastapi-jsonrpc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smagafurov%2Ffastapi-jsonrpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smagafurov%2Ffastapi-jsonrpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smagafurov%2Ffastapi-jsonrpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smagafurov%2Ffastapi-jsonrpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smagafurov","download_url":"https://codeload.github.com/smagafurov/fastapi-jsonrpc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smagafurov%2Ffastapi-jsonrpc/sbom","scorecard":{"id":832273,"data":{"date":"2025-08-11","repo":{"name":"github.com/smagafurov/fastapi-jsonrpc","commit":"c4bd192f2f53f8235473a974ca9e088cec223a6f"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.6,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":1,"reason":"Found 3/18 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":1,"reason":"0 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests-latest-fastapi-pydantic.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/smagafurov/fastapi-jsonrpc/tests-latest-fastapi-pydantic.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests-latest-fastapi-pydantic.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/smagafurov/fastapi-jsonrpc/tests-latest-fastapi-pydantic.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/smagafurov/fastapi-jsonrpc/tests.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/smagafurov/fastapi-jsonrpc/tests.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/tests-latest-fastapi-pydantic.yml:35","Warn: pipCommand not pinned by hash: .github/workflows/tests-latest-fastapi-pydantic.yml:42","Warn: pipCommand not pinned by hash: .github/workflows/tests-latest-fastapi-pydantic.yml:46","Warn: pipCommand not pinned by hash: .github/workflows/tests.yml:37","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   4 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/tests-latest-fastapi-pydantic.yml:1","Warn: no topLevel permission defined: .github/workflows/tests.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 18 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-23T18:03:46.474Z","repository_id":35056401,"created_at":"2025-08-23T18:03:46.475Z","updated_at":"2025-08-23T18:03:46.475Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28503259,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T06:57:29.758Z","status":"ssl_error","status_checked_at":"2026-01-17T06:56:03.931Z","response_time":85,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["asgi","fastapi","json-rpc","json-rpc-server","openapi","pydantic","starlette","swagger"],"created_at":"2024-07-31T00:01:01.491Z","updated_at":"2026-01-17T07:14:19.197Z","avatar_url":"https://github.com/smagafurov.png","language":"Python","readme":"|tests|\n\n.. |tests| image:: https://github.com/smagafurov/fastapi-jsonrpc/actions/workflows/tests.yml/badge.svg\n   :target: https://github.com/smagafurov/fastapi-jsonrpc/actions/workflows/tests.yml\n\n\nDescription\n===========\n\nJSON-RPC server based on fastapi:\n\n    https://fastapi.tiangolo.com\n\nOpenRPC supported too.\n\nMotivation\n^^^^^^^^^^\n\nAutogenerated **OpenAPI** and **Swagger** (thanks to fastapi) for JSON-RPC!!!\n\nInstallation\n============\n\n.. code-block:: bash\n\n    pip install fastapi-jsonrpc\n\nDocumentation\n=============\n\nRead FastAPI documentation and see usage examples bellow\n\nSimple usage example\n====================\n\n.. code-block:: bash\n\n    pip install uvicorn\n\nexample1.py\n\n.. code-block:: python\n\n    import fastapi_jsonrpc as jsonrpc\n    from pydantic import BaseModel\n    from fastapi import Body\n\n\n    app = jsonrpc.API()\n\n    api_v1 = jsonrpc.Entrypoint('/api/v1/jsonrpc')\n\n\n    class MyError(jsonrpc.BaseError):\n        CODE = 5000\n        MESSAGE = 'My error'\n\n        class DataModel(BaseModel):\n            details: str\n\n\n    @api_v1.method(errors=[MyError])\n    def echo(\n        data: str = Body(..., examples=['123']),\n    ) -\u003e str:\n        if data == 'error':\n            raise MyError(data={'details': 'error'})\n        else:\n            return data\n\n\n    app.bind_entrypoint(api_v1)\n\n\n    if __name__ == '__main__':\n        import uvicorn\n        uvicorn.run('example1:app', port=5000, debug=True, access_log=False)\n\nOpenRPC:\n\n    http://127.0.0.1:5000/openrpc.json\n\nSwagger:\n\n    http://127.0.0.1:5000/docs\n\nFastAPI dependencies usage example\n==================================\n\n.. code-block:: bash\n\n    pip install uvicorn\n\nexample2.py\n\n.. code-block:: python\n\n    import logging\n    from contextlib import asynccontextmanager\n\n    from pydantic import BaseModel, Field\n    import fastapi_jsonrpc as jsonrpc\n    from fastapi import Body, Header, Depends\n\n\n    logger = logging.getLogger(__name__)\n\n\n    # database models\n\n    class User:\n        def __init__(self, name):\n            self.name = name\n\n        def __eq__(self, other):\n            if not isinstance(other, User):\n                return False\n            return self.name == other.name\n\n\n    class Account:\n        def __init__(self, account_id, owner, amount, currency):\n            self.account_id = account_id\n            self.owner = owner\n            self.amount = amount\n            self.currency = currency\n\n        def owned_by(self, user: User):\n            return self.owner == user\n\n\n    # fake database\n\n    users = {\n        '1': User('user1'),\n        '2': User('user2'),\n    }\n\n    accounts = {\n        '1.1': Account('1.1', users['1'], 100, 'USD'),\n        '1.2': Account('1.2', users['1'], 200, 'EUR'),\n        '2.1': Account('2.1', users['2'], 300, 'USD'),\n    }\n\n\n    def get_user_by_token(auth_token) -\u003e User:\n        return users[auth_token]\n\n\n    def get_account_by_id(account_id) -\u003e Account:\n        return accounts[account_id]\n\n\n    # schemas\n\n    class Balance(BaseModel):\n        \"\"\"Account balance\"\"\"\n        amount: int = Field(..., example=100)\n        currency: str = Field(..., example='USD')\n\n\n    # errors\n\n    class AuthError(jsonrpc.BaseError):\n        CODE = 7000\n        MESSAGE = 'Auth error'\n\n\n    class AccountNotFound(jsonrpc.BaseError):\n        CODE = 6000\n        MESSAGE = 'Account not found'\n\n\n    class NotEnoughMoney(jsonrpc.BaseError):\n        CODE = 6001\n        MESSAGE = 'Not enough money'\n\n        class DataModel(BaseModel):\n            balance: Balance\n\n\n    # dependencies\n\n    def get_auth_user(\n        # this will become the header-parameter of json-rpc method that uses this dependency\n        auth_token: str = Header(\n            None,\n            alias='user-auth-token',\n        ),\n    ) -\u003e User:\n        if not auth_token:\n            raise AuthError\n\n        try:\n            return get_user_by_token(auth_token)\n        except KeyError:\n            raise AuthError\n\n\n    def get_account(\n        # this will become the parameter of the json-rpc method that uses this dependency\n        account_id: str = Body(..., example='1.1'),\n        user: User = Depends(get_auth_user),\n    ) -\u003e Account:\n        try:\n            account = get_account_by_id(account_id)\n        except KeyError:\n            raise AccountNotFound\n\n        if not account.owned_by(user):\n            raise AccountNotFound\n\n        return account\n\n\n    # JSON-RPC middlewares\n\n    @asynccontextmanager\n    async def logging_middleware(ctx: jsonrpc.JsonRpcContext):\n        logger.info('Request: %r', ctx.raw_request)\n        try:\n            yield\n        finally:\n            logger.info('Response: %r', ctx.raw_response)\n\n\n    # JSON-RPC entrypoint\n\n    common_errors = [AccountNotFound, AuthError]\n    common_errors.extend(jsonrpc.Entrypoint.default_errors)\n\n    api_v1 = jsonrpc.Entrypoint(\n        # Swagger shows for entrypoint common parameters gathered by dependencies and common_dependencies:\n        #    - json-rpc-parameter 'account_id'\n        #    - header parameter 'user-auth-token'\n        '/api/v1/jsonrpc',\n        errors=common_errors,\n        middlewares=[logging_middleware],\n        # this dependencies called once for whole json-rpc batch request\n        dependencies=[Depends(get_auth_user)],\n        # this dependencies called separately for every json-rpc request in batch request\n        common_dependencies=[Depends(get_account)],\n    )\n\n\n    # JSON-RPC methods of this entrypoint\n\n    # this json-rpc method has one json-rpc-parameter 'account_id' and one header parameter 'user-auth-token'\n    @api_v1.method()\n    def get_balance(\n        account: Account = Depends(get_account),\n    ) -\u003e Balance:\n        return Balance(\n            amount=account.amount,\n            currency=account.currency,\n        )\n\n\n    # this json-rpc method has two json-rpc-parameters 'account_id', 'amount' and one header parameter 'user-auth-token'\n    @api_v1.method(errors=[NotEnoughMoney])\n    def withdraw(\n        account: Account = Depends(get_account),\n        amount: int = Body(..., gt=0, example=10),\n    ) -\u003e Balance:\n        if account.amount - amount \u003c 0:\n            raise NotEnoughMoney(data={'balance': get_balance(account)})\n        account.amount -= amount\n        return get_balance(account)\n\n\n    # JSON-RPC API\n\n    app = jsonrpc.API()\n    app.bind_entrypoint(api_v1)\n\n\n    if __name__ == '__main__':\n        import uvicorn\n        uvicorn.run('example2:app', port=5000, debug=True, access_log=False)\n\nOpenRPC:\n\n    http://127.0.0.1:5000/openrpc.json\n\nSwagger:\n\n    http://127.0.0.1:5000/docs\n\n.. image:: ./images/fastapi-jsonrpc.png\n\nSentry\n======\n\n\n* (auto) JRPC method name as transaction name\n* (only for FastApiJsonRPCIntegration) Tracing support. Single transaction for batch requests, each method is span\n\n.. code-block:: python\n\n    import sentry_sdk\n    from fastapi_jsonrpc.contrib.sentry import FastApiJsonRPCIntegration\n    from sentry_sdk.integrations.starlette import StarletteIntegration\n    from sentry_sdk.integrations.fastapi import FastApiIntegration\n    \n\n    sentry_sdk.init(\n       ...,\n       integrations=[FastApiJsonRPCIntegration()],\n       # if you do not use common (RESTlike) routes you can disable other integrations\n       # for performance reasons\n       disabled_integrations=[StarletteIntegration, FastApiIntegration],\n    )\n\nDevelopment\n===========\n\n* Install poetry\n\n    https://github.com/sdispater/poetry#installation\n\n* Install dependencies\n\n    .. code-block:: bash\n\n        poetry update\n\n* Regenerate README.rst\n\n    .. code-block:: bash\n\n        rst_include include -q README.src.rst README.rst\n\n* Change dependencies\n\n    Edit ``pyproject.toml``\n\n    .. code-block:: bash\n\n        poetry update\n\n* Bump version\n\n    .. code-block:: bash\n\n        poetry version patch\n        poetry version minor\n        poetry version major\n\n* Publish to pypi\n\n    .. code-block:: bash\n\n        poetry publish --build\n\n","funding_links":[],"categories":["Projects","Examples","HarmonyOS","RPC Utilities"],"sub_categories":["Open Source Projects","Windows Manager"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmagafurov%2Ffastapi-jsonrpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmagafurov%2Ffastapi-jsonrpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmagafurov%2Ffastapi-jsonrpc/lists"}