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
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
-
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);
}); -
Request Cancellation: Use cancellation tokens for long-running requests that might need to be cancelled.
-
Headers: Set appropriate headers for your requests, especially for content types and authentication:
const options = {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token'
}
}; -
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
});
}
}