silk.http.client.
A simple HTTP client: send a request, and get the whole response in memory.
When to use#
Use Http to call web APIs. Code that sends requests requires ? &mut Http. The program
gives a provider one time, near main: NativeHttp from silk.http.client_native for real
requests, or a fake in tests. Use silk.http.exchange to stream bodies or to control the
connection.
Details#
Build a Request with chained calls, such as Request.get("/repos").query("page",
"2").bearer(token). Building never allocates and never fails. Http.send checks the request.
A response with any status, also 4xx and 5xx, is a Response. Call Response.expectOk to
make a status outside 200 to 299 an error.
Errors#
HttpErrorfor all failures. Itskindtells what failed,statushas the response status if one arrived, andcausekeeps the error from the lower module.OutOfMemoryErrorif theAllocatorfails.
Gotchas#
A request holds at most 8 path segments, 16 query parameters, and 32 headers. More fail at send
time with InvalidRequest. Request.json writes only the fields that are visible from your
module. Fields that are private to another module are not written.
Examples#
Test code that uses Http with a fake provider#
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.core.effect { Effect }
import silk.http.client { Http, HttpError, Request, Response }
import silk.text.string { String }
struct FakeHttp {
calls: i32,
}
impl Http for FakeHttp {
effect fn send(self: &mut Self, request: Request) -> Response
! HttpError | OutOfMemoryError
? &mut Allocator {
self.calls = self.calls + 1
let url = run request.resolveUrl("https://api.example.com")
if String.view(&url) == "https://api.example.com/search?q=a%20b" {
return run Response.make(200, b"found")
}
return run Response.make(404, b"")
}
}
// This function works with any provider.
effect fn search() -> i32
! HttpError | OutOfMemoryError
? &mut Http | &mut Allocator {
let response = run Http.send(Request.get("/search").query("q", "a b"))
let checked = run response.expectOk()
let text = run checked.text()
if text != "found" {
return 1
}
return 0
}
pub effect fn main() -> i32
! HttpError | OutOfMemoryError {
let mut allocator = Allocator.systemAllocatorProvider()
let mut fake = FakeHttp { calls: 0 }
let code = run search() |> Effect.provideMut<Http>(&mut fake)
|> Effect.provideMut<Allocator>(&mut allocator)
if fake.calls != 1 {
return 1
}
return code
}Import as HttpClient with import silk.http.client as HttpClient.
Public declarations: 11.
MAX_PATH_SEGMENTS#
pub const MAX_PATH_SEGMENTS: usizeThe maximum number of path segments in a request.
MAX_QUERY_PARAMETERS#
pub const MAX_QUERY_PARAMETERS: usizeThe maximum number of query parameters in a request.
MAX_HEADERS#
pub const MAX_HEADERS: usizeThe maximum number of headers that you add to a request.
HttpErrorKind#
pub enum HttpErrorKindWhat kind of failure an HttpError reports.
InvalidUrl#
InvalidUrlThe URL is not valid, has user information, or its scheme is not http or https.
InvalidRequest#
InvalidRequestA method or a header is not valid, or the request has too many parts.
Encode#
EncodeThe request body could not be encoded.
Connect#
ConnectName resolution or the TCP connection failed.
Tls#
TlsTLS negotiation, certificate validation, or the trust store failed.
Timeout#
TimeoutThe request deadline passed.
Protocol#
ProtocolThe response broke the HTTP rules or a limit.
TooLarge#
TooLargeThe response body exceeded the configured limit.
Redirect#
RedirectA redirect is not valid, is not safe, or there were too many redirects.
Status#
StatusThe status is not from 200 to 299, and Response.expectOk or the provider rejects it.
Decode#
DecodeThe response body could not be decoded as requested.
Implementation Debug for HttpErrorKind#
impl Debug for HttpErrorKindOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as InvalidUrl.
HttpCause#
pub union HttpCauseThe lower-level error behind an HttpError, kept for code that needs the detail.
None#
NoneNo lower-level error.
Provider#
ProviderAn HTTP host interface failed with a provider-specific error code.
Field provider#
pub provider: string<'static>The host interface identifying the code's domain.
Field code#
pub code: u32The host's error code, such as a WASI HTTP error variant ordinal.
Uri#
UriURL parsing failed.
Field error#
pub error: UriErrorThe parser failure.
Value#
ValueA header or status value was invalid.
Field error#
pub error: ValueErrorThe value failure.
Request#
RequestRequest preparation failed.
Field error#
pub error: RequestErrorThe preparation failure.
Exchange#
ExchangeThe HTTP exchange failed.
Field error#
pub error: ExchangeErrorThe exchange failure.
Resolver#
ResolverName resolution failed.
Field error#
pub error: ResolverErrorThe resolver failure.
Tls#
TlsTLS negotiation or certificate validation failed.
Field error#
pub error: ConnectionErrorThe connection failure.
Identity#
IdentityThe server certificate identity could not be checked.
Field error#
pub error: IdentityErrorThe identity failure.
Trust#
TrustThe trust store could not be loaded.
Field error#
pub error: TrustSourceErrorThe trust source failure.
Json#
JsonJSON encoding or decoding failed.
Field error#
pub error: JsonErrorThe JSON failure.
Utf8#
Utf8The body was not valid UTF-8.
Field error#
pub error: InvalidUtf8The decoding failure.
Implementation Debug for HttpCause#
impl Debug for HttpCauseOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as None.
HttpError#
pub struct HttpErrorOne HTTP client failure.
Details#
kind tells what failed, status has the response status if one arrived, and cause keeps
the error from the lower module.
Field kind#
pub kind: HttpErrorKindWhat went wrong.
Field message#
pub message: string<'static>A short description for people.
Field status#
pub status: Option<u16>The response status, when a response arrived.
Field cause#
pub cause: HttpCauseThe lower-level error, when there is one.
Implementation Debug for HttpError#
impl Debug for HttpErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the fields, as HttpError { kind: ..., message: ..., ... }.
Implementation HttpError#
impl HttpErrorAssociated function make#
pub fn make(kind: HttpErrorKind, message: string<'static>) -> HttpErrorMakes an error with no status and no lower-level cause.
Associated function caused#
pub fn caused(kind: HttpErrorKind, message: string<'static>, cause: HttpCause) -> HttpErrorMakes an error that keeps a lower-level cause.
Field#
pub struct Field<'a>One query parameter or header as given to a Request.
Field name#
pub name: string<'a>The parameter or header name.
Field value#
pub value: string<'a>The parameter or header value.
Implementation Copy for Field<'a>#
impl<'a> Copy for Field<'a>Body#
pub union Body<'a>The request payload and its media type.
Empty#
EmptyNo payload.
Borrowed#
BorrowedBorrowed payload bytes.
Field data#
pub data: &'a [u8]The payload.
Field contentType#
pub contentType: string<'a>The Content-Type value.
Owned#
OwnedOwned payload bytes, such as encoded JSON.
Field data#
pub data: BytesThe payload.
Field contentType#
pub contentType: string<'static>The Content-Type value.
Request#
pub struct Request<'a>An HTTP request that you build with chained calls. Nothing is checked or sent until
Http.send.
Details#
Build it with chained calls, such as Request.get("/repos").query("page", "2").bearer(token).
Nothing is checked until Http.send. Only Request.json allocates.
Gotchas#
A request holds at most 8 path segments, 16 query parameters, and 32 headers. More fail at send
time with InvalidRequest. Request.json writes only the fields that are visible from your
module.
Implementation Request<'a>#
impl<'a> Request<'a>Associated function make#
pub fn make(method: Method<'static>, url: string<'a>) -> Request<'a>Starts a request with an explicit method.
Associated function get#
pub fn get(url: string<'a>) -> Request<'a>Starts a GET request.
Associated function post#
pub fn post(url: string<'a>) -> Request<'a>Starts a POST request.
Associated function put#
pub fn put(url: string<'a>) -> Request<'a>Starts a PUT request.
Associated function patch#
pub fn patch(url: string<'a>) -> Request<'a>Starts a PATCH request.
Associated function delete#
pub fn delete(url: string<'a>) -> Request<'a>Starts a DELETE request.
Associated function head#
pub fn head(url: string<'a>) -> Request<'a>Starts a HEAD request.
Associated function options#
pub fn options(url: string<'a>) -> Request<'a>Starts an OPTIONS request.
Method path#
pub fn path(self: Self, segment: string<'a>) -> Request<'a>Adds segment to the end of the URL path, as given, such as "/repos".
Method query#
pub fn query(self: Self, name: string<'a>, value: string<'a>) -> Request<'a>Adds a query parameter. The name and the value are percent-encoded when the request is sent.
Method header#
pub fn header(self: Self, name: string<'a>, value: string<'a>) -> Request<'a>Adds a header. The name and value are validated when the request is sent.
Details#
User-Agent, Accept, Authorization, and Host replace the generated values.
Content-Length and Transfer-Encoding are generated from the body and are rejected.
Method bearer#
pub fn bearer(self: Self, token: string<'a>) -> Request<'a>Sets Authorization: Bearer <token>, replacing any Authorization header.
Method bytes#
pub fn bytes(self: Self, data: &'a [u8], contentType: string<'a>) -> Request<'a>Sends borrowed bytes with an explicit Content-Type.
Method text#
pub fn text(self: Self, text: string<'a>) -> Request<'a>Sends UTF-8 text as text/plain; charset=utf-8.
Method json#
pub effect fn json<T>(self: Self, value: &T) -> Request<'a>
! HttpError | OutOfMemoryError
? &mut AllocatorSerializes the visible fields of value as compact JSON and sends it as application/json.
Details#
value is a named or anonymous struct, such as &.{ title: "Water plants" }. Its fields are
written in declaration order through their Serialize witnesses. The bytes are allocated
from the ambient allocator.
Gotchas#
Fields that are private to another module are not written.
Method timeoutSeconds#
pub fn timeoutSeconds(self: Self, seconds: u64) -> Request<'a>Sets the deadline of this request, in place of the default of the provider.
Method maxBodyBytes#
pub fn maxBodyBytes(self: Self, limit: usize) -> Request<'a>Sets the maximum size of the response body, in place of the default of the provider.
Method maxRedirects#
pub fn maxRedirects(self: Self, hops: usize) -> Request<'a>Sets the maximum number of redirects to follow. With 0, a redirect response is returned as it is.
Method method#
pub fn method(self: &Self) -> Method<'static>Returns the request method.
Method url#
pub fn url(self: &Self) -> string<'a>Returns the URL exactly as given, before path segments and query parameters.
Method paths#
pub fn paths(self: &Self) -> &[string<'a>]Returns the path segments in the order they were added.
Method queryParameters#
pub fn queryParameters(self: &Self) -> &[Field<'a>]Returns the query parameters in the order they were added.
Method headers#
pub fn headers(self: &Self) -> &[Field<'a>]Returns the headers in the order they were added.
Method bodyBytes#
pub fn bodyBytes(self: &Self) -> &[u8]Returns the payload bytes, empty when there is no body.
Method contentType#
pub fn contentType(self: &Self) -> Option<string<'a>>Returns the payload's Content-Type, when there is a body.
Method hasBody#
pub fn hasBody(self: &Self) -> boolReturns whether the request has a body.
Method overflowed#
pub fn overflowed(self: &Self) -> boolReturns true if the request has more parts than it can hold. Http.send then fails with
InvalidRequest.
Method timeout#
pub fn timeout(self: &Self) -> Option<u64>Returns the per-request timeout in seconds, when set.
Method maxBody#
pub fn maxBody(self: &Self) -> Option<usize>Returns the per-request response body limit, when set.
Method bearerToken#
pub fn bearerToken(self: &Self) -> Option<string<'a>>Returns the bearer token, when set.
Method redirects#
pub fn redirects(self: &Self) -> Option<usize>Returns the per-request redirect limit, when set.
Method resolveUrl#
pub effect fn resolveUrl(self: &Self, base: string) -> String ! OutOfMemoryError ? &mut AllocatorReturns the full URL: base if the URL has no scheme, then the URL, the path segments, and
the percent-encoded query parameters.
Response#
pub struct ResponseA complete response: status, headers, and the whole body in memory.
Details#
A response with any status, also 4xx and 5xx, is a Response. Call Response.expectOk to
make a status outside 200 to 299 an error.
Implementation Response#
impl ResponseAssociated function fromParts#
pub fn fromParts(head: OwnedResponseHead, body: Bytes, url: String) -> ResponseMakes a response from a head, a body, and the final URL. Providers use it.
Associated function make#
pub effect fn make(status: u16, body: &[u8]) -> Response
! HttpError | OutOfMemoryError
? &mut AllocatorMakes a response with no headers, for fake providers in tests.
Associated function withHeaders#
pub effect fn withHeaders(status: u16, headers: &[Header], body: &[u8]) -> Response
! HttpError | OutOfMemoryError
? &mut AllocatorMakes a response with headers, for fake providers in tests.
Method status#
pub fn status(self: &Self) -> u16Returns the status code, such as 200 or 404.
Method ok#
pub fn ok(self: &Self) -> boolReturns true if the status is from 200 to 299.
Method header#
pub fn header<'r>(self: &'r Self, name: string) -> Option<&'r [u8]>Returns the value of the first header with this name, compared without case.
Method head#
pub fn head<'r>(self: &'r Self) -> ResponseHead<'r>Returns the response head with every header.
Method body#
pub fn body(self: &Self) -> &[u8]Returns the body bytes.
Method intoBody#
pub fn intoBody(self: Self) -> BytesMoves the body out of the response.
Method url#
pub fn url(self: &Self) -> stringReturns the URL of the response, after redirects. It is empty for a response from
Response.make.
Method text#
pub effect fn text(self: &Self) -> string ! HttpErrorReturns the body as text. Fails with Decode if the body is not valid UTF-8.
Method json#
pub effect fn json(self: &Self) -> Value ! HttpError | OutOfMemoryError ? &mut AllocatorParses the body as one JSON document. Fails with Decode if it is not valid JSON.
Method decode#
pub effect fn decode<T: Deserialize>(self: &Self) -> T ! HttpError | OutOfMemoryError ? &mut AllocatorDecodes the body as one JSON document of type T. Fails with Decode if it does not match.
Method expectOk#
pub effect fn expectOk(self: Self) -> Response ! HttpErrorReturns the response if its status is from 200 to 299. Otherwise fails with a Status error
that has the status.
Http#
pub service HttpThe service that sends HTTP requests.
Details#
The provider decides how requests travel. NativeHttp in silk.http.client_native uses sockets
and TLS, and a test provider can return fixed responses. A provider can also wrap another
provider, for example to add headers, logs, or retries, and forward with
Effect.provideMut<Http>.
When to use#
Use it to call web APIs. Code that sends requests requires ? &mut Http. The program gives a
provider one time, near main: NativeHttp from silk.http.client_native for real requests,
or a fake in tests. Use silk.http.exchange to stream bodies or to control the connection.
Operation send#
effect fn send(request: Request) -> Response ! HttpError | OutOfMemoryError ? &mut Http | &mut AllocatorSends one request and returns the complete response, whatever its status.
Details#
It checks the request first. A response with a 4xx or 5xx status is a success. Call
Response.expectOk to make it an error.
Errors#
HttpErrorfor all failures. Itskindtells what failed,statushas the response status if one arrived, andcausekeeps the error from the lower module. A request with more than 8 path segments, 16 query parameters, or 32 headers fails withInvalidRequest.OutOfMemoryErrorif theAllocatorfails.
Implementation Http#
impl HttpAssociated function get#
pub effect fn get(url: string) -> Response ! HttpError | OutOfMemoryError ? &mut Http | &mut AllocatorSends a GET request to url.
Associated function postJson#
pub effect fn postJson<T>(url: string, value: &T) -> Response
! HttpError | OutOfMemoryError
? &mut Http | &mut AllocatorSends value as JSON in a POST request to url.
Category: HTTP.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.