{"id":17151924,"url":"https://github.com/dancardin/responsaas","last_synced_at":"2026-01-27T15:31:14.806Z","repository":{"id":190423433,"uuid":"682591148","full_name":"DanCardin/responsaas","owner":"DanCardin","description":null,"archived":false,"fork":false,"pushed_at":"2024-04-23T01:28:09.000Z","size":80,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-30T06:25:03.530Z","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":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DanCardin.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":"2023-08-24T13:53:46.000Z","updated_at":"2023-08-25T19:54:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"35901062-5c5a-4614-9afd-fa16eca9a30a","html_url":"https://github.com/DanCardin/responsaas","commit_stats":null,"previous_names":["dancardin/responsaas"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/DanCardin/responsaas","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanCardin%2Fresponsaas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanCardin%2Fresponsaas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanCardin%2Fresponsaas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanCardin%2Fresponsaas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DanCardin","download_url":"https://codeload.github.com/DanCardin/responsaas/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanCardin%2Fresponsaas/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28815397,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T12:25:15.069Z","status":"ssl_error","status_checked_at":"2026-01-27T12:25:05.297Z","response_time":168,"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":[],"created_at":"2024-10-14T21:42:23.170Z","updated_at":"2026-01-27T15:31:14.789Z","avatar_url":"https://github.com/DanCardin.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Responsaas\n\n[![Actions Status](https://github.com/DanCardin/responsaas/actions/workflows/test.yml/badge.svg)](https://github.com/dancardin/responsaas/actions)\n[![Coverage Status](https://coveralls.io/repos/github/DanCardin/responsaas/badge.svg?branch=main)](https://coveralls.io/github/DanCardin/responsaas?branch=main)\n[![Documentation Status](https://readthedocs.org/projects/responsaas/badge/?version=latest)](https://responsaas.readthedocs.io/en/latest/?badge=latest)\n[![Docker](https://img.shields.io/docker/cloud/build/dancardin/responsaas?label=Docker\u0026style=flat)](https://hub.docker.com/r/dancardin/responsaas)\n\nWraps the python [responses](https://github.com/getsentry/responses) library As\nA Service.\n\nSee the full documentation [here](https://responsaas.readthedocs.io/en/latest/)\n(or more specifically\n[converting from responses](https://responsaas.readthedocs.io/en/latest/converting.html)).\n\n## Quickstart\n\n### Automatic (with pytest)\n\nUsing\n[pytest-mock-resources](https://github.com/schireson/pytest-mock-resources/), we\ncan use Docker to manage the lifecycle of the server.\n\n`pip install responsaas[pmr]`\n\n```python\nfrom responsaas.pytest import create_responsaas_fixture, create_responsaas_server_fixture\n\nresponsaas_server = create_responsaas_server_fixture()\nresponsaas = create_responsaas_fixture()\n\ndef test_foo(responsaas: Responsaas):\n    responsaas.add(\"/foo\", json={\"bar\": True})\n\n    response = requests.get(responsaas.base_url + \"/foo\")\n    assert response.json() == {\"bar\": True}\n```\n\n### Manual\n\nThe manual examples assume you have some external way of standing up the server\n\n`pip install responsaas`\n\n```python\nimport requests\nfrom responsaas import ResponsaasServer, Responsaas\n\n# With pytest\nfrom responsaas.pytest import create_responsaas_fixture\n\nresponsaas = create_responsaas_fixture(\"http://localhost:7564\")\n\ndef test_foo(responsaas: Responsaas):\n    responsaas.add(\"/foo\", json={\"bar\": True})\n\n    response = requests.get(responsaas.base_url + \"/foo\")\n    assert response.json() == {\"bar\": True}\n\n\n# Or completely manually.\ndef test_foo():\n    responsaas_server = ResponsaasServer(\"http://localhost:7564\")\n    with responsaas_server.activate() as responsaas:\n        responsaas.add(\"/foo\", json={\"bar\": True})\n\n        response = requests.get(responsaas.base_url + \"/foo\")\n        assert response.json() == {\"bar\": True}\n```\n\n## Why?!?\n\nUnder the hood, `repsonses` is `patch`ing the network calls being made and\nreplacing their result with the result you specify. It's very fast, convenient,\nand (by default) disallows you from making **actual** network calls.\n\n**However** the same (`patch`) strategy that makes it useful has some issues.\n\n- This can run afoul of other libraries which perform `patch` operations. The\n  issue history of responses has many instances (frequently with `moto`), where\n  patches get clobbered in one way or another.\n\n  - `responsaas` does not use `patch` at all. It is a real standalone service\n    responding to real requests.\n\n- Either through `patch` issues, or through programmer error, `responses` can be\n  **so** non-invasive that API calls accidentally get made through to the\n  original destination URL.\n\n  - `responsaas` forces you to change (or really, make configurable) the URL\n    you're hitting for tests, which should make it impossible to hit the\n    original destination url in tests on accident.\n\n- `responses` allows you to return arbitrary python objects (like exceptions)\n  which wouldn't be possible for a request to actually return.\n\n  - `responsaas` (once again), is a literal service responding to requests. The\n    requesting client code is receiving bytes over the wire, and parsing it\n    normally.\n\n- `responses` is(?) limited to mocking the `requests` library. Which doesn't\n  cover cases like `httpx`, `aiohttp`, etc.\n\n  - `responsaas` is client agnostic, given that it's a real service.\n\n- `responses` needs an additional mechanism to allow \"passthru\" requests\n\n  - `responsaas` (once again), is a literal service responding to requests, so\n    it can only return.\n\n## How?\n\nWhat's going on internally is:\n\n- Each test registers a new \"namespace\" against the `responsaas` server\n- Each new namespace corresponds to one `responses.RequestsMock`.\n- As incoming requests are received by the server, they're mapped to the request\n  shape expected by `responses`, and routed directly through its request\n  matching and responds logic.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdancardin%2Fresponsaas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdancardin%2Fresponsaas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdancardin%2Fresponsaas/lists"}