Parcel is a small browser HTTP client for SwiftWASM with pluggable typed body codecs. It defaults to JSON for Encodable request bodies and Decodable responses.
structRequest:Encodable{}structResponse:Decodable{}letclient=Client()letaccepted=tryawait client.send(.post(URL(string:"https://example.com/api/generate")!,
body:Request()),
as:Response.self
)Typed decode consumes the response body once. Client.Response preserves the decoded value, the response head, and the final URL, but it does not retain raw response bytes after decoding. HTTPBody.text() buffers in memory and defaults to a 2 MiB cap. Raise that limit explicitly when you expect larger bodies.
If you need to drop to a raw request, use Client.raw(_:, body:timeout:). Raw calls do not apply codec-specific Accept or Content-Type defaults. Raw responses may carry 4xx or 5xx status codes; typed Client.send calls treat non-2xx responses as failures and throw ClientError.unsuccessfulStatusCode before decoding.
letrequest=HTTPRequest(method:.get, url:URL(string:"https://example.com/api/generate")!)letresponse=tryawait client.raw(request)letstatusCode= response.response.status.code
letbodyText=tryawait response.body?.text()For successful responses with no body, use EmptyResponse:
letdeleteURL=URL(string:"https://example.com/api/delete")!
letresponse=tryawait client.send(.delete(deleteURL),
as:EmptyResponse.self
)If you need custom JSONEncoder / JSONDecoder behavior, configure the default codec through ClientConfiguration:
letclient=Client(
configuration:ClientConfiguration(
defaultTimeout:.seconds(30),
defaultCodec:.json(
codec:JSONBodyCodec(
makeDecoder:{letdecoder=JSONDecoder()
decoder.keyDecodingStrategy =.convertFromSnakeCase
return decoder
}))))Parcel includes additional built-in codecs for common wire formats: .formURLEncoded(), .plainText(), .rawData().
If you need a different typed wire format entirely, provide a custom BodyCodec:
enumCustomCodecError:Error{case unsupported
}structCustomCodec:BodyCodec{func encode<Request:Encodable>(_ value:Request)throws->Data{throwCustomCodecError.unsupported
}func decode<Response:Decodable>(_ type:Response.Type, from data:Data)throws->Response{throwCustomCodecError.unsupported
}}letclient=Client(
configuration:ClientConfiguration(
defaultCodec:.custom(CustomCodec(),
requestContentType:"application/custom",
accept:["application/custom"])))Parcel is browser-oriented. Client() is only compiled on wasm32 builds that include Parcel's browser transport dependencies. Host builds must inject a custom Transport, which is how Parcel's native unit tests exercise the higher-level client behavior. On wasm32, the built-in transport supports both window-style and worker-style globals; unsupported JavaScript runtimes fail requests with ClientError.unsupportedPlatform.
BrowserTransport is likewise only available on those wasm32 builds. It installs the JavaScriptKit executor when it initializes in a supported runtime.
Browser transport responses stream lazily from ReadableStream through HTTPBody. Outgoing request bodies are still buffered before Parcel passes them to fetch, with a 2 MiB default cap configurable via BrowserTransport(maximumBufferedRequestBodyBytes:).