{"id":28512252,"url":"https://github.com/fluxninja/aperture-py","last_synced_at":"2026-06-24T03:31:55.275Z","repository":{"id":157826688,"uuid":"613929383","full_name":"fluxninja/aperture-py","owner":"fluxninja","description":"Aperture Python SDK","archived":false,"fork":false,"pushed_at":"2024-01-30T11:24:21.000Z","size":740,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-09T13:16:37.115Z","etag":null,"topics":[],"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/fluxninja.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}},"created_at":"2023-03-14T14:51:11.000Z","updated_at":"2023-10-30T11:53:16.000Z","dependencies_parsed_at":null,"dependency_job_id":"613c2987-b0bd-459b-9225-5f49267b0343","html_url":"https://github.com/fluxninja/aperture-py","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/fluxninja/aperture-py","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxninja%2Faperture-py","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxninja%2Faperture-py/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxninja%2Faperture-py/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxninja%2Faperture-py/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluxninja","download_url":"https://codeload.github.com/fluxninja/aperture-py/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxninja%2Faperture-py/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34716324,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-24T02:00:07.484Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2025-06-09T00:37:24.389Z","updated_at":"2026-06-24T03:31:55.263Z","avatar_url":"https://github.com/fluxninja.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n🚀 \u003cb\u003e\u003c/b\u003eJust launched v1 of \u003ca href=\"https://blog.fluxninja.com/blog/aperture-v1-launch-2024/\"\u003emanaged rate limiting service\u003c/a\u003e\u003c/b\u003e\n  \u003cbr/\u003eSupport us with your feedback and questions on \u003ca href=\"https://www.producthunt.com/posts/fluxninja-aperture\"\u003eProduct Hunt\u003c/a\u003e or \u003ca href=\"https://discord.gg/U3N3fCZEPm\"\u003eDiscord\u003c/a\u003e\n  \u003cbr/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/fluxninja/aperture/raw/main/docs/content/assets/img/aperture_logo.png\" alt=\"FluxNinja Aperture\" width=\"75%\"\u003e\n  \u003cbr/\u003e\n  \u003ca href=\"https://docs.fluxninja.com\"\u003e\n    \u003cimg alt=\"Documentation Reference\" src=\"https://img.shields.io/badge/documentation-reference-brightgreen?style=for-the-badge\u0026logo=data:image/png;base64,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\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://join.slack.com/t/fluxninja-aperture/shared_invite/zt-1eunlrkhh-10P1HUkmBfVJX3qrSLRk~g\"\u003e\n    \u003cimg alt=\"Slack Community\" src=\"https://img.shields.io/badge/Join%20Our%20Community-Slack-brightgreen?style=for-the-badge\u0026logo=slack\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n# Rate Limiting for Python Applications\n\nThe `aperture-py` SDK provides an easy way to integrate your Python applications\nwith [FluxNinja Aperture](https://github.com/fluxninja/aperture). It allows flow\ncontrol functionality on fine-grained features inside service code.\n\nRefer to [documentation](https://docs.fluxninja.com/sdk/python/) for more\ndetails.\n\n## Usage\n\n### Install SDK\n\nRun the command below to install the SDK:\n\n```bash\npip install aperture-py\n```\n\n### Create Aperture Client\n\nThe next step is to create an Aperture Client instance, for which, the address\nof the organization created in Aperture Cloud and API key are needed. You can\nlocate both these details by clicking on the Aperture tab in the sidebar menu of\nAperture Cloud.\n\n```python\nfrom aperture_sdk.client import ApertureClient, FlowParams\n\nagent_address = os.getenv(\"APERTURE_AGENT_ADDRESS\", default_agent_address)\napi_key = os.getenv(\"APERTURE_API_KEY\", \"\")\ninsecure = os.getenv(\"APERTURE_AGENT_INSECURE\", \"true\").lower() == \"true\"\n\naperture_client = ApertureClient.new_client(\n    address=agent_address, insecure=insecure, api_key=api_key\n)\n```\n\n### Flow Functionality\n\nThe created instance can then be used to start a flow:\n\n```python\n# business logic produces labels\n    labels = {\n        \"user_id\": \"some_user_id\",\n        \"user_tier\": \"gold\",\n        \"priority\": \"100\",\n    }\n    flow_params = FlowParams(\n        check_timeout=timedelta(seconds=200),\n        explicit_labels=labels,\n    )\n    # start_flow performs a flowcontrol.v1.Check call to Aperture Agent.\n    # It returns a Flow or raises an error if any.\n    flow = await aperture_client.start_flow(\n        control_point=\"AwesomeFeature\",\n        params=flow_params,\n    )\n\n    # Check if flow check was successful.\n    if not flow.success:\n        logger.info(\"Flow check failed - will fail-open\")\n\n    # See whether flow was accepted by Aperture Agent.\n    if flow.should_run():\n        # do actual work\n        pass\n    else:\n        # handle flow rejection by Aperture Agent\n        flow.set_status(FlowStatus.Error)\n\n    res = await flow.end()\n    if res.get_error():\n        logger.error(\"Error: {}\".format(res.get_error()))\n    elif res.get_flow_end_response():\n        logger.info(\"Flow End Response: {}\".format(res.get_flow_end_response()))\n\n    # Simulate work being done\n    await asyncio.sleep(2)\n    return \"\", 202\n```\n\nThe above code snippet is making `start_flow` calls to Aperture. For this call,\nit is important to specify the control point (`AwesomeFeature` in the example)\nand `FlowParams` that will be aligned with the policy created in Aperture Cloud.\nFor request prioritization use cases, it's important to set a higher gRPC\ndeadline. This parameter specifies the maximum duration a request can remain in\nthe queue. For each flow that is started, a `should_run` decision is made,\ndetermining whether to allow the request into the system or to rate limit it. It\nis important to make the `end` call made after processing each request, to send\ntelemetry data that would provide granular visibility for each flow.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluxninja%2Faperture-py","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluxninja%2Faperture-py","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluxninja%2Faperture-py/lists"}