From e39886a05d75694bb52c9ccfe431602536b34957 Mon Sep 17 00:00:00 2001 From: birddevelper Date: Thu, 3 Apr 2025 15:30:48 +0300 Subject: [PATCH] feat: Add basic documentation --- docs/source/API parameters.rst | 37 +++++++++++++++ docs/source/api.rst | 7 --- docs/source/async_client.rst | 29 ++++++++++++ docs/source/caching.rst | 12 +++++ docs/source/circuit_breaker.rst | 82 +++++++++++++++++++++++++++++++++ docs/source/config.rst | 23 +++++++++ docs/source/index.rst | 30 ++++++------ docs/source/installation.rst | 10 ++++ docs/source/retry.rst | 14 ++++++ docs/source/sync_client.rst | 20 ++++++++ docs/source/usage.rst | 34 -------------- 11 files changed, 240 insertions(+), 58 deletions(-) create mode 100644 docs/source/API parameters.rst delete mode 100644 docs/source/api.rst create mode 100644 docs/source/async_client.rst create mode 100644 docs/source/caching.rst create mode 100644 docs/source/circuit_breaker.rst create mode 100644 docs/source/config.rst create mode 100644 docs/source/installation.rst create mode 100644 docs/source/retry.rst create mode 100644 docs/source/sync_client.rst delete mode 100644 docs/source/usage.rst diff --git a/docs/source/API parameters.rst b/docs/source/API parameters.rst new file mode 100644 index 0000000..ccbed46 --- /dev/null +++ b/docs/source/API parameters.rst @@ -0,0 +1,37 @@ +Handling Parameters +=================== + +dequest provides `PathParameter`, `QueryParameter`, `FormParameter` and `JsonBody` to handle API parameters. + +Path Parameters +--------------- + +Use `PathParameter` to include values in the URL: + +.. code-block:: python + + from dequest import sync_client, PathParameter + + @sync_client(url="https://api.example.com/users/{user_id}") + def get_user(user_id: PathParameter[int]): + pass + + user = get_user(user_id=42) + print(user) + +Query Parameters +---------------- + +Use `QueryParameter` to pass values as query parameters: + +.. code-block:: python + + from dequest import sync_client, QueryParameter + + @sync_client(url="https://api.example.com/search") + def search(keyword: QueryParameter[str, "q"]): + pass + + results = search(keyword="python") + print(results) + diff --git a/docs/source/api.rst b/docs/source/api.rst deleted file mode 100644 index ec94338..0000000 --- a/docs/source/api.rst +++ /dev/null @@ -1,7 +0,0 @@ -API -=== - -.. autosummary:: - :toctree: generated - - lumache diff --git a/docs/source/async_client.rst b/docs/source/async_client.rst new file mode 100644 index 0000000..7a0cfb2 --- /dev/null +++ b/docs/source/async_client.rst @@ -0,0 +1,29 @@ +Using `async_client` +==================== + +The `@async_client` decorator lets you make non-blocking HTTP requests. + +.. code-block:: python + + from dequest import async_client + + @async_client(url="https://api.example.com/notify", method="POST") + def notify(): + pass + + notify() # Fire-and-forget call + + +Using Callbacks +--------------- + +If you need to handle the response asynchronously, use a callback function. Callbacks let you process API responses asynchronously. + +.. code-block:: python + + async def process_response(data): + print("Received:", data) + + @async_client(url="https://api.example.com/updates", callback=process_response) + def fetch_updates(): + pass diff --git a/docs/source/caching.rst b/docs/source/caching.rst new file mode 100644 index 0000000..26ceabe --- /dev/null +++ b/docs/source/caching.rst @@ -0,0 +1,12 @@ +Caching Responses +================= + +To improve performance, `dequest` can cache responses. + +.. code-block:: python + + @sync_client(url="https://api.example.com/popular", enable_cache=True, cache_ttl=60) + def get_popular(): + pass + +The response will be stored for 60 seconds, reducing API calls. It generates a cache_key by combining the URL, including the values of path parameters, with query parameters, ensuring that an API request with different query parameters is cached separately for each paramter set. \ No newline at end of file diff --git a/docs/source/circuit_breaker.rst b/docs/source/circuit_breaker.rst new file mode 100644 index 0000000..00aa67e --- /dev/null +++ b/docs/source/circuit_breaker.rst @@ -0,0 +1,82 @@ +Circuit Breaker +=============== + +Basic Usage +----------- +To use a circuit breaker with `dequest`, create an instance of `CircuitBreaker` and pass it to the `sync_client` or `async_client` decorator. + +.. code-block:: python + + from dequest.clients import sync_client + from dequest.circuit_breaker import CircuitBreaker + + # Define a Circuit Breaker with failure threshold of 3 and recovery timeout of 10 seconds + breaker = CircuitBreaker(failure_threshold=3, recovery_timeout=10) + + @sync_client(url="https://api.unstable.com/data", circuit_breaker=breaker) + def fetch_data(): + pass + +If the API fails **3 times in a row**, the circuit breaker opens and blocks further requests for **10 seconds**. +Note The retry logic wraps the entire operation so that only if all attempts fail, then the circuit breaker record one failure: + +.. code-block:: python + + from dequest.clients import sync_client + from dequest.circuit_breaker import CircuitBreaker + + breaker = CircuitBreaker(failure_threshold=3, recovery_timeout=10) + + @sync_client(url="https://api.unstable.com/data", circuit_breaker=breaker, retries=2) + def fetch_data(): + pass + +In the above example if API fails 2 * 3 times, the circuit opens and blocks requests for 10 seconds. + + +Handling Circuit Breaker Open Errors +------------------------------------ +When the circuit breaker is open, calling the function will raise a `CircuitBreakerOpenError`: + +.. code-block:: python + + from dequest.circuit_breaker import CircuitBreakerOpenError + + try: + response = fetch_data() + except CircuitBreakerOpenError: + print("Circuit breaker is open! Too many failures, try again later.") + +Using a `fallback_function` +--------------------------- + +Instead of raising an error when the circuit breaker is open, you can define a **fallback function** that provides an alternative response. + +For example, if the main API fails, we can return a cached response or default data: + +.. code-block:: python + + from dequest import sync_client + from dequest.circuit_breaker import CircuitBreaker + + # Define a fallback function + def fallback_response(): + return {"message": "Service unavailable, returning cached data instead"} + + # Create a Circuit Breaker with a fallback function + breaker = CircuitBreaker( + failure_threshold=3, + recovery_timeout=10, + fallback_function=fallback_response # Fallback instead of raising an error + ) + + @sync_client(url="https://api.unstable.com/data", circuit_breaker=breaker) + def fetch_unstable_data(): + pass + + # Simulating multiple failed requests + for _ in range(5): # Exceeds the failure threshold + response = fetch_unstable_data() + print(response) # This will return the fallback response instead of failing + +This helps build a **resilient, fault-tolerant** system that gracefully handles API failures. diff --git a/docs/source/config.rst b/docs/source/config.rst new file mode 100644 index 0000000..17da92d --- /dev/null +++ b/docs/source/config.rst @@ -0,0 +1,23 @@ +Configuration +============= + +You can configure `dequest` globally using `DequestConfig`. + +Cache Provider +-------------- + +.. code-block:: python + + from dequest.config import DequestConfig + + DequestConfig.CACHE_PROVIDER = "redis" # Options: "in_memory", "redis" and "django" + +Redis Configuration +------------------- +If you set "redis" as cache provider, you should set the redis server configuration also. +.. code-block:: python + + DequestConfig.REDIS_HOST = "localhost" + DequestConfig.REDIS_PORT = 6379 + DequestConfig.REDIS_PASSWORD = None + DequestConfig.REDIS_SSL = False diff --git a/docs/source/index.rst b/docs/source/index.rst index 03d09a5..8f92eab 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,22 +1,18 @@ -Welcome to Lumache's documentation! -=================================== +.. Dequest Documentation +======================== -**Lumache** (/lu'make/) is a Python library for cooks and food lovers -that creates recipes mixing random ingredients. -It pulls data from the `Open Food Facts database `_ -and offers a *simple* and *intuitive* API. +Welcome to the documentation for `dequest`, a Python library for declarative HTTP requests. `dequest` provides powerful decorators for synchronous and asynchronous API calls, with built-in support for retries, caching, circuit breakers, and more. -Check out the :doc:`usage` section for further information, including -how to :ref:`installation` the project. - -.. note:: - - This project is under active development. +.. toctree:: + :caption: Contents: -Contents --------- + installation + sync_client + async_client + retry + config + caching + circuit_breaker + API parameters -.. toctree:: - usage - api diff --git a/docs/source/installation.rst b/docs/source/installation.rst new file mode 100644 index 0000000..e050cca --- /dev/null +++ b/docs/source/installation.rst @@ -0,0 +1,10 @@ +Installation +============ + +To install `dequest`, simply run: + +.. code-block:: bash + + pip install dequest + +This will install all necessary dependencies. Now, you're ready to make API requests in a declarative way. diff --git a/docs/source/retry.rst b/docs/source/retry.rst new file mode 100644 index 0000000..3be6a8e --- /dev/null +++ b/docs/source/retry.rst @@ -0,0 +1,14 @@ +Automatic Retries +================= + +If an API request fails due to network issues or server errors, `dequest` can automatically retry the request. + +.. code-block:: python + + from dequest import sync_client + + @sync_client(url="https://api.example.com/data", retries=3, retry_delay=2) + def get_data(): + pass + +This will retry up to 3 times with a 2-second delay between attempts. diff --git a/docs/source/sync_client.rst b/docs/source/sync_client.rst new file mode 100644 index 0000000..daeec1a --- /dev/null +++ b/docs/source/sync_client.rst @@ -0,0 +1,20 @@ +Using `sync_client` +=================== + +The `@sync_client` decorator allows you to make synchronous HTTP requests declaratively. + +Basic Example +------------- + +.. code-block:: python + + from dequest import sync_client + + @sync_client(url="https://api.example.com/users") + def get_users(): + pass # No implementation needed! + + users = get_users() + print(users) + +This sends a GET request and automatically handles response parsing. diff --git a/docs/source/usage.rst b/docs/source/usage.rst deleted file mode 100644 index 924afcf..0000000 --- a/docs/source/usage.rst +++ /dev/null @@ -1,34 +0,0 @@ -Usage -===== - -.. _installation: - -Installation ------------- - -To use Lumache, first install it using pip: - -.. code-block:: console - - (.venv) $ pip install lumache - -Creating recipes ----------------- - -To retrieve a list of random ingredients, -you can use the ``lumache.get_random_ingredients()`` function: - -.. autofunction:: lumache.get_random_ingredients - -The ``kind`` parameter should be either ``"meat"``, ``"fish"``, -or ``"veggies"``. Otherwise, :py:func:`lumache.get_random_ingredients` -will raise an exception. - -.. autoexception:: lumache.InvalidKindError - -For example: - ->>> import lumache ->>> lumache.get_random_ingredients() -['shells', 'gorgonzola', 'parsley'] -