Topics Covered:
· REST APIs
· HTTP requests
· URLs and parameters
This assessment will assess your mastery of the following Learning Outcomes:
· You will be able to understand the difference between a client and a server.
· You will be able to construct a URL with query parameters.
· You will be able to use an API's documentation to determine how to interact with the API.
· You will be able to retrieve data from an API.
· You will be able to send data to an API.
· You will be able to write code that is organized, easily understood, and free of e
ors.
Assignment
Open the assessment and clone it to your computer.
You will create a client that calls the FruityVice API, an online fruit database, to generate a list of fruits. The FruityVice API allows you to make GET requests to retrieve information about different fruits. It also allows you to attempt to add new fruits to the database through a PUT request.
Documentation: https:
www.fruityvice.com/doc/index.html
You will be doing your work in the FruitHttpClient.java file and the FruitDTO.java file. Do not modify the code in Main.java.
Step One - Create the DTO classes FruitDTO and Nutritions
Create a DTO class in FruitDTO.java using the documentation and response from the FruityVice service. You have two classes inside of FruitDTO.json, which are FruitDTO and Nutritions.
Nutritions is a subclass of FruitDTO.
A sample FruitDTO represented as JSON will look something like this:
{ "genus": "Musa", "name": "Banana", "id": 2, "family": "Musaceae", "order": "Zingiberales", "nutritions": { "ca
ohydrates": 22.4, "protein": 0.1, "fat": 0.2, "calories": 96.5, "sugar": 17.2 }}
You can use the DTO Generator plugin we used in the reading to generate your getters and setters. Pass the JSON sample above into the DTO generator to generate the DTO.
After you have generated your DTO classes for FruitDTO and Nutritions, you will need to do the following
· Remove the word abstract from the class definition for FruitDTO.
· Right-click inside of Nutritions and generate a toString() method for all of the properties of Nutritions.
· Right-click inside of FruitDTO and generate a toString() method for all of the properties of FruitDTO.
Inside of the FruitDTO method toString(), you will need to replace this line:
", nutritions=" + nutritions +
With this:
", nutritions=" + nutritions.toString() +
This will allow us to see the properties inside the Nutritions class in our FruitDTO.
Step Two - Complete the method getDesiredURL(FruitCriteria fc) in FruitHttpClient.java
There will be an Enum called FruitCriteria with three values:
· ALL: This will hit the all fruits endpoint.
· LOW_CARB: This will get all fruits with less or equal to 5 grams of ca
ohydrates.
· HIGH_CALORIE: This will get all fruits with 100 or more calories.
Now, you will need to determine which URL you want to use based on the enum value we want to pass. To figure out the full URL for each of these criteria, look in the Fruity Vice documentation.
Once you know which URLs to use for each criterion, you can replace the "" in each return in each case statement with the URL string.
? Hint: Try out your GET queries in Postman or a web
owser to test that you have the co
ect URL and to see what response the server sends. A co
ect response will have a format similar to this:
[{ "genus": "Solanum", "name": "Tomato", "id": 5, "family": "Solanaceae", "order": "Solanales", "nutritions": { "ca
ohydrates": 3.9, "protein": 0.9, "fat": 0.2, "calories": 74, "sugar": 2.6 }}, { "genus": "Prunus", "name": "Apricot", "id": 35, "family": "Rosaceae", "order": "Rosales", "nutritions": { "ca
ohydrates": 3.9, "protein": 0.5, "fat": 0.1, "calories": 15, "sugar": 3.2 }}]
This is the actual response from the low-ca
endpoint, but you will see similar data in GET requests to the API.
Step Three - Complete the method getFruits() that sends GET requests to the FruityVice service and return the JSON response
This will retrieve fruits from the fruits endpoint based on whichever URL you pass it.
You are simply creating a GET request that calls the URL you passed in and returns the JSON response. You are not transforming the data into a list of FruitDTO objects in this method, all you need to do is return the response body. This will be very similar to what was done in the readings and in the activity.
Step Four - Complete the method getFruitsList() to serialize the response from getFruits() into a List of FruitDTO objects
In this method, you will take the response body from getFruitsList() and create a List of FruitDTO objects from that.
Remember the technique where you serialized a List of objects earlier by creating a new TypeReference from the Jackson li
ary. You will need to use that technique on the response from the GET requests to the FruityVice API.
Step Five - Complete the method createFruitDTO() to create a sample FruitDTO
Next, fill in the method createFruitDTO(). You can instantiate a new FruitDTO object and a new Nutritions object, and then for the properties of each object, fill in values using the setter methods you wrote earlier.
Remember, since Nutritions is a nested static class of FruitDTO, you can instantiate a Nutritions object like this:
FruitDTO.Nutritions nutrition = new FruitDTO.Nutritions();
Here are some sample values you can consider putting in your sample FruitDTO object:
{ "genus": "Fragaria", "name": "Blackbe
y", "family": "Rosaceae", "order": "Rosales", "nutritions": { "ca
ohydrates": 5.5, "protein": 0, "fat": 0.4, "calories": 29, "sugar": 5.4 }}
Of course, you will have to use your setter methods to fill in each of these items on the necessary FruitDTO and Nutritions objects.
Step Six - Fill in the fruitToJSON(FruitDTO) method in FruitHttpClient
Next, you will need to be able convert a FruitDTO object to a JSON string.
We can simply use the DTO to JSON conversion technique we learned from the Jackson li
ary from the readings.
Step Seven - Complete the method putFruit() to make a PUT request to add a new fruit to the database
IMPORTANT NOTE: The PUT request will likely fail as you may only input a new fruit once. If the entry already exists, the PUT will fail. THAT IS OKAY. The purpose of this section is to get practice implementing and sending a PUT request, even if you receive an e
or in response.
Fill in the method putFruit(String fruitJSON, String url). The method must take in a FruitDTO JSON string and use a PUT request to send it to the FruityVice service. The URL for the PUT request is already in main(), so you do not need to determine where to send the request.
? Hint: Try out your PUT queries in Postman or a web
owser to test that you are sending valid values from createFruitDTO() and to see what response the server sends. To do this, model your JSON after the sample described in Step Six and change values around as needed. From there, you can modify the values in the setters in createFruitDTO().
If you attempt to send a fruit that already exists in the database, you will receive an HTTP 422 "unprocessable entity" response back from the API. The request body will look something like this:
{"e
or": "The fruit either already existed or had an invalid json object attached"}
If you manage to PUT a new fruit, you see this message in your Postman testing:
{"success":"The fruit sent will be reviewed and eventually be added to the database!"}
Any response, e
or or success, is acceptable as long as the createFruitDTO() method is used to set the values and the DTO is used in the PUT request code.
Test your code
Unit tests have been provided in the FruitHttpClientTest.java, the FruitDTOTest.java, and the MainTest files. Make sure your code passes all of the tests defined there.
Once you have completed all of the steps in the assessment, if you attempt to run main(), your total output should look something like this:
Here is a list of all fruits: FruitDto{genus='Malus', name='Apple', id=6, family='Rosaceae', order='Rosales', nutritions='Nutritions{ca
ohydrates=11.4, protein=0.3, fat=0.4, calories=52.0, sugar=10.3}'}FruitDto{genus='Prunus', name='Apricot', id=35, family='Rosaceae', order='Rosales', nutritions='Nutritions{ca
ohydrates=3.9, protein=0.5, fat=0.1, calories=15.0, sugar=3.2}'}FruitDto{genus='Musa', name='Banana', id=1, family='Musaceae', order='Zingiberales', nutritions='Nutritions{ca
ohydrates=22.0, protein=1.0, fat=0.2, calories=96.0, sugar=17.2}'}FruitDto{genus='Fragaria', name='Bluebe
y', id=33, family='Rosaceae', order='Rosales', nutritions='Nutritions{ca
ohydrates=5.5, protein=0.0, fat=0.4, calories=29.0, sugar=5.4}'}FruitDto{genus='Prunus', name='Che
y', id=9, family='Rosaceae', order='None', nutritions='Nutritions{ca
ohydrates=12.0, protein=1.0, fat=0.3, calories=50.0, sugar=8.0}'}FruitDto{genus='Durio', name='Durian', id=60, family='Malvaceae', order='Malvales', nutritions='Nutritions{ca
ohydrates=27.1, protein=1.5, fat=5.3, calories=147.0, sugar=6.75}'}FruitDto{genus='Vitis', name='Grapes', id=47, family='Vitaceae', order='Vitales', nutritions='Nutritions{ca
ohydrates=18.1, protein=0.72, fat=0.16, calories=69.0, sugar=15.48}'}FruitDto{genus='Psidium', name='Guava', id=37, family='Myrtaceae', order='Myrtales', nutritions='Nutritions{ca
ohydrates=14.0, protein=2.6, fat=1.0, calories=68.0, sugar=9.0}'}FruitDto{genus='Citrus', name='Lemon', id=26, family='Rutaceae', order='Sapindales', nutritions='Nutritions{ca
ohydrates=9.0, protein=1.1, fat=0.3, calories=29.0, sugar=2.5}'}FruitDto{genus='Citrus', name='Lime', id=44, family='Rutaceae', order='Sapindales', nutritions='Nutritions{ca
ohydrates=8.4, protein=0.3, fat=0.1, calories=25.0, sugar=1.7}'}FruitDto{genus='Mangifera', name='Mango', id=27, family='Anacardiaceae', order='Sapindales', nutritions='Nutritions{ca
ohydrates=15.0, protein=0.82, fat=0.38, calories=60.0, sugar=13.7}'}FruitDto{genus='Cucumis', name='Melon', id=41, family='Cucu
itaceae', order='Cucu
itaceae', nutritions='Nutritions{ca
ohydrates=8.0, protein=0.0, fat=0.0, calories=34.0, sugar=8.0}'}FruitDto{genus='Citrus', name='Orange', id=2, family='Rutaceae', order='Sapindales', nutritions='Nutritions{ca
ohydrates=8.3, protein=1.0, fat=0.2, calories=43.0, sugar=8.2}'}FruitDto{genus='Carica', name='Papaya', id=42, family='Caricaceae', order='Caricacea', nutritions='Nutritions{ca
ohydrates=11.0, protein=0.0, fat=0.4, calories=43.0, sugar=1.0}'}FruitDto{genus='Pyrus', name='Pear', id=4, family='Rosaceae', order='Rosales', nutritions='Nutritions{ca
ohydrates=15.0, protein=0.4, fat=0.1, calories=57.0, sugar=10.0}'}FruitDto{genus='Diospyros', name='Persimmon', id=52, family='Ebenaceae', order='Rosales', nutritions='Nutritions{ca
ohydrates=18.0, protein=0.0, fat=0.0, calories=81.0, sugar=18.0}'}FruitDto{genus='Ananas', name='Pineapple', id=10, family='Bromeliaceae', order='Poales', nutritions='Nutritions{ca
ohydrates=13.12, protein=0.54, fat=0.12, calories=50.0, sugar=9.85}'}FruitDto{genus='Rubus', name='Raspbe
y', id=23, family='Rosaceae', order='Rosales', nutritions='Nutritions{ca
ohydrates=12.0, protein=1.2, fat=0.7, calories=53.0, sugar=4.4}'}FruitDto{genus='Fragaria', name='Strawbe
y', id=3, family='Rosaceae', order='Rosales', nutritions='Nutritions{ca
ohydrates=5.5, protein=0.8, fat=0.4, calories=29.0, sugar=5.4}'}FruitDto{genus='Solanum', name='Tomato', id=5, family='Solanaceae', order='Solanales', nutritions='Nutritions{ca
ohydrates=3.9, protein=0.9, fat=0.2, calories=74.0, sugar=2.6}'}FruitDto{genus='Citrullus', name='Watermelon', id=25, family='Cucu
itaceae', order='Cucu
itales', nutritions='Nutritions{ca
ohydrates=8.0, protein=0.6, fat=0.2, calories=30.0, sugar=6.0}'}Here is a list of low-ca
fruits: FruitDto{genus='Solanum', name='Tomato', id=5, family='Solanaceae', order='Solanales', nutritions='Nutritions{ca
ohydrates=3.9, protein=0.9, fat=0.2, calories=74.0, sugar=2.6}'}FruitDto{genus='Prunus', name='Apricot', id=35, family='Rosaceae', order='Rosales', nutritions='Nutritions{ca
ohydrates=3.9, protein=0.5, fat=0.1, calories=15.0, sugar=3.2}'}Here is a list of high-calorie fruits: FruitDto{genus='Durio', name='Durian', id=60, family='Malvaceae', order='Malvales', nutritions='Nutritions{ca
ohydrates=27.1, protein=1.5, fat=5.3, calories=147.0, sugar=6.75}'}Here is the response from attempting to put a fruit: {"success":"The fruit sent will be reviewed and eventually be added to the database!"}
It is acceptable to have an e
or in the final PUT attempt.
Codes on IntelliJ IDE
1) Fruit Criteria (Main.Java)
· package com.kenzie.app;
import java.io.IOException;
import java.util.List;
import necessary li
aries
enum FruitCriteria {
ALL,
LOW_CARB,
HIGH_CALORIE
}
public class Main {
public static void main(String[] args) throws IOException, Inte
uptedException {
do not change code in main()
XXXXXXXXXXString allFruitsDesiredUrl = FruitHttpClient.getDesiredURL(FruitCriteria.ALL);
XXXXXXXXXXString lowCa
FruitsDesiredUrl = FruitHttpClient.getDesiredURL(FruitCriteria.LOW_CARB);
XXXXXXXXXXString highCalorieFruitsDesiredUrl = FruitHttpClient.getDesiredURL(FruitCriteria.HIGH_CALORIE);
XXXXXXXXXXFruitHttpClient fruitHttpClient = new FruitHttpClient();
get all fruits and print them
XXXXXXXXXXString allFruitsResponseBody = fruitHttpClient.getFruits(allFruitsDesiredUrl);
XXXXXXXXXXList
allFruits = fruitHttpClient.getFruitsList(allFruitsResponseBody);
XXXXXXXXXXSystem.out.println("Here is a list of all fruits: ");
XXXXXXXXXXfor(FruitDTO fruit : allFruits){
XXXXXXXXXXSystem.out.println(fruit.toString());
}
XXXXXXXXXXSystem.out.println("");
get low ca
fruits and print them
XXXXXXXXXXString lowCa
FruitsResponseBody = fruitHttpClient.getFruits(lowCa
FruitsDesiredUrl);
XXXXXXXXXXList lowCa
Fruits