Documentation Index
Fetch the complete documentation index at: https://mintlify.com/iii-hq/sdk/llms.txt
Use this file to discover all available pages before exploring further.
The III SDK provides types for handling HTTP API requests and responses, including support for streaming data.
ApiRequest
Represents an incoming HTTP request with parsed parameters and body.
type ApiRequest<TBody = unknown> = {
path_params: Record<string, string>
query_params: Record<string, string | string[]>
body: TBody
headers: Record<string, string | string[]>
method: string
}
class ApiRequest(BaseModel, Generic[TInput]):
path_params: dict[str, str] = Field(default_factory=dict, alias="pathParams")
query_params: dict[str, str | list[str]] = Field(default_factory=dict, alias="queryParams")
body: Any | None = None
headers: dict[str, str | list[str]] = Field(default_factory=dict)
method: str = "GET"
pub struct ApiRequest<T = Value> {
pub query_params: HashMap<String, String>,
pub path_params: HashMap<String, String>,
pub headers: HashMap<String, String>,
pub path: String,
pub method: String,
pub body: T,
}
Fields
Path parameters extracted from the URL pattern (e.g., /users/:id → { id: "123" }).
Query string parameters. Values can be strings or arrays for repeated parameters.
The parsed request body. Type can be specified via generic parameter.
HTTP headers. Values can be strings or arrays for repeated headers.
HTTP method (GET, POST, PUT, PATCH, DELETE, etc.).
ApiResponse
Represents an HTTP response to be sent back to the client.
type ApiResponse<
TStatus extends number = number,
TBody = string | Buffer | Record<string, unknown>
> = {
status_code: TStatus
headers?: Record<string, string>
body?: TBody
}
class ApiResponse(BaseModel, Generic[TOutput]):
status_code: int = Field(alias="statusCode")
body: Any
headers: dict[str, str] = Field(default_factory=dict)
pub struct ApiResponse<T = Value> {
pub status_code: u16,
pub headers: HashMap<String, String>,
pub body: T,
}
Fields
HTTP status code (200, 404, 500, etc.).
Response headers to include.
Response body. Can be a string, Buffer, or object (automatically JSON serialized).
HttpRequest
For streaming HTTP handlers, includes access to the request body stream.
type HttpRequest<TBody = unknown> = {
path_params: Record<string, string>
query_params: Record<string, string | string[]>
body: TBody
headers: Record<string, string | string[]>
method: string
request_body: ChannelReader
}
@dataclass
class HttpRequest:
path_params: dict[str, str]
query_params: dict[str, str | list[str]]
body: Any
headers: dict[str, str | list[str]]
method: str
request_body: ChannelReader
// HttpRequest in Rust is the same as ApiRequest
// For streaming, use InternalHttpRequest which includes:
pub struct InternalHttpRequest<TBody = Value> {
pub path_params: HashMap<String, String>,
pub query_params: HashMap<String, String>,
pub body: TBody,
pub headers: HashMap<String, String>,
pub method: String,
pub response: ChannelWriter,
pub request_body: ChannelReader,
}
Additional Fields
Stream reader for accessing the raw request body as chunks.
HttpResponse
Streaming response writer for HTTP handlers.
type HttpResponse = {
status: (statusCode: number) => void
headers: (headers: Record<string, string>) => void
stream: NodeJS.WritableStream
close: () => void
}
class HttpResponse:
async def status(self, status_code: int) -> None
async def headers(self, headers: dict[str, str]) -> None
@property
def stream(self) -> WritableStream
def close(self) -> None
// HttpResponse functionality is provided through ChannelWriter
// Send control messages via writer.send_message()
Methods
Set the HTTP status code for the response.
Writable stream for sending response body chunks.
Close the response stream and complete the HTTP response.
Usage Examples
Simple API Handler
type CreateUserRequest = {
name: string
email: string
}
iii.registerFunction(
{ id: 'api::users::create' },
async (req: ApiRequest<CreateUserRequest>): Promise<ApiResponse<201, { id: string }>> => {
const user = await db.users.create(req.body)
return {
status_code: 201,
headers: { 'Content-Type': 'application/json' },
body: { id: user.id }
}
}
)
@dataclass
class CreateUserRequest:
name: str
email: str
async def create_user(req: ApiRequest[CreateUserRequest]) -> ApiResponse:
user = await db.users.create(req.body)
return ApiResponse(
status_code=201,
headers={'Content-Type': 'application/json'},
body={'id': user.id}
)
iii.register_function('api::users::create', create_user)
iii.register_function("api::users::create", |input: Value| {
Box::pin(async move {
let req: ApiRequest = serde_json::from_value(input)?;
let user = db.users.create(req.body).await?;
let response = ApiResponse {
status_code: 201,
headers: HashMap::from([
("Content-Type".into(), "application/json".into())
]),
body: json!({ "id": user.id }),
};
Ok(serde_json::to_value(response)?)
})
});
Streaming Response
import { http } from '@iii/sdk'
const handler = http(async (req: HttpRequest, res: HttpResponse) => {
await res.status(200)
await res.headers({ 'Content-Type': 'text/plain' })
res.stream.write('Starting stream...\n')
for (let i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 100))
res.stream.write(`Chunk ${i}\n`)
}
res.close()
})
iii.registerFunction({ id: 'api::stream' }, handler)
from iii import http
async def stream_handler(req: HttpRequest, res: HttpResponse):
await res.status(200)
await res.headers({'Content-Type': 'text/plain'})
res.stream.write(b'Starting stream...\n')
for i in range(10):
await asyncio.sleep(0.1)
res.stream.write(f'Chunk {i}\n'.encode())
res.close()
iii.register_function('api::stream', http(stream_handler))
// Streaming in Rust uses ChannelWriter directly
iii.register_function("api::stream", |input: Value| {
Box::pin(async move {
let req: InternalHttpRequest = serde_json::from_value(input)?;
req.response.send_message(
&json!({"type": "set_status", "status_code": 200}).to_string()
).await?;
req.response.send_message(
&json!({"type": "set_headers", "headers": {"Content-Type": "text/plain"}}).to_string()
).await?;
req.response.write(b"Starting stream...\n").await?;
for i in 0..10 {
tokio::time::sleep(Duration::from_millis(100)).await;
req.response.write(format!("Chunk {}\n", i).as_bytes()).await?;
}
req.response.close().await?;
Ok(Value::Null)
})
});