8. Consuming a data source
10m

Overview

With a new class wired up and ready to be called, we can connect some dots in our datafetcher method.

In this lesson, we will:

  • Connect our datafetcher to our
  • Account for unfamiliar JSON properties in the REST API response
  • Map JSON objects into Java classes we can manipulate and reason about

Consuming a data source

We now have a handy way to call out to the REST API for featured listings data. So... will running our FeaturedListings return real data?

query FeaturedListings {
featuredListings {
id
title
numOfBeds
costPerNight
closedForBookings
}
}

Not quite! When this is executed, the first thing DGS does is look for the corresponding featuredListings datafetcher method. In this case, that's the featuredListings method inside of ListingDataFetcher.

Of course, this method is still just returning hardcoded data. It can't call our ListingService.featuredListingsRequest method because it doesn't know about it yet.

Let's jump back into datafetchers/ListingDataFetcher to fix that.

Using ListingService in the datafetcher

First, we'll import ListingService, and give our class a listingService property. Then, we'll include a constructor that wires everything up on the class. (We'll also include IOException to handle any thrown exceptions shortly!)

ListingDataFetcher
// ...other imports
import com.example.listings.datasources.ListingService;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.IOException;
@DgsComponent
public class ListingDataFetcher {
private final ListingService listingService;
@Autowired
public ListingDataFetcher(ListingService listingService) {
this.listingService = listingService;
}
// featuredListings method
}

Note that we're using the Spring @Autowired annotation to take advantage of dependency injection. This means that the instance of ListingService will automatically be injected when we create an instance of the ListingDataFetcher class.

In our class' featuredListings datafetcher method (the one that DGS is going to call for the Query.featuredListings !), we'll first clean up our mocks.

@DgsQuery
public List<ListingModel> featuredListings() {
- ListingModel meteorListing = new ListingModel();
- meteorListing.setId("1");
- meteorListing.setTitle("Beach house on the edge of the Laertes meteor");
- meteorListing.setCostPerNight(360.00);
- meteorListing.setClosedForBookings(false);
- meteorListing.setNumOfBeds(3);
-
- ListingModel gasGiantListing = new ListingModel();
- gasGiantListing.setId("2");
- gasGiantListing.setTitle("Unforgettable atmosphere, unbeatable heat, tasteful furnishings");
- gasGiantListing.setCostPerNight(124.00);
- gasGiantListing.setClosedForBookings(true);
- gasGiantListings.setNumOfBeds(4);
-
- return List.of(meteorListing, gasGiantListing);
}

Next, we'll call the featuredListingsRequest method on our class' listingService instance, and return the results.

@DgsQuery
public List<ListingModel> featuredListings() {
return listingService.featuredListingsRequest();
}

Finally, because the featuredListingsRequest can throw an exception, let's also update our method signature for the featuredListings datafetcher.

public List<ListingModel> featuredListings() throws IOException {
// ...method body
}

Time to return to the Explorer! First, let's make sure that we restart our server so that we're running the latest changes.

Task!

Now let's navigate back to the Explorer and check that the connection to http://localhost:8080/graphql is still valid.

Let's make one little tweak to our before running it; let's change the name from FeaturedListings to GetFeaturedListings. (It's a bit more descriptive about exactly what we're doing with the featured listings!)

Aaaaand, drumroll...

query GetFeaturedListings {
featuredListings {
id
title
numOfBeds
costPerNight
closedForBookings
}
}

UH-OH! Another error!

https://studio.apollographql.com/sandbox/explorer

A screenshot of the Explorer, with an error in the response panel

Here's the message in our terminal:

Unrecognized field "description" (class com.example.listings.models.ListingModel),
not marked as ignorable (5 known properties: "title", "id", "numOfBeds", "costPerNight", "closedForBookings"])

We're seeing this error because our ListingModel class only knows how to handle five specific properties: id, title, numOfBeds, costPerNight, and closedForBookings.

But we're attempting to take each JSON object in our response, with many more properties, and convert each into an instance of ListingModel. When we inspect one of these listing objects from our REST endpoint, we can see that "hostId" is indeed one of its properties. But our ListingModel class doesn't know what to do with it!

The JsonIgnoreProperties annotation

The Jackson package gives us an annotation—JsonIgnoreProperties—to handle this very scenario. By setting @JsonIgnoreProperties on a class, and passing it an of ignoreUnknown = true, we can instruct our class to ignore any unfamiliar JSON properties it encounters, and handle what it does recognize.

Let's apply this annotation to our ListingModel class to take care of the error.

models/ListingModel
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ListingModel {
}

And with that, let's again restart our server to see the effect of adding this annotation.

Task!

Run the query, fetch the data!

Back in the Explorer, let's try that again.

query GetFeaturedListings {
featuredListings {
id
title
numOfBeds
costPerNight
closedForBookings
}
}

In the Response panel, we should now see actual data from our REST API!

https://studio.apollographql.com/sandbox/explorer

A screenshot of the Explorer, showing a successful response to our query

Key takeaways

  • Datafetcher methods can connect directly to the in our API
  • The JsonIgnoreProperties annotation allows us to ignore unfamiliar JSON properties when instantiating a new class

Up next

Amazing! We've translated the REST API response to the types that we defined in the schema, and we have a seamless experience. But right now, our listings are pretty sparse. Based on our mockups, we need to start exploring some additional functionality—such as querying for additional listing properties (hello, amenities!) or asking for a particular listing. Let's uplevel our API in the next lesson.

Previous

Share your questions and comments about this lesson

This course is currently in

beta
. 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.