Networking
For requests initiated by a view, dispatch one of Hosanna's generated Http
commands. This keeps request execution consistent across web, native targets,
and Roku worker tasks.
Make a request from a view
import { Http } from '@src-generated/async/AsyncManagerCommands';
import { IHsFetchResponse } from '@hs-src/hosanna-bridge-core/api';
this.dispatch<IHsFetchResponse>(Http.Get, {
url: 'https://api.example.com/items',
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((response) => {
this.items = response.json as Item[];
})
.catch((reason) => {
this.errorMessage = String(reason);
});
The supported commands are:
Http.GetHttp.PostHttp.PatchHttp.PutHttp.DeleteHttp.HeadHttp.DownloadFile
Request options sit beside url; there is no nested options object:
this.dispatch<IHsFetchResponse>(Http.Post, {
url: 'https://api.example.com/items',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'A new item',
}),
maxMs: 15_000,
});
body is a string. Serialize JSON yourself. Useful options include headers,
credentials, forceText, retainBodyError, maxMs, contextData, and
postProcessFunction.
An HTTP status response resolves as an IHsFetchResponse; inspect fields such
as ok, status, text, and json according to the endpoint. Transport or
command failures reject the HsPromise.
Post-process in the worker
postProcessFunction runs inside the HTTP command handler before the command is
completed. It must be an exported module-level function because Hosanna sends a
function pointer across the task boundary:
// response-handlers.ts
export function indexResponse(response: IHsFetchResponse) {
const requestKey = response.contextData?.requestKey;
console.info('Processed response for', requestKey);
}
// In the view
this.dispatch<IHsFetchResponse>(Http.Get, {
url: 'https://api.example.com/items',
contextData: { requestKey: 'featured' },
postProcessFunction: indexResponse,
}).then((response) => {
// This callback runs on the view side.
this.items = response.json as Item[];
});
The worker function must not capture this, mutate view state, or depend on
browser-only globals such as localStorage. Use the returned promise to update
the UI. If post-processing throws, the handler logs the error but still
completes the HTTP command.
contextData is attached to the response before post-processing and is useful
for serializable caller context. Inline functions, closures, and
.bind(this) are not valid function pointers.
Cancel a request
Pass an HsCancellationToken as the third argument to dispatch():
import { HsCancellationToken } from '@hs-src/hosanna-bridge-core/api';
private requestToken = new HsCancellationToken();
loadItems() {
return this.dispatch<IHsFetchResponse>(
Http.Get,
{ url: 'https://api.example.com/items' },
this.requestToken,
);
}
cancelLoad() {
this.requestToken.cancel();
}
Create a fresh token, or call reset(), before reusing a cancelled token.
Download a file
Http.DownloadFile uses a different argument and result shape:
this.dispatch<HttpDownloadFileResult>(Http.DownloadFile, {
url: 'https://cdn.example.com/catalogue.json',
path: 'tmp:/catalogue.json',
headers: { Authorization: `Bearer ${token}` },
timeoutMs: 30_000,
}).then((result) => {
if (!result.success) {
console.error(result.error);
}
});
The handler writes to a .partial file and renames it only after a successful
download.
Use HsFetch directly
Services already running in an appropriate execution context can call
HsFetch.fetch(url, options, cancellationToken) directly:
const fetcher = new HsFetch();
fetcher.fetch(
'https://api.example.com/items',
{ method: HttpMethod.GET },
cancellationToken,
);
For view code, prefer dispatch(Http.*) so task routing, mocks, and generated
command names remain in use.