Host API
The Host API can be accessed from Javascript through the global slipway_host
object,
and from Rust through the generated slipway_host
module.
For other languages which compile to WASM, access will be through the code generated from the
slipway.wit
file (viewable using the slipway wit
command).
All calls to the Host API are checked on the host side to ensure the component has the appropriate permissions to perform the action being invoked.
Logging
The Host API provides methods for logging at the following levels: error
, warn
, info
, debug
, trace
.
Javascript
You can log from the standard console
methods:
console.error("This is an error.");
console.warn("This is a warning.");
console.log("This is information.");
console.debug("This is debug information.");
console.trace("This is trace information.");
Or directly through the slipway_host
object:
slipway_host.log_error("This is an error.");
slipway_host.log_warn("This is a warning.");
slipway_host.log_log("This is information.");
slipway_host.log_debug("This is debug information.");
slipway_host.log_trace("This is trace information.");
Rust (WASM)
The WIT file defines the following methods:
log-trace: func(message: string);
log-debug: func(message: string);
log-info: func(message: string);
log-warn: func(message: string);
log-error: func(message: string);
From Rust you can access these through the generated slipway_host
module:
slipway_host::log_error("This is an error.");
slipway_host::log_warn("This is a warning.");
slipway_host::log_info("This is information.");
slipway_host::log_debug("This is debug information.");
slipway_host::log_trace("This is trace information.");
Fetch
The Host API provides separate fetch methods for fetching binary or text content.
The fetch method, based on the URL format, provides a universal interface for fetching the following data:
- HTTP requests (e.g.
https://example.com/foo.txt
) - Local files (e.g.
file:../data/foo.txt
) - Environment variables (e.g.
env://FOO_BAR
) - Files contained in the current or other components (e.g.
component://svg_icons/foo.svg
, wheresvg_icons
is a Component Handle) - The responses of executing components (e.g.
component://noise?width=100&height=100
)
This overloading can be quite powerful. It allows components to take URLs as inputs, fetch them, and process the response without knowing whether the response came from an HTTP server, a file, or was generated dynamically by another component.
However the shape of the fetch API is optimized for HTTP requests, which can make it less convenient if you know that you just want to, for example, fetch an environment variable.
The Host API therefore also provides more specialized methods to these other actions, which will be discussed shortly.
Errors
Any general errors performing the fetch action will result in an error being returned
(thrown in Javascript, or as a Result::Err
variant in Rust), and the error's
response
field will be empty.
Any error status codes will also result in an error being returned
(thrown in Javascript, or as a Result::Err
variant in Rust), and the error's
response
field will contain the response from the server (with the body parsed as text).
In both cases the error will also contain a message
field containing the error message,
and an inner
field containing a list of strings representing any inner error messages.
In addition, the fetch operation will error if the component does not have the appropriate permissions.
Javascript
The fetch methods take an optional requestOptions
, whose fields are also optional:
const requestOptions = {
headers: { "content-type": "application/json" },
method: "GET",
body: '{ "a": 1 }',
timeout_ms: 1000,
};
Fetching text:
const response = await slipway_host.fetch_text(url, requestOptions);
console.log(response.status_code);
console.log(response.body); // `body` is a `string`.
console.log(response.headers); // `headers` is a list of [string, string] tuples
Fetching binary data:
const response = await slipway_host.fetch_bin(url, requestOptions);
console.log(response.status_code);
console.log(response.body); // `body` is a `Uint8Array`.
console.log(response.headers); // `headers` is a list of [string, string] tuples
We also provide a basic polyfill for the standard Javascript fetch
API:
const response = await fetch(url);
const type = response.headers.get("content-type");
if (type === "image/svg+xml" || type === "application/svg+xml") {
return response.text();
}
return response.arrayBuffer();
Rust (WASM)
The fetch methods take an optional requestOptions
, whose fields are also optional:
let request_options = slipway_host::RequestOptions {
headers: Some(vec![("content-type", "application/json")]),
method: Some("GET".to_string()),
body: Some("{ \"a\": 1 }".to_string().into_bytes()),
timeout_ms: Some(1000),
};
Fetching text:
let response = slipway_host::fetch_text(&url, Some(&request_options))?;
dbg!(response.status_code);
dbg!(response.headers); // `headers` is a `Vec<(String, String)>`
dbg!(response.body); // `body` is a String
Fetching binary data:
let response = slipway_host::fetch_bin(&url, Some(&request_options))?;
dbg!(response.status_code);
dbg!(response.headers); // `headers` is a `Vec<(String, String)>`
dbg!(response.body); // `body` is a Vec<u8>
Environment Variables
Javascript
The env
method never fails, and returns null
if either the environment variable
doesn't exist or if the component doesn't have permission to access it.
const env = slipway_host.env("FOO_BAR");
Alternatively, using fetch_text
:
const response = await slipway_host.fetch_text("env://FOO_BAR");
const env = response.body;
Rust
The env
method never fails, and returns None
if either the environment variable
doesn't exist or if the component doesn't have permission to access it.
let env = slipway_host::env("FOO_BAR");
Alternatively, using fetch_text
:
let response = slipway_host::fetch_text("env://FOO_BAR", None)?;
let env = response.body;
Component Files
Two methods are provided, load_text
and load_bin
, which each
take two arguments: a Component Handle and
a file path to the file within the component.
Errors
Loading a component file will error if the file does not exist, or if the component does not have appropriate permissions.
Javascript
const svg = await slipway_host.load_text("icons", "foo.svg");
const png = await slipway_host.load_bin("icons", "foo.png");
Alternatively, using the Fetch API:
const text_response = await slipway_host.fetch_text("component://icons/foo.svg");
const svg = text_response.body;
const bin_response = await slipway_host.fetch_bin("component://icons/foo.png");
const png = bin_response.body;
Run Components
Components can be run programmatically using the run
method. This method
takes two arguments: a Component Handle and
the input data for the component.
Only components listed in the component's callouts
can be run
(see the Rigs page) and the Components page
for more information).
Errors
The run
method will error if either the component handle isn't found, or the calling
component doesn't have the appropriate permissions, or if the component being run errors.
Javascript
const result = await slipway_host.run("increment", { value: 1 });
Alternatively, using the Fetch API:
const response = await slipway_host.fetch_text("component://increment?value=1");
const output = JSON.parse(response.body);
In the above example we take advantage of a feature where, when running a component, the query string parameters are automatically converted into a JSON structure and passed in as the component input.
For more complex input data, we can use the request body:
const response = await slipway_host.fetch_text(
"component://increment",
{ body: JSON.stringify({ value: 1 }) });
const output = JSON.parse(response.body);
You can also combine the two approaches, in which case the query string parameters are applied to the given body.
The query string parameters can contain periods and array indices, for example
component://increment?a.b[1].c[2]=1
, or even wildcards, for example
component://increment?a.b[*].c[2]=1
to apply values to every item at the given
path in the supplied body.
Rust
let result = slipway_host::run(
"increment",
&serde_json::to_string(&json!({ value: 1 })).unwrap(),
)?;
See the Javascript examples for examples of using the Fetch API to run.
Fonts
Fonts can be queries using the font
method. This method takes one argument
which is the font stack string.
Javascript
If none of the requested fonts are found, or the component does not have permission to
access them, then null
is returned.
let font_result = await slipway_host.font("Helvetica, Arial, sans-serif");
if (font_result) {
console.log(font_result.family) // The name of the font resolved from the stack.
console.log(font_result.data) // Data is a Uint8Array.
}
Rust
let maybe_resolved_font = slipway_host::font("Helvetica, Arial, sans-serif");
if let Some(resolved_font) = maybe_resolved_font {
dbg!(resolved_font.family); // The name of the font resolved from the stack.
dbg!(resolved_font.data); // Data is a Vec<u8>.
}
Binary Encoding and Decoding
The encode_bin
and decode_bin
methods allow you to encode binary data as a string
decode it again.
It is most often used when you need to store binary data in the output of a component, as encoding it as a string is more efficient than representing it as a numeric array in JSON.
Currently encoding uses base64, but this should not be relied upon and may change between Slipway versions. For example Slipway could in future cache the binary data and return a short ID to it.
Javascript
const encoded = slipway_host.encode_bin([1, 2, 3]); // Input can be a Uint8Array or number[]
const decoded = slipway_host.decode_bin(encoded); // Output is a Uint8Array
Rust
let encoded = slipway_host::encode_bin(&vec![1, 2, 3]);
let decoded = slipway_host::decode_bin(&encoded);