Overview
With a new data source 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 data source
- 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 query return real data?
query FeaturedListings {featuredListings {idtitlenumOfBedscostPerNightclosedForBookings}}
Not quite! When this query 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!)
// ...other importsimport com.example.listings.datasources.ListingService;import org.springframework.beans.factory.annotation.Autowired;import java.io.IOException;@DgsComponentpublic class ListingDataFetcher {private final ListingService listingService;@Autowiredpublic 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 field!), we'll first clean up our mocks.
@DgsQuerypublic 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.
@DgsQuerypublic 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.
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 query 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 {idtitlenumOfBedscostPerNightclosedForBookings}}
UH-OH! Another error!
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 argument 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.
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.
Run the query, fetch the data!
Back in the Explorer, let's try that query again.
query GetFeaturedListings {featuredListings {idtitlenumOfBedscostPerNightclosedForBookings}}
In the Response panel, we should now see actual data from our REST API!
Key takeaways
- Datafetcher methods can connect directly to the data sources in our GraphQL API
- The
JsonIgnorePropertiesannotation 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 querying 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 GraphQL API in the next lesson.
Share your questions and comments about this lesson
This course is currently in
You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.