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