Skip to main content

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.Get
  • Http.Post
  • Http.Patch
  • Http.Put
  • Http.Delete
  • Http.Head
  • Http.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[];
});
Do not update views from postProcessFunction

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.

Talk to us