{"id":23282720,"url":"https://github.com/amaziahub/mimicker","last_synced_at":"2025-10-16T01:39:58.909Z","repository":{"id":259909781,"uuid":"878910517","full_name":"amaziahub/mimicker","owner":"amaziahub","description":"Your lightweight, Python-native HTTP mocking server","archived":false,"fork":false,"pushed_at":"2024-12-12T18:50:54.000Z","size":165,"stargazers_count":4,"open_issues_count":4,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-12-12T19:02:00.865Z","etag":null,"topics":["api-testing","api-testing-framework","api-tests","ci-cd","http-mock-server","http-mocking","http-server","mock","mock-server","mocking","mocking-server","purepython","python","stub-server","stubbing","testing","testing-tools"],"latest_commit_sha":null,"homepage":"","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/amaziahub.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":"2024-10-26T12:55:37.000Z","updated_at":"2024-12-12T18:47:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"ae811044-4f65-49c4-bf1a-8f04c8f89f90","html_url":"https://github.com/amaziahub/mimicker","commit_stats":null,"previous_names":["amaziahub/mockingbird","amaziahub/mimicker"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amaziahub%2Fmimicker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amaziahub%2Fmimicker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amaziahub%2Fmimicker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amaziahub%2Fmimicker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amaziahub","download_url":"https://codeload.github.com/amaziahub/mimicker/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230516762,"owners_count":18238446,"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-testing","api-testing-framework","api-tests","ci-cd","http-mock-server","http-mocking","http-server","mock","mock-server","mocking","mocking-server","purepython","python","stub-server","stubbing","testing","testing-tools"],"created_at":"2024-12-20T00:19:52.820Z","updated_at":"2025-10-16T01:39:53.854Z","avatar_url":"https://github.com/amaziahub.png","language":"Python","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/amaziahub/mimicker/main/mimicker.jpg\" alt=\"Mimicker logo\" \n       style=\"width: 200px; height: auto; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border: 2px solid black;\"\u003e\n\u003c/p\u003e\n\u003cdiv\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n\u003e **Mimicker** – Your lightweight, Python-native HTTP mocking server.\n\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![Mimicker Tests](https://github.com/amaziahub/mimicker/actions/workflows/test.yml/badge.svg)](https://github.com/amaziahub/mimicker/actions/workflows/test.yml)\n[![PyPI Version](https://img.shields.io/pypi/v/mimicker.svg)](https://pypi.org/project/mimicker/)\n[![Downloads](https://pepy.tech/badge/mimicker)](https://pepy.tech/project/mimicker)\n[![Last Commit](https://img.shields.io/github/last-commit/amaziahub/mimicker.svg)](https://github.com/amaziahub/mimicker/commits/main)\n[![Codecov Coverage](https://codecov.io/gh/amaziahub/mimicker/branch/main/graph/badge.svg?token=YOUR_CODECOV_TOKEN)](https://codecov.io/gh/amaziahub/mimicker)\n[![License](http://img.shields.io/:license-apache2.0-red.svg)](http://doge.mit-license.org)\n![Poetry](https://img.shields.io/badge/managed%20with-poetry-blue)\n\n\u003c/div\u003e\n\u003c/div\u003e\n\n\nMimicker is a Python-native HTTP mocking server inspired by WireMock, designed to simplify the process of stubbing and\nmocking HTTP endpoints for testing purposes.\nMimicker requires no third-party libraries and is lightweight, making it ideal for integration testing, local\ndevelopment, and CI environments.\n\n## Features\n\n- Create HTTP stubs for various endpoints and methods\n- Mock responses with specific status codes, headers, and body content\n- Flexible configuration for multiple endpoints\n\n## Installation\n\nMimicker can be installed directly from PyPI using pip or Poetry:\n\n### Using pip:\n\n```bash\npip install mimicker\n```\n\n### Using poetry:\n\n```bash\npoetry add mimicker\n```\n\n## Usage\n\nTo start Mimicker on a specific port with a simple endpoint, you can use the following code snippet:\n\n```python\nfrom mimicker.mimicker import mimicker, get\n\nmimicker(8080).routes(\n    get(\"/hello\").\n    body({\"message\": \"Hello, World!\"}).\n    status(200)\n)\n```\n\n### Examples\n\n#### Using Path Parameters\n\nMimicker can handle path parameters dynamically. Here's how you can mock an endpoint with a variable in the path:\n\n```python\nfrom mimicker.mimicker import mimicker, get\n\nmimicker(8080).routes(\n    get(\"/hello/{name}\")\n    .body({\"message\": \"Hello, {name}!\"})\n    .status(200)\n)\n\n# When the client sends a request to /hello/world, the response will be:\n# {\"message\": \"Hello, world!\"}\n```\n\n#### Using Query Parameters\n\n##### Explicitly defined query parameters\n\nMimicker can handle query parameters dynamically. Here's how you can mock an endpoint with a variable in the query:\n\n```python\nfrom mimicker.mimicker import mimicker, get\n\nmimicker(8080).routes(\n    get(\"/hello?name={name}\")\n    .body({\"message\": \"Hello, {name}!\"})\n    .status(200)\n)\n\n# When the client sends a request to /hello?name=world, the response will be:\n# {\"message\": \"Hello, world!\"}\n```\n\n##### Implicit query parameters\n\nWhen query parameters are not explicitly part of the path template, Mimicker will match\nall otherwise matching requests against those parameters as if using a wildcard. For instance\n\n```python\nfrom mimicker.mimicker import mimicker, get\n\nmimicker(8080).routes(\n    get(\"/hello\")\n    .body({\"message\": \"Hello, world!\"})\n    .status(200)\n)\n\n# When the client sends a request to /hello?name=bob, the request will match and the response will be:\n# {\"message\": \"Hello, world!\"}\n```\n\nThese implicitly matched query parameters are available through dynamic responses\nusing the `\"query_params\"` key in `kwargs` in `response_func` (see below), e.g.\n\n```python\nfrom mimicker.mimicker import mimicker, get\n\ndef custom_response(**kwargs):\n    query_params: Dict[str, List[str]] = kwargs['query_params']\n    return 200, {\"message\": f\"Hello {query_params['name'][0]}!\"}\n\nmimicker(8080).routes(\n    get(\"/hello\")\n    .response_func(custom_response)\n)\n\n# When the client sends a request to /hello?name=world, the request will match and the response will be:\n# {\"message\": \"Hello, world!\"}\n```\n\nNote that because query parameters can be repeated with multiple values, they will\nalways appear in a list of values.\n\n#### Using Headers\n\nYou can also mock responses with custom headers:\n\n```python\nfrom mimicker.mimicker import mimicker, get\n\nmimicker(8080).routes(\n    get(\"/hello\")\n    .body(\"Hello with headers\")\n    .headers([(\"Content-Type\", \"text/plain\"), (\"Custom-Header\", \"Value\")])\n    .status(200)\n)\n\n# The response will include custom headers\n```\n\n#### Multiple Routes\n\nMimicker allows you to define multiple routes for different HTTP methods and paths. Here's an example with `GET`\nand `POST` routes:\n\n```python\nfrom mimicker.mimicker import mimicker, get, post\n\nmimicker(8080).routes(\n    get(\"/greet\")\n    .body({\"message\": \"Hello, world!\"})\n    .status(200),\n\n    post(\"/submit\")\n    .body({\"result\": \"Submission received\"})\n    .status(201)\n)\n\n# Now the server responds to:\n# GET /greet -\u003e {\"message\": \"Hello, world!\"}\n# POST /submit -\u003e {\"result\": \"Submission received\"}\n\n```\n\n#### Handling Different Status Codes\n\nYou can also mock different HTTP status codes for the same endpoint:\n\n```python\nfrom mimicker.mimicker import mimicker, get\n\nmimicker(8080).routes(\n    get(\"/status\")\n    .body({\"message\": \"Success\"})\n    .status(200),\n\n    get(\"/error\")\n    .body({\"message\": \"Not Found\"})\n    .status(404)\n)\n\n# GET /status -\u003e {\"message\": \"Success\"} with status 200\n# GET /error -\u003e {\"message\": \"Not Found\"} with status 404\n```\n\n#### Mocking Responses with JSON Body\n\nMimicker supports JSON bodies, making it ideal for API testing:\n\n```python\nfrom mimicker.mimicker import mimicker, get\n\nmimicker(8080).routes(\n    get(\"/json\")\n    .body({\"message\": \"Hello, JSON!\"})\n    .status(200)\n)\n\n# The response will be: {\"message\": \"Hello, JSON!\"}\n```\n\n#### Delaying the response\n\nThis is useful when testing how your code handles timeouts when calling a web API.\n\n```python\nfrom mimicker.mimicker import mimicker, get\nimport requests\n\nmimicker(8080).routes(\n    get(\"/wait\").\n    delay(0.5).\n    body(\"the client should have timed out\")\n)\ntry:\n    resp = requests.get(\"http://localhost:8080/wait\", timeout=0.2)\nexcept requests.exceptions.ReadTimeout as error:\n    print(f\"the API is unreachable due to request timeout: {error=}\")\nelse:\n    # do things with the response\n    ...\n```\n\n#### Supporting Other Body Types (Text, Files, etc.)\n\nIn addition to JSON bodies, Mimicker supports other types of content for the response body. Here's how you can return\ntext or file content:\n\n##### Text Response:\n\n```python\nfrom mimicker.mimicker import mimicker, get\n\nmimicker(8080).routes(\n    get(\"/text\")\n    .body(\"This is a plain text response\")\n    .status(200)\n)\n\n# The response will be plain text: \"This is a plain text response\"\n```\n\n#### File Response:\n\nYou can also return files from a mock endpoint:\n\n```python\nfrom mimicker.mimicker import mimicker, get\n\nmimicker(8080).routes(\n    get(\"/file\")\n    .body(open(\"example.txt\", \"rb\").read())  # Mock a file response\n    .status(200)\n)\n\n# The response will be the content of the \"example.txt\" file\n\n```\n\n### Dynamic Responses with `response_func`\n\nMimicker allows dynamic responses based on the request data using `response_func`. \nThis feature enables you to build mock responses that adapt based on request parameters, headers, and body.\n\n```python\nfrom mimicker.mimicker import mimicker, post\n\n# Available for use with response_func:\n# kwargs.get(\"payload\")\n# kwargs.get(\"headers\")\n# kwargs.get(\"params\")\n\ndef custom_response(**kwargs):\n    request_payload = kwargs.get(\"payload\")\n    return 200, {\"message\": f\"Hello {request_payload.get('name', 'Guest')}\"}\n\nmimicker(8080).routes(\n    post(\"/greet\")\n    .response_func(custom_response)\n)\n\n# POST /greet with body {\"name\": \"World\"} -\u003e {\"message\": \"Hello World\"}\n# POST /greet with empty body -\u003e {\"message\": \"Hello Guest\"}\n```\n\n### Using a Random Port\n\nIf you start Mimicker with port `0`, the system will automatically assign an available port. You can retrieve the actual port Mimicker is running on using the `get_port` method:\n\n```python\nfrom mimicker.mimicker import mimicker, get\n\nserver = mimicker(0).routes(\n    get(\"/hello\")\n    .body({\"message\": \"Hello, World!\"})\n    .status(200)\n)\n\nactual_port = server.get_port()\nprint(f\"Mimicker is running on port {actual_port}\")\n```\n\nThis is useful for test environments where a specific port is not required.\n\n\n## Available Features:\n\n* `get(path)`: Defines a `GET` endpoint.\n* `post(path)`: Defines a `POST` endpoint.\n* `put(path)`: Defines a `PUT` endpoint.\n* `delete(path)`: Defines a `DELETE` endpoint.\n* `patch(path)`: Defines a `PATCH` endpoint.\n* `.delay(duration)`: Defines the delay in seconds waited before returning the response (optional, 0. by default).\n* `.body(content)`: Defines the response `body`.\n* `.status(code)`: Defines the response `status code`.\n* `.headers(headers)`: Defines response `headers`.\n* `.response_func(func)`: Defines a dynamic response function based on the request data.\n\n---\n\n## Logging\nMimicker includes built-in logging to help you observe and debug how your mocked endpoints behave.\n\nBy default, Mimicker logs at the INFO level and uses a colorized output for readability. You’ll see messages like:\n\n```css\n[MIMICKER] [2025-05-04 14:52:10] INFO: ✓ Matched stub. Returning configured response.\n```\n\nand:\n\n```css\n[MIMICKER] [2025-05-05 11:50:10,226] INFO: → GET /hello\nHeaders:\n{\n  \"host\": \"localhost:8080\",\n  \"user-agent\": \"python-requests/2.31.0\",\n  \"accept-encoding\": \"gzip, deflate\",\n  \"accept\": \"*/*\",\n  \"connection\": \"keep-alive\"\n}\n```\n\n###  Controlling the Log Level\nYou can control the log level using the `MIMICKER_LOG_LEVEL` environment variable. Valid values include:\n\n- `DEBUG`\n- `INFO` (default)\n- `WARNING`\n- `ERROR`\n- `CRITICAL`\n\nThis will show detailed request information including method, path, headers, and body.\n\n---\n\n## Requirements\nMimicker supports Python 3.7 and above.\n\n---\n\n### Get in touch\n\nYou are welcome to report 🐞 or  [issues](https://github.com/amaziahub/mimicker/issues),\nupvote 👍 [feature requests](https://github.com/users/amaziahub/projects/1),\nor 🗣️ discuss features and ideas @ [slack community](https://join.slack.com/t/mimicker/shared_invite/zt-2yr7vubw4-8Y09YyxZ5j~G2tlQ5uOXKw)\n\n\n### Contributors\n\nI'm thankful to all the people who have contributed to this project.\n\n\u003ca href=\"https://github.com/amaziahub/mimicker/graphs/contributors\"\u003e\n  \u003cimg src=\"https://contrib.rocks/image?repo=amaziahub/mimicker\" /\u003e\n\u003c/a\u003e\n\n\n## License\nMimicker is released under the MIT License. see the [LICENSE](LICENSE) for more information.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famaziahub%2Fmimicker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famaziahub%2Fmimicker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famaziahub%2Fmimicker/lists"}