HTTPie: modern, user-friendly command-line HTTP client for the API era.
—
HTTPie provides an extensible plugin system that allows developers to add custom authentication methods, output formatters, content converters, and transport adapters.
from httpie.plugins.base import BasePlugin, AuthPlugin, FormatterPlugin, ConverterPlugin, TransportPlugin
from httpie.plugins.registry import plugin_manager
from typing import Tuple
import requests.authAll HTTPie plugins inherit from the base plugin class and are automatically discovered when installed.
class BasePlugin:
"""Base class for all HTTPie plugins."""
name: str = None # Plugin display name
description: str = None # Short description for help text
package_name: str = None # Set automatically when loadedCreate custom authentication methods for APIs that require non-standard authentication schemes.
class AuthPlugin(BasePlugin):
"""Base class for authentication plugins."""
auth_type: str = None # Auth type identifier for --auth-type
auth_require: bool = True # Whether -a argument is required
auth_parse: bool = True # Whether to parse -a as username:password
netrc_parse: bool = False # Whether to use netrc as fallback
prompt_password: bool = True # Whether to prompt for missing password
raw_auth: str = None # Raw -a argument value
def get_auth(self, username: str = None, password: str = None):
"""
Return a requests.auth.AuthBase instance.
Args:
username: Parsed username (if auth_parse=True)
password: Parsed password (if auth_parse=True)
Returns:
requests.auth.AuthBase: Authentication handler
"""
raise NotImplementedError()Example Authentication Plugin:
from httpie.plugins import AuthPlugin
import requests.auth
class APIKeyAuthPlugin(AuthPlugin):
name = 'API Key Authentication'
description = 'API key in custom header'
auth_type = 'api-key'
auth_require = True
auth_parse = False # Don't parse as username:password
def get_auth(self, username=None, password=None):
# Use raw_auth as the API key
api_key = self.raw_auth
class APIKeyAuth(requests.auth.AuthBase):
def __call__(self, request):
request.headers['X-API-Key'] = api_key
return request
return APIKeyAuth()
# Usage: http --auth-type=api-key -a my-secret-key example.com/apiCustomize how HTTPie displays HTTP messages, headers, and response bodies.
class FormatterPlugin(BasePlugin):
"""Base class for output formatter plugins."""
group_name: str = 'format' # Plugin group identifier
enabled: bool = True # Whether formatter is enabled
format_options: dict # Formatting options from CLI
def __init__(self, **kwargs):
"""
Initialize formatter with options.
Args:
env: Environment instance
format_options: Dictionary of format options
**kwargs: Additional formatter arguments
"""
self.enabled = True
self.kwargs = kwargs
self.format_options = kwargs['format_options']
def format_headers(self, headers: str) -> str:
"""
Format HTTP headers for display.
Args:
headers: Raw headers as string
Returns:
str: Formatted headers
"""
return headers
def format_body(self, content: str, mime: str) -> str:
"""
Format response body for display.
Args:
content: Response body as string
mime: Content-Type MIME type (e.g., 'application/json')
Returns:
str: Formatted body content
"""
return content
def format_metadata(self, metadata: str) -> str:
"""
Format response metadata for display.
Args:
metadata: Metadata string
Returns:
str: Formatted metadata
"""
return metadataTransform binary response data into textual representations for terminal display.
class ConverterPlugin(BasePlugin):
"""Base class for content converter plugins."""
def __init__(self, mime: str):
"""
Initialize converter for specific MIME type.
Args:
mime: MIME type this converter handles
"""
self.mime = mime
def convert(self, body: bytes) -> Tuple[str, str]:
"""
Convert binary body to textual representation.
Args:
body: Binary response body
Returns:
Tuple[str, str]: (new_content_type, converted_content)
"""
raise NotImplementedError()
@classmethod
def supports(cls, mime: str) -> bool:
"""
Check if this converter supports the given MIME type.
Args:
mime: MIME type to check
Returns:
bool: True if supported
"""
raise NotImplementedError()Example Converter Plugin:
from httpie.plugins import ConverterPlugin
import base64
class Base64ConverterPlugin(ConverterPlugin):
name = 'Base64 Decoder'
description = 'Decode base64 content for display'
@classmethod
def supports(cls, mime):
return mime == 'application/base64'
def convert(self, body):
try:
decoded = base64.b64decode(body).decode('utf-8')
return 'text/plain', decoded
except Exception:
return 'text/plain', f'<base64 data: {len(body)} bytes>'Add support for custom protocols or modify how HTTPie handles HTTP transport.
class TransportPlugin(BasePlugin):
"""Base class for transport adapter plugins."""
prefix: str = None # URL prefix to mount adapter to
def get_adapter(self):
"""
Return a requests transport adapter.
Returns:
requests.adapters.BaseAdapter: Transport adapter instance
"""
raise NotImplementedError()Example Transport Plugin:
from httpie.plugins import TransportPlugin
import requests.adapters
class CustomProtocolPlugin(TransportPlugin):
name = 'Custom Protocol'
description = 'Support for custom:// URLs'
prefix = 'custom://'
def get_adapter(self):
class CustomAdapter(requests.adapters.BaseAdapter):
def send(self, request, **kwargs):
# Custom request handling logic
response = requests.models.Response()
response.status_code = 200
response.headers['Content-Type'] = 'text/plain'
response._content = b'Custom protocol response'
return response
return CustomAdapter()
# Usage: http custom://example.com/resourceHTTPie automatically discovers plugins installed in the Python environment. Plugins must be properly packaged and declare entry points.
setup.py for plugin distribution:
from setuptools import setup
setup(
name='httpie-my-plugin',
version='1.0.0',
py_modules=['httpie_my_plugin'],
install_requires=['httpie>=3.0.0'],
entry_points={
'httpie.plugins.auth.v1': [
'my_auth = httpie_my_plugin:MyAuthPlugin'
],
'httpie.plugins.formatter.v1': [
'my_formatter = httpie_my_plugin:MyFormatterPlugin'
]
}
)# Plugin registry access
from httpie.plugins.registry import plugin_manager
def list_plugins() -> dict:
"""List all available plugins by type."""
def load_installed_plugins(plugins_dir: str) -> None:
"""Load plugins from the specified directory."""HTTPie includes several built-in plugins:
Plugins should handle errors gracefully and provide meaningful error messages:
class MyAuthPlugin(AuthPlugin):
def get_auth(self, username=None, password=None):
if not self.raw_auth:
raise ValueError("API key is required")
try:
# Plugin logic here
return MyAuth(self.raw_auth)
except Exception as e:
raise ValueError(f"Authentication setup failed: {e}")Plugin errors are reported with ExitStatus.PLUGIN_ERROR (exit code 7).
Install with Tessl CLI
npx tessl i tessl/pypi-httpie