13. Wrapping up
10m

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

Task!

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 : @DgsMutation!

Let's import it at the top of the file.

datafetchers/ListingDataFetcher
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 : createListing.

public class ListingDataFetcher {
@DgsMutation
public 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 the schema expects.

@DgsMutation
public 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 imports
import com.example.listings.generated.types.CreateListingInput;
// other annotations
@DgsMutation
public 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.

datafetchers/ListingDataFetcher
// other imports
import com.example.listings.generated.types.CreateListingInput;
import com.example.listings.generated.types.CreateListingResponse;
// other annotations
@DgsMutation
public 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.

Task!

In Explorer, fill out the following :

mutation CreateListing($input: CreateListingInput!) {
createListing(input: $input) {
code
success
message
listing {
title
description
costPerNight
amenities {
name
category
}
}
}
}

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 , we'll see that this 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

Task!

You've built a API! You've got a working , jam-packed with intergalactic listings, that uses a REST API as a . You've written queries and , and learned some common GraphQL conventions along the way. You've explored how to use GraphQL , , 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 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!

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.