Level 7 - Milestone 8

Milestone 8 - Improving the Results

In this section we will improve the results we return to our users, by limiting what we give them to only the information they are interested in.

Before completion of this milestone, students will:

  • Add a Data Transfer Object that will hold the result we received from the external service
  • Ignore any fields from that request which we are not interested in returning to our users

Creating a Data Transfer Object

Currently we are receiving the data from the external service as a String. A much better option is to accept it in the form of a custom Java object that represents the data we receive. As a Java object, we can much more easily manipulate the response within our application. This process is simple once we have created the data transfer object.

To create the object, we could of course start from scratch and make it ourselves, but there are tools available that we can use to create a Java object (or objects) that represents the data contained in the JSON response. We will use jsonschema2pojo.org. All that needs to be done is to take a sample response that we received from a request to the service. We will also want to make sure to enter an appropriate name for the class, there are a few other options to select:

  • Target Language:
    • Java

  • Source Type
    • JSON

  • Annotation Style
    • Jackson 2.x



You may find that the sample response you submit contains too many results for the generator to work. You can use a JSON formatter to properly format the JSON, which will make it easier to delete all of the results except for one.

Add the DTO to the Project

Create a package name "dto" inside of the repository package, and deposit the newly-created Java object(s) there.

Using the DTO

Using the DTO is is rather simple. In the repository class, we will simply replace String.class with the name of our newly-created class, inside of the bodyToMono() method call. We can further improve our response to the user by simply returning the list of results from within the object we receive from the Library of Congress. After the .block(), simply call .getResults(), which will cause only the list of Result objects to be returned from this method. This will require us to update the return types of the methods in our repository, service, and controller classes to reflect this change. We should also update the swagger annotations in the controller class for this endpoint to show that we are no longer returning a String, as well as include that we are a returning a list of the specified object. The annotation should now looks something like this:
@ApiOperation(value = "Searches for articles matching the search term",
            notes = "Response may include multiple Result values.",
            response = Result.class,
            responseContainer="List")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Result(s) found"),
            @ApiResponse(code = 404, message = "Result(s) not found")
    })
                    

Getting Rid of Unwanted Fields

It is likely that there are a number of fields returned from the external service which we are uninterested in giving to our users. Unfortunately, jsonschema2pojo includes a lot of annotations which we do not need. We could have asked it to not include any annotations, but then all of the field names would have been converted to camel case with no indication of whether they are represented in snake case in the JSON we will receive.

First, we can remove any fields from the objects which we do not want to return to our users. Next, we can remove all annotations in the DTO class(es). However, at this point we want to make sure to annotate any fields that are original in snake case with an @JsonAlias("original_name") annotation. We can also use this opportunity to rename the fields in the Java class itself to be more appropriate if necessary, also indicating this difference from the JSON field with the @JsonAlias annotation.

After all the changes are made, if you rerun the application and test out the endpoint from the Swagger UI, you should no longer see the unnecessary fields, and and any renamed fields should show up accordingly.

Returning 404 Status When No Results Are Found

In the swagger notations for our LocController class, we have already state that the application will return a status code of 404 if there are no results found, it's time to make good on that promise. Remember that status codes are meant to succinctly tell the user the result of their request. In the event they provide a bad search term, it would be much nicer for us to simply tell them there were no results found than give them an empty list as a result. Notice this is similar to how it works with webpages, if you navigate to a subpage that doesn't exist, instead of simply displaying a blank html page, you receive a status of 404, meaning "not found". This can be accomplished in our code by updating the LocController method to something like the following:

List<Result>LocController results = locService.getResults(query);
if(CollectionUtils.isEmpty(results)){
    throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Result(s) not found.");
}
return results;

Summary of Code Changes for this Milestone