Declarative HTTP client for Python
Project description
DeclarativeX
Why DeclarativeX? 🤔
Tired of spelling out each HTTP step? Headers, JSON parsing, the whole shebang? Chill, DeclarativeX
is here to simplify your life. Now you can focus on what actually matters — your business logic.
Key Features 🗝️
- Declarative Syntax: Just slap on some decorators and you're good to go.
- Data Validation: Got Pydantic? We've got your back on robust data validation.
- Async Support: Async you said? Yep, we're all in.
How to Get It 🛠
pip install declarativex
The Basics 📚
Param Types Explained 🤓
Here's the lowdown on the different param types:
default
- sets a default value.field_name
- Changes the field name at theClient
implementation level.
🛤️ Path
Pass data right into the URL path like so:
class SomeClient(BaseClient):
@get("/some/path/{uuid}/")
def get_some_data(uuid: UUID = Path(...)):
...
But hey, if the arg name matches the path variable, that's your default.
So the example above equals:
class SomeClient(BaseClient):
@get("/some/path/{uuid}/")
def get_some_data(uuid: UUID):
...
🔍 Query
Want URL query params? No biggie:
class SomeClient(BaseClient):
@get("/some/path/")
def get_some_data(order_by: str = Query(default="name_asc", field_name="orderBy")):
...
Goodbye, lowerCamelCase! Hello, Pythonic style! 🐍
If we had a snake_case order_by
field in external API we deal with, the code will be like this:
class SomeClient(BaseClient):
@get("/some/path/")
def get_some_data(order_by: str = "name_asc"):
...
📦 BodyField
Let's imagine, that we have two data sources and we need them to make a POST request with.
❓ What are you reaching for the dictionary for, huh?
You don't need to create a dictionary, that will contain the data, use DeclarativeX
:
class FooClient(declarativex.BaseClient):
@post("/bar")
def create_baz(foo: BodyField(...), baz: BodyField(...)) -> dict:
...
client = FooClient(base_url="https://example.com/")
Meanwhile, in the parallel reality file:
def do_something():
foo = fetch_from_db()
baz = fetch_from_cache()
client.create_baz(foo=foo, baz=baz)
If you've actually given in and made that dictionary, check out the next parameter type... Who did I even bother for?
📄 Json
Haha, so you did end up creating that damn dictionary, huh? Alright, now let's see how you're gonna use it:
@post("/bar")
def create_baz(data: Json(...)) -> dict:
...
There you go, you've put it to use. Happy now? 😄
Quick Examples 🚀
1️⃣ Basic GET Request
Fetch a todo item like a pro:
from declarativex import BaseClient, get, Path
class TodoClient(BaseClient):
@get("/todos/{id}")
async def get_todo_by_id(self, id: int = Path(...)) -> dict:
pass
todo_client = TodoClient("https://jsonplaceholder.typicode.com")
response = await todo_client.get_todo_by_id(1)
2️⃣ GET with Query Params
Here's how to get comments for a post:
from declarativex import BaseClient, get, Query
class CommentClient(BaseClient):
@get("/comments")
async def get_comments(self, post_id: int = Query(...)) -> list:
pass
comment_client = CommentClient("https://jsonplaceholder.typicode.com")
response = await comment_client.get_comments(post_id=1)
3️⃣ POST with JSON Body
Check out this POST request:
from declarativex import BaseClient, post, Json
class PostClient(BaseClient):
@post("/posts")
async def create_post(self, data: dict = Json(...)) -> dict:
pass
post_client = PostClient("https://jsonplaceholder.typicode.com")
response = await post_client.create_post(data={"title": "foo", "body": "bar", "userId": 1})
4️⃣ Timeout Handling
You can even set timeouts, because who's got time to wait?
from declarativex import BaseClient, post, Json
class PostClient(BaseClient):
@post("/delay/{delay}", timeout=3)
async def create_post(self, delay: int) -> dict:
pass
post_client = PostClient("https://jsonplaceholder.typicode.com")
response = await post_client.create_post(data={"title": "foo", "body": "bar", "userId": 1})
Pydantic Love ❤️
Use Pydantic models for both input and output:
import asyncio
from declarativex import BaseClient, post, Json
from pydantic import BaseModel
class MyPydanticModel(BaseModel):
name: str
age: int
class AsyncPydanticClient(BaseClient):
@post("/some/path")
async def post_something(self, data: MyPydanticModel = Json(...)) -> MyPydanticModel:
pass
client = AsyncPydanticClient(base_url="https://example.com/")
asyncio.run(client.post_something(MyPydanticModel(name="John", age=42))
Wrap Up 🌯
And there you have it — DeclarativeX
. Making your HTTP requests easier, more Pythonic, and just plain better.
Support the Creator 🙌
If you're digging DeclarativeX and want to give back, consider supporting the creator. Your contributions help keep this project alive and kicking!
Every bit helps and is massively appreciated! 🌟
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for declarativex-1.1.1-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 64e3fa1522b6c07527b4835a4e339afe6774beea34403b7bb5f698feed36ba7b |
|
MD5 | 8222c04f6b8856dfa6a80da1de93de8a |
|
BLAKE2b-256 | 6c7d5b14affdf8930f7c532604e81521ceec4c00a9dca4154a70e28cd97fbeef |