The Aurelia Fetch Client can handle various response types, including JSON, Blob, and text. Proper handling of these types is crucial for correctly processing server responses.
This example demonstrates how to fetch and process a JSON response.
This snippet shows how to handle binary data (like images or files) received from the server.
This interceptor transforms JSON responses using a custom transformData function, allowing for consistent data shaping across the application.
The Fetch Client can be used in a couple of different ways. You can create a new instance using the new
keyboard or use dependency injection to create an instance.
Here's a quick example of how to set up and make a GET request with the Aurelia Fetch Client in an Aurelia 2 application. The Fetch client ships with Aurelia and requires no additional installation. Import the HttpClient
from the @aurelia/fetch-client
package to use it.
You can inject a new instance into your component or service class by injecting the Fetch client with the newInstanceOf
decorator. This will ensure our component gets a new instance of the Fetch client.
You should avoid creating new instances of the Fetch client. Instead, you should create a service class or wrapper functionality that encapsulates your HTTP calls.
Many configuration options available to the native Fetch API are also available in the Aurelia Fetch Client. You can set default headers, create interceptors (more on that further down) and more.
requestError
acts as a Promise rejection handler during Request creation and request interceptor execution. It will receive the rejection reason and can either re-throw or recover by returning a valid Request.
responseError
is similar to requestError
and acts as a Promise rejection handler for response rejections.
These methods on the interceptor object can also return a Promise
for their respective return values.
There are some caveats with the default Fetch implementation around error handling that Aurelia conveniently provides helper methods to work with.
config.rejectErrorResponses()
will add a response interceptor that causes responses with unsuccessful status codes to result in a rejected Promise.
config.useStandardConfiguration()
will apply rejectErrorResponses()
, and also configure credentials: 'same-origin'
as a default on all requests.
The Fetch API has no convenient way of sending JSON in the body of a request. Objects must be manually serialized to JSON, and the Content-Type
header must be set appropriately. the Fetch package includes a helper called json
for this.
For the example above, if you prefer .get
/.post
/etc.. style, you can also use corresponding method on the Fetch client
Robust error handling is crucial for any application making HTTP requests. It involves not only catching and responding to errors but also implementing strategies for error recovery and user notification.
The Fetch client comes with a retry implementation that can be configured like the following example
There are several options can be specified, per the following type:
Note that for option strategy
, there are 4 default strategies provided via the export RetryStrategy
from the @aurelia/fetch-client
package:
Per the names suggest, the interval which a request will be attempted again will be calcuated accordingly for each strategy. If you want to supply your own strategy, the strategy
option can take a callback to be invoked with the number of the retry and the return value is treated as the time to wait until the next fetch attempt.
Handling forms with the Fetch Client involves preparing FormData objects and sending them via HTTP requests. This is essential for tasks like submitting form data or uploading files.
This example shows how to submit form data using FormData
.
Here's how to upload a file using the Fetch Client, which is common in many web applications.
You can also use resolve
In the example above, withBaseUrl()
is used to specify a base URL that all fetches will be relative to. The withDefaults()
method allows passing an object that can include any properties described in the optional init
parameter to the and will be merged into the new before it is passed to the first request interceptor.
withInterceptor()
enables passing an object which can provide any of these four optional methods: request
, requestError
, response
, and responseError
. Here's an explanation of how each of these methods works:request
takes the that will be passed to window.fetch()
after interceptors run. It should return the same Request or create a new one. It can also return a to short-circuit the call to fetch()
and complete the request immediately. Interceptors will handle errors thrown in request interceptors.
response
will be run after fetch()
completes, and will receive the resulting . As with request
, it can either pass the Response along, return a modified response, or throw.
Configuring the Fetch Client for specific needs like setting default headers, handling timeouts, or implementing retry logic can enhance application performance and reliability.
Setting default headers ensures that every request sent via the Fetch Client includes these headers, maintaining consistency and reducing redundancy in your code.
This configuration sets the default Accept
and Content-Type
headers to handle JSON data and adds an Authorization
header with a bearer token.
Response caching can improve performance by storing and reusing responses for identical requests.
This configuration adds a simple caching layer, storing responses in a map and retrieving them for identical subsequent requests. It ensures faster response times for repeated requests to the same endpoints with the same parameters.
This example sets up a retry mechanism that retries the request up to three times with a one-second delay between attempts, but only for certain types of errors (like network errors).
The Fetch client provides a default implementation of retry interceptor similar like above, with more options for configuration. It's enabled when called httpClient.configure(c => c.withRetry(...))
The @aurelia/fetch-client
is a HTTP client for making network requests, designed to integrate seamlessly with Aurelia 2 applications. It is built on top of the Fetch API, providing an easy-to-use and promise-based interface to communicate with RESTful APIs.
The Aurelia Fetch Client comes with a host of features that make it a powerful tool for developers:
Fetch API Compliance: Utilizes the native Fetch API, ensuring a standards-compliant requesting mechanism.
Fluent and Chainable API: Offers a fluent interface to build requests in a readable and chainable manner.
Flexible Interceptors: Interceptors allow for request and response manipulation, enabling tasks such as adding headers, logging, or handling authentication globally.
Configurable: Easy to configure with sensible defaults that can be overridden as needed for different request scenarios.
Promise-based Workflow: Built around Promises, it provides a streamlined way to handle asynchronous HTTP operations.
Compared to the native Fetch API, Aurelia's Fetch Client offers several advantages. It provides a more straightforward configuration process, better default settings for common scenarios, and helper methods that simplify common tasks. For instance, setting default headers or handling JSON data becomes more intuitive with Aurelia's approach.
The Aurelia Fetch Client supports a variety of configuration options to tailor its behavior to your application's needs. These include setting default headers, base URLs, timeout settings, and more.
Enhance the capabilities of your HTTP requests and responses by using interceptors. This feature allows you to handle various cross-cutting concerns such as logging, authentication, or adding common headers.
Efficient error handling is crucial for a robust application. The Aurelia Fetch Client provides mechanisms for catching and managing errors that may occur during the request lifecycle.
For more complex scenarios, the Aurelia Fetch Client supports advanced configurations and use cases, such as creating custom interceptors, managing request retries, and working with various content types.
The @aurelia/fetch-client
is a versatile HTTP client that simplifies network communication in Aurelia 2 applications. By leveraging the Fetch API and providing additional features for customization and extensibility, it equips developers with the tools required for efficient and effective API interactions.
For in-depth information on configuration, usage examples, interceptor implementation, and more, please explore the other sections of this documentation.
Interceptors are a powerful feature of Aurelia's Fetch Client, allowing you to modify requests and responses or perform side effects like logging and authentication. They enable developers to implement centralized logic that handles various aspects of HTTP communication.
Interceptors can be attached to the Fetch Client configuration and consist of four optional methods: request
, requestError
, response
, and responseError
. Here’s how each method operates:
request
: Invoked before a request is sent. This method receives the Request
object and can modify it or return a new one. It can also return a Response
object to short-circuit the fetch operation.
requestError
: Triggered if an error occurs during the request generation or in a request
interceptor. This method can handle the error and potentially recover by returning a new Request
object.
response
: Called after the server responds. This method receives the Response
object, which can be manipulated or replaced before being returned to the original caller.
responseError
: Invoked when a fetch request fails due to network errors or when a response
interceptor throws an error. It can handle the error and perform tasks like retrying the request or returning an alternative response.
Each method can return either their respective expected object (Request
or Response
) or a Promise
that resolves to it.
The logging interceptor tracks all outgoing requests and incoming responses, which is useful for debugging and monitoring.
The authentication interceptor appends a bearer token to each request, centralizing the authentication handling for secured API endpoints.
A robust error handling interceptor intercepts responses and response errors to manage API errors centrally.
Single Responsibility: Each interceptor should have a single responsibility, whether it's logging, adding headers, or error handling.
Order Matters: The order in which interceptors are added can affect their behavior, as they are executed in a pipeline.
Error Recovery: Consider implementing strategies within requestError
and responseError
interceptors for error recovery, such as retrying failed requests.
Avoid Side Effects: While interceptors can perform side effects, it's best to avoid them unless necessary for functionality like logging.
Short-Circuiting: Interceptors can short-circuit the fetch process by returning a Response
object in the request
interceptor.
When implementing interceptors, it is important to be aware of their full potential and how to avoid common pitfalls:
Interceptor Lifecycle: Interceptors are executed in the order they are registered. Understanding this order is crucial when you have dependencies between interceptors' operations.
Asynchronous Interceptors: Interceptors can return Promise
s, allowing for asynchronous operations. Ensure that any asynchronous code is handled properly to avoid unexpected behavior.
Pitfalls to Avoid: Be cautious when changing shared request configurations within an interceptor, as this might affect other application parts. Always treat the Request
and Response
objects as immutable.
Performance Impacts: Remember that complex logic within interceptors can impact the performance of your HTTP requests. Monitor the performance to ensure that interceptors do not introduce significant delays.
Debugging Interceptors: Use logging within interceptors to help identify the flow of requests and responses. This can be invaluable when debugging unexpected behavior.
Organizing Interceptors: For better maintainability, organize interceptors in a logical structure, such as grouping related interceptors together or keeping them close to the feature modules they relate to.
Advanced Use Cases: For more complex scenarios, consider using interceptors for response caching, request retries with backoff strategies, or implementing custom prioritization of outgoing requests.