Overview
In the last lesson, we finished building out our request to the REST API to create a new listing. The finish line is in sight!
In this lesson, we will:
- Complete our mutation datafetcher method, and create some new listings
Connecting the dots in the datafetcher
Our schema is complete with all the types we need to make our mutation work, and ListingService
is updated with a new method. Now we just need to hook up the last piece in the datafetcher!
Let's first make sure that our generated code accounts for these new schema types, and restart our server.
Next, we'll jump back into our ListingDataFetcher
file. Remember the @DgsQuery
annotation we used on our class' featuredListings
method? Well, there's another we can use to mark a method as responsible for a mutation: @DgsMutation
!
Let's import it at the top of the file.
import com.netflix.graphql.dgs.DgsMutation;
Now we can add this annotation, and write our new method just below it. We'll give it the same name as our Mutation
type's field: createListing
.
public class ListingDataFetcher {@DgsMutationpublic void createListing() {}// other methods}
If you're using IntelliJ as your IDE, you'll see immediately that a yellow squiggly line appears beneath the name of our method. Hovering over it, we'll see a message that encourages us to use the @InputArgument
annotation, and add the input
argument the schema field expects.
@DgsMutationpublic void createListing(@InputArgument CreateListingInput input) {}
We haven't defined a CreateListingInput
Java class we can use as input
's data type, but fortunately DGS has us covered! After updating our schema and restarting our server, we should now see a new class made just for this purpose in our generated code folder: CreateListingInput
!
Tip: If you don't see the CreateListingInput
generated class, try restarting your server.
We can import it from our generated folder to complete our annotation.
// other importsimport com.example.listings.generated.types.CreateListingInput;// other annotations@DgsMutationpublic void createListing(@InputArgument CreateListingInput input) {}
We'll also find that we can now assign an appropriate return type to our createListing
method, as the generated code folder now contains an CreateListingPayload
class as well.
// other importsimport com.example.listings.generated.types.CreateListingInput;import com.example.listings.generated.types.CreateListingResponse;// other annotations@DgsMutationpublic CreateListingResponse createListing(@InputArgument CreateListingInput input) {}
Preparing the response body
We expect our method to return an instance of CreateListingResponse
, so let's create a new object that we can set when the call succeeds or fails.
CreateListingResponse response = new CreateListingResponse();
Just after this, we'll create a new try/catch
block, then return the response
.
CreateListingResponse response = new CreateListingResponse();try {// happy path} catch (Exception e) {// sad path}return response;
Inside the try
, we'll attach properties to our response if things go as expected. We want to use all of the properties that get passed into this method as input
, so we'll pass input
right to the ListingService
class' createListingRequest
method. We'll capture the newly-created listing the endpoint returns as a ListingModel
type called createdListing
. Then we'll set some properties on our response
showing that the listing was created as expected.
try {ListingModel createdListing = listingService.createListingRequest(input);response.setListing(createdListing);response.setCode(200);response.setMessage("success");response.setSuccess(true);} catch (Exception e) {// sad path}
Handling the sad path
If our call to the endpoint fails for any reason, we'll want to have control over what we send back to the client. Inside of the catch
block, we can account for any exceptions that are thrown. We'll set the exception's message, along with our other properties code
and success
, on the returned response
object.
try {// try block logic} catch (Exception e) {response.setListing(null);response.setCode(500);response.setMessage(e.getMessage());response.setSuccess(false);}
Running a simple mutation
We'll restart our server to make sure all of our changes have been applied.
In Explorer, fill out the following operation:
mutation CreateListing($input: CreateListingInput!) {createListing(input: $input) {codesuccessmessagelisting {titledescriptioncostPerNightamenities {namecategory}}}}
And add the following to the Variables panel.
{"input": {"title": "Mars' top destination","description": "A really cool place to stay","costPerNight": 44.0,"amenities": ["am-1", "am-2"],"numOfBeds": 2}}
When we run the operation, we'll see that this mutation works as expected! We can clearly see the values we set for code
, success
, and message
in our happy path—not to mention the details for the new listing we've just created!
Bravo, you've done it!
Journey's end
You've built a GraphQL API! You've got a working GraphQL server, jam-packed with intergalactic listings, that uses a REST API as a data source. You've written queries and mutations, and learned some common GraphQL conventions along the way. You've explored how to use GraphQL arguments, variables, and input types in your schema design. Take a moment to celebrate; that's a lot of learning!
But the journey doesn't end here! When you're ready to take your GraphQL API even further, jump into the next course in this series: Federation with Java & DGS.
Thanks for joining us in this course; we hope to see you in the next one!
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.