Composite REST Resource
What Is a Composite Resource?
Section titled “What Is a Composite Resource?”In REST-based web services, a composite resource refers to a resource that is a combination of multiple other resources. This is useful when you need to aggregate data from different sources into a single cohesive response.
- A composite resource allows you to present a unified interface to the client while fetching and combining data from various data sources and remote APIs behind the scenes.
- Composite resources are essentially a way to aggregate and present data from multiple endpoints in a cohesive manner.
Example Scenario
Section titled “Example Scenario”Imagine an online travel booking service that provides information about flights, hotels, and car rentals. Each of these services could be managed by different APIs:
- Flights API: Provides information about available flights, airlines, schedules, etc.
- Hotels API: Provides information about hotel availability, room types, prices, etc.
- Car Rentals API: Provides information about car rental options, prices, car types, etc.
A composite resource could be created to offer a unified search feature, allowing users to find flights, hotels, and car rentals in a single query. Here’s how it might work:
Data Aggregation: Typical Workflow Example
Section titled “Data Aggregation: Typical Workflow Example”-
Composite Resource Endpoint:
/api/v1/travel-options -
Client Request:
- The client sends a request to the composite resource endpoint with parameters like
destination,check-in date,check-out date, andnumber of travelers.
- The client sends a request to the composite resource endpoint with parameters like
-
Backend Processing:
- The server-side logic calls the Flights API to get flight options to the specified destination.
- It then calls the Hotels API to check available accommodations for the specified dates.
- Finally, it queries the Car Rentals API to find available vehicles.
-
Aggregation:
- The responses from the individual APIs are aggregated into a single, cohesive response. This may involve data transformation, filtering, or merging.
-
Unified Response:
- The aggregated data is returned to the client as a single JSON response, which could look something like this:
JSON representation example of a composite resource: {"flights": [{"flight_id": "123","airline": "Airline A","price": 300,"departure": "2024-09-01T10:00:00Z","arrival": "2024-09-01T14:00:00Z"},{"flight_id": "456","airline": "Airline B","price": 350,"departure": "2024-09-01T12:00:00Z","arrival": "2024-09-01T16:00:00Z"}],"hotels": [{"hotel_id": "789","name": "Hotel A","price_per_night": 120,"rating": 4.5},{"hotel_id": "101","name": "Hotel B","price_per_night": 150,"rating": 4.0}],"car_rentals": [{"car_id": "111","company": "CarRentals A","price_per_day": 50,"type": "SUV"},{"car_id": "222","company": "CarRentals B","price_per_day": 45,"type": "Sedan"}]}json
Implementing a Composite Resource
Section titled “Implementing a Composite Resource” /*** Handles the HTTP GET request to retrieve the list of players and aggregate them with external data.** This function fetches a list of players from the database based on the filters passed in the request's query parameters,* and then fetches additional data from an external API (SportsDB) to aggregate both datasets into one.** The aggregated dataset is returned as a JSON response.** @param Request $request The HTTP request object, containing query parameters for filtering players.* @param Response $response The HTTP response object that will be populated with the aggregated data.* @param array $uri_args The URI arguments passed with the request, though not used in this method.** @return Response The HTTP response object containing the aggregated data in JSON format.*/public function handleGetPlayers(Request $request, Response $response, array $uri_args): Response{ $filters = $request->getQueryParams();
// Step 1) Pull the list of players from the database $players = $this->players_model->getAllPlayers($filters);
// Step 2) Fetch a list of all teams in a league belonging to the specified country and/or sport. $api_data = $this->getListOfLeagues();
// Step 3) Aggregate both datasets into a single dataset to be included in the response. // Step 3.a) TODO: validate the $api_data before merging it with the players dataset. $players["REPLACE_ME"] = $api_data;
// NOTE: the REPLACE_ME key needs to be changed. // You should use a descriptive, meaningful key (e.g., leagues, // exercises, shows, animals, planets, etc.)
return $this->renderJson($response, $players);}
/*** Fetches a list of leagues from the SportsDB API.** This function uses the Guzzle HTTP client to make a GET request to the SportsDB API to retrieve a list of soccer leagues* in a specified country. The API data is returned in a format that can be aggregated with other datasets.** @return mixed Returns the data fetched from the SportsDB API, typically an array or object containing the list of leagues.*/public function getListOfLeagues() : mixed{ /* Fetch a list of leagues from the SportsDB API Endpoint: https://www.thesportsdb.com/api/v1/json/3/search_all_leagues.php?c=England&s=Soccer Use Guzzle HTTP client to fetch data from the remote API that you've selected. * NOTE: Refer to Lab #5, Step #3). */ return [];}Example JSON Output
Section titled “Example JSON Output”The following example shows what the composite resource response would look like after aggregating player data from the database with league data from the SportsDB API:
{ "players": { // 👈 Your collection resource's data (e.g., players) "meta": { "current_page": 1, "page_size": 10, "total_pages": 5, "total_records": 47 }, "data": [ { "player_id": "1", "name": "John Doe", "position": "Forward", "team": "Manchester United", "jersey_number": 10 }, { "player_id": "2", "name": "Jane Smith", "position": "Midfielder", "team": "Chelsea FC", "jersey_number": 8 }, { "player_id": "3", "name": "Mike Johnson", "position": "Defender", "team": "Arsenal FC", "jersey_number": 5 } ] }, "leagues": [ // 👈 Resource data from the external API (e.g., leagues) { "idLeague": "4328", "strLeague": "English Premier League", "strSport": "Soccer", "strLeagueAlternate": "Premier League" }, { "idLeague": "4329", "strLeague": "English League Championship", "strSport": "Soccer", "strLeagueAlternate": "The Championship" }, { "idLeague": "4330", "strLeague": "Scottish Premier League", "strSport": "Soccer", "strLeagueAlternate": "SPL" } ]}