7. The listings REST API


It's time to jump into the we'll be using throughout this course.

In this lesson, we will:

  • Explore the listings REST API
  • Create a class that can manage our requests to different REST endpoints

Exploring real data

The data that our retrieve can come from all kinds of places: a database, a third-party API, webhooks, and so on. These are called . The beauty of is that you can mix any number of data sources to create an API that serves the needs of your client applications and graph consumers.

For the rest of the course, we're going to be using a REST API that provides listings data. We'll access it at the following URL.

Our REST API data source

Unfortunately, our is missing documentation and contains some that are no longer actively used. We'll use to make an API that's a lot more accessible and intuitive for our downstream consumers.

The next question we need to answer is how our data is structured in our REST API. This impacts how we retrieve and transform that data to match the in our schema.

Our goal is to retrieve data for featured listings, and there's an endpoint for exactly that: GET /featured-listings. Let's access the /featured-listings response by opening a new browser tab and navigating to the following URL.

The GET /featured-listings endpoint

When the page loads, we can inspect the shape of the response we get back.

This endpoint returns an array containing three objects with a number of different properties.


A screenshot of the featured listings endpoint response

Note: Seeing some messy JSON? Click the "Pretty print" checkbox at the top of the screen!

Let's compare these properties with the for the Listing type we defined in our :

type Listing {
id: ID!
title: String!
numOfBeds: Int
costPerNight: Float
closedForBookings: Boolean

Each object in the response array includes all of these , along with a bunch of other properties that we don't need for nowβ€”hostId, latitude, and longitude, to name a few!

The first object in the response, highlighting fields that match our schema
"id": "listing-1",
"title": "Cave campsite in snowy MoundiiX",
"description": "Enjoy this amazing cave campsite in snow MoundiiX, where you'll be one with the nature and wildlife in this wintery planet. All space survival amenities are available. We have complementary dehydrated wine upon your arrival. Check in between 34:00 and 72:00. The nearest village is 3AU away, so please plan accordingly. Recommended for extreme outdoor adventurers.",
"costPerNight": 120,
"hostId": "user-1",
"locationType": "CAMPSITE",
"numOfBeds": 2,
"photoThumbnail": "https://res.cloudinary.com/apollographql/image/upload/v1644350721/odyssey/federation-course2/illustrations/listings-01.png",
"isFeatured": true,
"latitude": 1023.4,
"longitude": -203.4,
"closedForBookings": false,
"amenities": [{"id": "am-2"} /* additional objects */]

It's okay that the response contains that we don't need. Our will take care of picking out the data properties that match what a asks for.

Setting up our data source

We know where our data is, and we understand how it's structured. Awesome. Now, we need a way to request everything it has to offer!

Because it's a very common task to fetch data from REST when building a API, provides a DataSource class for just that: the RESTDataSource.

Let's add this RESTDataSource class to our project.

In the terminal, in the root of our project, run:

npm install @apollo/datasource-rest

Now, we should start by creating a file that can hold all of the logic specific to this listings serviceβ€”we'll call it listing-api.ts, and we'll store it in a new folder called datasources.

πŸ“‚ src
┣ πŸ“‚ datasources
┃ β”— πŸ“„ listing-api.ts
┣ πŸ“„ graphql.d.ts
┣ πŸ“„ helpers.ts
┣ πŸ“„ index.ts
β”— πŸ“„ schema.graphql

First, we import the RESTDataSource class from the @apollo/datasource-rest package.

import { RESTDataSource } from "@apollo/datasource-rest";

We'll declare a class called ListingAPI that extends RESTDataSource. While we're here, let's export it before we forget!

export class ListingAPI extends RESTDataSource {
// ...

Next, let's assign our REST API's baseURL. This property is used as the prefix to all the calls.

export class ListingAPI extends RESTDataSource {
baseURL = "https://rt-airlock-services-listing.herokuapp.com/";

Note: Be sure that your ListingAPI class' baseURL value ends with a /. This will allow our helper class to make requests and append new paths to the baseURL without any errors.

Data source methods

We need to give our class a method that can reach out to the REST API endpoint that returns listing data. Let's call it getFeaturedListings.

getFeaturedListings() {

The RESTDataSource class provides helper methods for HTTP requests. In our case, we want to perform a GET request to the featured-listings endpoint.

getFeaturedListings() {

The this.get method is a generic function that lets us pass it a hand-crafted return type. From exploring our JSON response, we know that we get back an array, which contains several objects. We'll define the return type as an array of any types for now, but we'll improve on this later.

getFeaturedListings() {

Since our response from this endpoint is an array of objects, we can return it directly.

getFeaturedListings() {
return this.get<any[]>("featured-listings");

Fantastic! Our file is complete for now.


Which of these are true about data sources?

Key takeaways

  • Bringing a new into our API starts with assessing the shape of its responses, and determining how best to map them to our schema .
  • We can extend the RESTDataSource class to introduce a REST API as a to our .

Up next

Our is ready to use! But how do we actually use the ListingAPI class in our ?

In the next lesson, we'll explore functions, and see just how we can populate data for in our .


Share your questions and comments about this lesson

This course is currently in

. Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.