Batch Requests

Oftentimes you will need to request data from multiple endpoints for a view within your application, such as observations and advisories. While you can perform multiple requests using multiple endpoint service classes, it is often more efficient to get all necessary data in a single request.

The Aeris Weather API offers the batch request for performing this action directly. Fortunately, the Aeris Weather SDK for iOS offers the AWFBatchRequest for the same functionality but with the ability to do so through the use of the same endpoint service classes you're already familiar with. This also eliminates the need for you to manage the batch request URL formatting or parsing to get the data you need.

Adding Endpoints

An AWFBatchRequest in the SDK is simply a series of individual endpoint service instances for each individual request. So to create a batch request, you first need to create instances for the individual endpoints you need to request data for:

AWFPlace *place = [AWFPlace placeWithCity:@"minneapolis" state:@"mn" country:@"us"];

AWFObservations *obs = [AWFObservations new];
obs.options.place = place;

AWFForecasts *forecasts = [AWFForecasts new];
forecasts.options.place = place;
forecasts.options.limit = 7;
forecasts.options.filterString = @"day";

AWFAdvisories *advisories = [AWFAdvisories new];
advisories.options.place = place;
let place = AWFPlace(city: "seattle", state: "wa", country: "us")

let obs = AWFObservations()
obs.options?.place = place

let forecasts = AWFForecasts()
forecasts.options?.place = place
forecasts.options?.limit = 7
forecasts.options?.filterString = "day"

let advisories = AWFAdvisories()
advisories.options?.place = place

Then create your batch request instance with the above endpoint objects:

AWFBatchRequest *request = [[AWFBatchRequest alloc] initWithEndpoints:@[obs, forecasts, advisories]];
let request = AWFBatchRequest(endpoints: [obs, forecasts, advisories])

Alternatively, you can create an empty batch request instance and add endpoints later:

AWFBatchRequest *request = [AWFBatchRequest new];
[request addEndpoint:advisories];
let request = AWFBatchRequest()
request.addEndpoint(advisories)

If you need to add an endpoint that uses a specific API action, such as within or search, you can either set the action property on the endpoint's options instance, or provide it when adding the endpoint to the batch request:

// setting the action on the options instance
advisories.options.action = AWFWeatherRequestActionSearch;

// or, providing the action when adding to the request
[request addEndpoint:advisories action:AWFWeatherRequestActionSearch options:nil];
// setting the action on the options instance
advisories.options?.action = .search

// or, providing the action when adding to the request
request.addEndpoint(advisories, action: .search, options: nil)

You can also add individual endpoint instances to a batch request by associating them with a unique key. Using this method allows you to easily reference that endpoint and its results directly:

[request addEndpoint:advisories forKey:@"advisories"];
request.addEndpoint(advisories, forKey: "advisories")

The keyed endpoint method can also be used for specific actions:

[request addEndpoint:advisories action:AWFWeatherRequestActionSearch forKey:@"advisories" options:nil];
request.addEndpoint(advisories, action: .search, forKey: "advisories", options: nil)

Once you've added an endpoint instance to a batch request by associating it with a key, you can retrieve that instance later:

AWFAdvisories *advisories = [request endpointForKey:@"advisories"];
let advisories = request.endpoint(forKey: "advisories")

Removing Endpoints

Similar to the methods support for adding endpoints to a batch request, you can also remove endpoints either by referencing the endpoint instance directly or using the key that was used when adding it:

// remove an endpoint by the instance
[request removeEndpoint:advisories];

// remove an endpoint by its key
[request removeEndpointForKey:@"advisories"];
// remove an endpoint by the instance
request.removeEndpoint(advisories)

// remove an endpoint by its key
request.removeEndpoint(forKey: "advisories")

You can also remove all endpoints from a batch request at once:

[request removeAllEndpoints];
request.removeAllEndpoints()

Performing the Request

Once you're batch request is setup with the necessary endpoints instances and options, you're ready to perform the actual request:

[request getWithOptions:nil completion:^(AWFBatchRequest * _Nonnull request, NSError * _Nullable error) {
    if (error) {
        NSLog(@"Batch request failed! - %@", error.localizedDescription);
        return;
    }

    // return objects for a specific endpoint instance
    NSArray *advisoryResults = [request resultsForEndpoint:advisories];

    // or, return objects for an endpoint associated with a specific key
    NSArray *advisoryResults = [request resultsForEndpointWithKey:@"advisories"];

    if ([advisoryResults count] > 0) {
        // do something with the data...
    }
}];
request.get(withOptions: nil) { (request, error) in
    guard error == nil else {
        print("Batch request failed! \(error)")
        return
    }

    // return objects for a specific endpoint instance
    if let advisoryResults = request.results(for: advisories) as? [AWFAdvisory], advisoryResults.count > 0 {
        // do something with the data...
    }

    // or, return objects for an endpoint associated with a specific key
    if let advisoryResults = request.resultsForEndpoint(withKey: "advisories") as? [AWFAdvisory], advisoryResults.count > 0 {
        // do something with the data...
    }
}

As the example request above demonstrates, once the request has completed you can access the returned objects for each endpoint directly using either the resultsForEndpoint: or resultsForEndpointWithKey: methods on your request instance. These methods will always return an array of model objects associated with that endpoint, or nil if there were no results for that endpoint request.

Updating the Batch Request Place

If you are performing a batch request for a single location, you may need to set or change the location being used for all endpoint instances within the batch request. Instead of iterating through the array of endpoints or setting the location directly for each instance, you can update the place across all endpoints using setPlaceForAllLoaders::

[request setPlaceForAllEndpoints:[AWFPlace placeWithCity:@"houston" state:@"tx" country:@"us"]];
request.setPlaceForAllEndpoints(AWFPlace(city: "houston", state: "tx", country: "us"))

Last modified: May 22, 2018