Aurelia HTTP Client with Fetch and HttpClient
In this tutorial, you will learn about Aurelia HTTP Client with Fetch and HttpClient. We cover key concepts, practical examples, and best practices to help you master this topic.
Aurelia's HttpClient builds on the Fetch API to provide a clean, injectable service for making HTTP requests with configurable interceptors and error handling.
What You'll Learn
- Configuring and injecting HttpClient
- Making GET, POST, PUT, and DELETE requests
- Adding request and response interceptors
- Handling HTTP errors gracefully
- Cancelling in-flight requests
Why It Matters
Nearly every web application communicates with a backend server. Aurelia's HttpClient abstracts away boilerplate and provides a consistent API that integrates naturally with the Dependency Injection system.
Real-World Use
A dashboard application that fetches real-time metrics from a REST API, sends user updates via POST, and displays appropriate loading states and error messages for each request.
HttpClient Architecture
flowchart LR
A[Aurelia Component] --> B[HttpClient]
B --> C[Request Interceptors]
C --> D[Fetch API]
D --> E[Backend Server]
E --> F[Response Interceptors]
F --> G[Component Data]
style B fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px
Installing and Configuring HttpClient
First install the fetch client plugin:
npm install aurelia-fetch-client
Register the plugin in your main configuration:
import { PLATFORM } from 'aurelia-pal';
export function configure(aurelia) {
aurelia.use
.standardConfiguration()
.plugin(PLATFORM.moduleName('aurelia-fetch-client'));
aurelia.start().then(() => aurelia.setRoot());
}
Creating an Injectable API Service
import { autoinject } from 'aurelia-framework';
import { HttpClient } from 'aurelia-fetch-client';
@autoinject
export class ApiService {
constructor(private http: HttpClient) {
http.configure(config => {
config
.withBaseUrl('https://api.example.com/')
.withDefaults({
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.withInterceptor({
request(request) {
console.log(`Sending request to ${request.url}`);
return request;
},
response(response) {
console.log(`Received ${response.status} from ${response.url}`);
return response;
}
});
});
}
}
Expected output: Every HTTP request is logged to the console with its URL, and every response is logged with its status code.
Making GET Requests
export class UserList {
users: User[] = [];
loading = false;
error = null;
constructor(private api: ApiService) {}
async loadUsers(): Promise<void> {
this.loading = true;
this.error = null;
try {
const response = await this.api.http.fetch('users');
this.users = await response.json();
} catch (err) {
this.error = 'Failed to load users. Please try again.';
} finally {
this.loading = false;
}
}
}
Expected output: The users array is populated with JSON data from the API, or an error message is displayed if the request fails.
POST, PUT, and DELETE Requests
// POST - Create a resource
async createUser(user: User): Promise<User> {
const response = await this.http.fetch('users', {
method: 'POST',
body: JSON.stringify(user)
});
return response.json();
}
// PUT - Update a resource
async updateUser(id: number, user: User): Promise<User> {
const response = await this.http.fetch(`users/${id}`, {
method: 'PUT',
body: JSON.stringify(user)
});
return response.json();
}
// DELETE - Remove a resource
async deleteUser(id: number): Promise<void> {
await this.http.fetch(`users/${id}`, {
method: 'DELETE'
});
}
Expected output: createUser returns the newly created resource with its server-assigned ID. updateUser returns the updated resource. deleteUser resolves successfully with no content.
Adding Request and Response Interceptors
Interceptors let you centralize cross-cutting concerns like authentication:
http.configure(config => {
config.withInterceptor({
request(request) {
const token = localStorage.getItem('auth_token');
if (token) {
request.headers.append('Authorization', `Bearer ${token}`);
}
return request;
},
responseError(error) {
if (error.status === 401) {
// Redirect to login page
window.location.hash = '#/login';
}
return Promise.reject(error);
}
});
});
Expected output: All outgoing requests automatically include the Authorization header. If the server returns 401, the user is redirected to the login page.
Cancelling Requests with AbortController
export class SearchComponent {
private abortController: AbortController | null = null;
async search(query: string): Promise<void> {
// Cancel previous request
if (this.abortController) {
this.abortController.abort();
}
this.abortController = new AbortController();
try {
const response = await this.http.fetch(`search?q=${query}`, {
signal: this.abortController.signal
});
this.results = await response.json();
} catch (err) {
if (err.name === 'AbortError') {
console.log('Previous search cancelled');
return;
}
throw err;
}
}
}
Expected output: When the user types quickly, only the final search request completes. Previous requests are cancelled and do not update the results.
Common Mistakes
Not checking response.ok - The Fetch API does not reject on HTTP error statuses (4xx, 5xx). Always check
response.okor use an interceptor to throw on errors.Forgetting to configure withBaseUrl - Without a base URL, every request must include the full absolute URL, making code brittle when the API endpoint changes.
Stringifying request body for GET - GET requests should not have a body. Only use
bodywith POST, PUT, and PATCH methods.Not handling loading states - Users may be confused if there is no visual feedback during long requests. Always toggle a loading indicator.
Memory leaks from uncancelled requests - Components that unmount while a request is in flight can cause state updates on destroyed components. Cancel requests when the component is deactivated.
Practice Questions
- How do you set a base URL for all HttpClient requests?
- What method do you call to run code before every request and after every response?
- How does Aurelia's HttpClient differ from using the native Fetch API directly?
- What property of the Response object should you check to verify a request succeeded?
- How can you cancel an in-flight HTTP request in Aurelia?
Challenge: Build a typeahead search component that fetches results from an API as the user types. Cancel the previous request each time the input changes, and display a loading indicator while waiting for the response.
FAQ
Mini Project
Create a task manager service that communicates with a REST API. Implement CRUD operations for tasks, add an interceptor that logs every request duration, and show loading spinners while requests are in progress.
What's Next
With HTTP communication in place, learn how to validate user input before sending data to the server.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro