Skip to content

Backend Interface

The backend abstraction provides a consistent interface across different HTTP client libraries.

Backend Base Class

All backends must inherit from Backend and implement its abstract methods.

from fastreq.backends.base import Backend

class CustomBackend(Backend):
    @property
    def name(self) -> str:
        return "custom"

    async def request(self, config: RequestConfig) -> NormalizedResponse:
        # Implementation
        pass

    async def close(self) -> None:
        # Cleanup
        pass

    async def __aenter__(self) -> "Backend":
        return self

    async def __aexit__(self, *args: Any) -> None:
        await self.close()

    def supports_http2(self) -> bool:
        return False

Backend Methods

Method Return Type Description
name str Backend identifier
request() NormalizedResponse Execute HTTP request
close() None Clean up resources
__aenter__() Backend Initialize backend
__aexit__() None Cleanup on exit
supports_http2() bool HTTP/2 support

RequestConfig

Configuration for a single HTTP request. Used internally by backends.

from fastreq.backends.base import RequestConfig

config = RequestConfig(
    url="https://example.com",
    method="GET",
    params={"key": "value"},
    data=b"raw data",
    json={"key": "value"},
    headers={"Authorization": "Bearer token"},
    cookies={"session": "abc123"},
    timeout=30.0,
    proxy="http://proxy:8080",
    http2=True,
    stream=False,
    follow_redirects=True,
    verify_ssl=True,
)

RequestConfig Attributes

Attribute Type Default Description
url str required Request URL
method str "GET" HTTP method
params dict[str, Any] \| None None Query parameters
data Any None Request body data
json Any None JSON body
headers dict[str, str] \| None None Request headers
cookies dict[str, str] \| None None Request cookies
timeout float \| None None Timeout in seconds
proxy str \| None None Proxy URL
http2 bool True Enable HTTP/2
stream bool False Enable streaming
follow_redirects bool True Follow redirects
verify_ssl bool True Verify SSL

NormalizedResponse

Normalized response from HTTP backends with a consistent interface.

from fastreq.backends.base import NormalizedResponse

response = NormalizedResponse(
    status_code=200,
    headers={"content-type": "application/json"},
    content=b'{"key": "value"}',
    text='{"key": "value"}',
    json_data={"key": "value"},
    url="https://example.com",
    is_json=True,
)

NormalizedResponse Attributes

Attribute Type Description
status_code int HTTP status code
headers dict[str, str] Response headers (lowercase keys)
content bytes Raw response body
text str Decoded response body
json_data Any Parsed JSON data
url str Final URL (after redirects)
is_json bool Whether response is valid JSON

NormalizedResponse Methods

from_backend()

Create NormalizedResponse from backend response.

response = NormalizedResponse.from_backend(
    status_code=200,
    headers={"Content-Type": "application/json"},
    content=b'{"key": "value"}',
    url="https://example.com",
    is_json=True,
)

_normalize_headers()

Normalize headers by converting all keys to lowercase.

headers = NormalizedResponse._normalize_headers({
    "Content-Type": "application/json",
    "Authorization": "Bearer token"
})
# Returns: {'content-type': '...', 'authorization': '...'}

Backend Implementations

Available Backends

Backend HTTP/2 Description
niquests Recommended,高性能
aiohttp Native async
requests Synchronous

Using Backends

# Auto-select (recommended)
client = ParallelRequests(backend="auto")

# Specific backend
client = ParallelRequests(backend="niquests")

Backend Initialization

Backends are initialized with HTTP/2 configuration:

from fastreq.backends.niquests import NiquestsBackend

backend = NiquestsBackend(http2_enabled=True)

async with backend:
    response = await backend.request(config)

Custom Backend Implementation

Create a custom backend:

from fastreq.backends.base import Backend, RequestConfig, NormalizedResponse
import httpx

class HttpxBackend(Backend):
    def __init__(self, http2_enabled: bool = True):
        super().__init__(http2_enabled)
        self._client = None

    @property
    def name(self) -> str:
        return "httpx"

    async def __aenter__(self) -> "Backend":
        self._client = httpx.AsyncClient(http2=self._http2_enabled)
        return self

    async def __aexit__(self, *args: Any) -> None:
        if self._client:
            await self._client.aclose()

    async def close(self) -> None:
        if self._client:
            await self._client.aclose()

    async def request(self, config: RequestConfig) -> NormalizedResponse:
        if not self._client:
            raise RuntimeError("Backend not initialized")

        response = await self._client.request(
            method=config.method,
            url=config.url,
            params=config.params,
            data=config.data,
            json=config.json,
            headers=config.headers,
            cookies=config.cookies,
            timeout=config.timeout,
            proxy=config.proxy,
            follow_redirects=config.follow_redirects,
            verify=config.verify_ssl,
        )

        return NormalizedResponse(
            status_code=response.status_code,
            headers=dict(response.headers),
            content=response.content,
            url=str(response.url),
            is_json=response.headers.get("content-type", "").startswith("application/json"),
        )

    def supports_http2(self) -> bool:
        return True

See Also