Skip to main content

Networking

The Hosanna UI Framework provides a robust networking layer that enables cross-platform HTTP communication. This documentation covers the key components and usage patterns for making network requests in your Hosanna applications.

Live Example

Try It

Trigger a request and observe how the view updates from the async response.

HsFetch

The core of Hosanna's networking capabilities is the HsFetch class, which provides a platform-agnostic implementation of the Fetch API. It works seamlessly across different platforms, including web browsers and Roku devices.

Basic Usage

const hosannaFetch = new HsFetch();
const response = await hosannaFetch.fetch(url, options);

Supported HTTP Methods

The framework supports all standard HTTP methods through the HttpMethod enum:

  • GET
  • POST
  • PUT
  • PATCH
  • DELETE
  • HEAD

HTTP Commands

Hosanna provides a high-level abstraction for HTTP requests through the HttpCommands class. This integrates with Hosanna's async command system for better state management and testing capabilities.

Making HTTP Requests

In a Hosanna view, you can make HTTP requests using the dispatch method:

// GET request
this.dispatch<IHsFetchResponse>(Http.Get, {
url: 'https://api.example.com/data'
})
.then((response) => {
// Handle response
})
.catch((error) => {
// Handle error
});

// POST request with body
this.dispatch<IHsFetchResponse>(Http.Post, {
url: 'https://api.example.com/data',
options: {
body: JSON.stringify({ key: 'value' }),
headers: {
'Content-Type': 'application/json'
}
}
});

Passing function pointers across tasks

You can pass a function pointer to be executed in a background task using AsyncFunctionPointer (module + export name). This is useful when you want to transform results off the main thread.

import { processRows } from './transformFunctions';

this.dispatch<IHsFetchResponse>(Http.Get, {
url: 'https://api.example.com/data',
transformFunction: { module: './transformFunctions', exportName: 'processRows' }
});

Signature:

// hosanna-api
export type AsyncFunctionPointer = { module: string; exportName: string };

The runtime can later resolve the function and run it in a background task (e.g., via a helper such as getAsyncFunctionFromPointer).

Features

1. Cancellation Support

Requests can be cancelled using the HsCancellationToken:

const cancellationToken = new HsCancellationToken();
hosannaFetch.fetch(url, options, cancellationToken);

// Cancel the request when needed
cancellationToken.cancel();

2. Mock Responses

For testing and development purposes, Hosanna supports mock responses through the developer utilities:

interface IDeveloperUtils {
getMockResponseForHttpRequest(method: HttpMethod, url: string): IHsFetchResponse | undefined;
}

3. Response Handling

The IHsFetchResponse interface provides a standardized way to handle responses:

interface IHsFetchResponse {
ok: boolean;
json: any;
status: number;
statusText: string;
headers: Record<string, string>;
ipAddress: string;
}

Best Practices

  1. Error Handling: Always implement proper error handling for network requests:

    this.dispatch<IHsFetchResponse>(Http.Get, { url })
    .then((response) => {
    if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json;
    })
    .catch((error) => {
    console.error('Network request failed:', error);
    });
  2. Request Cancellation: Use cancellation tokens for long-running requests that might need to be cancelled.

  3. Headers: Set appropriate headers for your requests, especially for content types and authentication:

    const options = {
    headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer your-token'
    }
    };
  4. Response Type Handling: Use TypeScript types to ensure type safety when handling responses:

    interface MyDataType {
    id: number;
    name: string;
    }

    this.dispatch<IHsFetchResponse>(Http.Get, { url })
    .then((response) => response.json as MyDataType)
    .then((data) => {
    // TypeScript knows the shape of 'data'
    });

Platform-Specific Considerations

The networking layer automatically handles platform-specific implementations:

  • Web: Uses the native Fetch API
  • Roku: Uses roUrlTransfer under the hood
  • Other Platforms: Can be extended through platform-specific implementations

Example Implementation

Here's a complete example of implementing a data fetching view:

@view('DataFetchingView')
export class DataFetchingView extends BaseView<ViewState> {
private loadData() {
const url = 'https://api.example.com/data';

return this.dispatch<IHsFetchResponse>(Http.Get, {
url,
options: {
headers: {
'Content-Type': 'application/json'
}
}
})
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json;
})
.catch((error) => {
console.error('Failed to fetch data:', error);
// Handle error in UI
});
}
}