From c9acfe9eacf265aeab681cd334593933d980580a Mon Sep 17 00:00:00 2001 From: AshtonGlover <113224225+AshtonGlover@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:03:45 -0500 Subject: [PATCH 01/10] weather start --- .../cs/student/main/activity/Activity.java | 11 +++++----- .../student/main/server/ActivityHandler.java | 22 +++++++++---------- .../brown/cs/student/main/server/Server.java | 2 +- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/main/java/edu/brown/cs/student/main/activity/Activity.java b/src/main/java/edu/brown/cs/student/main/activity/Activity.java index c9ff378..64238b8 100644 --- a/src/main/java/edu/brown/cs/student/main/activity/Activity.java +++ b/src/main/java/edu/brown/cs/student/main/activity/Activity.java @@ -5,17 +5,16 @@ * there are a few fields that you could filter on if you wanted! */ public class Activity { - private String activity; - private String type; - private int participants; - private double price; - private String key; + private String temperature; + private String wind; + private String description; + private Object forecast; public Activity() {} @Override public String toString() { - return this.activity + " with " + this.participants + " people."; + return "The temperature is " + this.temperature; } // TODO 1.1: Replace the top function with this one below once you have modified the URI in TODO 1 diff --git a/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java b/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java index 390b694..b14acfb 100644 --- a/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java +++ b/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java @@ -43,14 +43,14 @@ public Object handle(Request request, Response response) { // ex. http://localhost:3232/activity?key=num Set params = request.queryParams(); // System.out.println(params); - String key = request.queryParams("key"); + String city = request.queryParams("city"); // System.out.println(key); // Creates a hashmap to store the results of the request Map responseMap = new HashMap<>(); try { // Sends a request to the API and receives JSON back - String activityJson = this.sendRequest(); + String activityJson = this.sendRequest(city); // Deserializes JSON into an Activity Activity activity = ActivityAPIUtilities.deserializeActivity(activityJson); // Adds results to the responseMap @@ -67,28 +67,28 @@ public Object handle(Request request, Response response) { return responseMap; } - private String sendRequest() throws URISyntaxException, IOException, InterruptedException { - // Build a request to this BoredAPI. Try out this link in your browser, what do you see? + private String sendRequest(String city) throws URISyntaxException, IOException, InterruptedException { + // Build a request to this Weather API. Try out this link in your browser, what do you see? // TODO 1: Looking at the documentation, how can we modify the URI to query based on specific activity keys? // HINT: you will want to replace random with a different endpoint! // TODO 1.1: complete the TODO in Activity.java - HttpRequest buildBoredApiRequest = + HttpRequest buildWeatherApiRequest = HttpRequest.newBuilder() - .uri(new URI("https://bored-api.appbrewery.com/random")) + .uri(new URI("https://goweather.herokuapp.com/weather/" + city)) .GET() .build(); // Send that API request then store the response in this variable. Note the generic type. - HttpResponse sentBoredApiResponse = + HttpResponse sentWeatherApiResponse = HttpClient.newBuilder() .build() - .send(buildBoredApiRequest, HttpResponse.BodyHandlers.ofString()); + .send(buildWeatherApiRequest, HttpResponse.BodyHandlers.ofString()); // What's the difference between these two lines? Why do we return the body? What is useful from // the raw response (hint: how can we use the status of response)? - System.out.println(sentBoredApiResponse); - System.out.println(sentBoredApiResponse.body()); + System.out.println(sentWeatherApiResponse); + System.out.println(sentWeatherApiResponse.body()); - return sentBoredApiResponse.body(); + return sentWeatherApiResponse.body(); } } diff --git a/src/main/java/edu/brown/cs/student/main/server/Server.java b/src/main/java/edu/brown/cs/student/main/server/Server.java index e9f1825..04901a6 100644 --- a/src/main/java/edu/brown/cs/student/main/server/Server.java +++ b/src/main/java/edu/brown/cs/student/main/server/Server.java @@ -61,7 +61,7 @@ public static void main(String[] args) { // Setting up the handler for the GET /order and /activity endpoints Spark.get("order", new OrderHandler(menu)); - Spark.get("activity", new ActivityHandler()); + Spark.get("weather", new ActivityHandler()); Spark.init(); Spark.awaitInitialization(); From e5367cbf0f4f4cdbedb5d39f83b4472cc0d5108a Mon Sep 17 00:00:00 2001 From: AshtonGlover <113224225+AshtonGlover@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:06:04 -0500 Subject: [PATCH 02/10] weather start --- .../edu/brown/cs/student/main/server/ActivityHandler.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java b/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java index b14acfb..662dacc 100644 --- a/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java +++ b/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java @@ -44,13 +44,13 @@ public Object handle(Request request, Response response) { Set params = request.queryParams(); // System.out.println(params); String city = request.queryParams("city"); - // System.out.println(key); + // System.out.println(city); // Creates a hashmap to store the results of the request Map responseMap = new HashMap<>(); try { // Sends a request to the API and receives JSON back - String activityJson = this.sendRequest(city); + String activityJson = this.sendRequest(); // Deserializes JSON into an Activity Activity activity = ActivityAPIUtilities.deserializeActivity(activityJson); // Adds results to the responseMap @@ -67,14 +67,14 @@ public Object handle(Request request, Response response) { return responseMap; } - private String sendRequest(String city) throws URISyntaxException, IOException, InterruptedException { + private String sendRequest() throws URISyntaxException, IOException, InterruptedException { // Build a request to this Weather API. Try out this link in your browser, what do you see? // TODO 1: Looking at the documentation, how can we modify the URI to query based on specific activity keys? // HINT: you will want to replace random with a different endpoint! // TODO 1.1: complete the TODO in Activity.java HttpRequest buildWeatherApiRequest = HttpRequest.newBuilder() - .uri(new URI("https://goweather.herokuapp.com/weather/" + city)) + .uri(new URI("https://goweather.herokuapp.com/weather/Providence")) .GET() .build(); From f397b9124b7d4668df34c3a97b4f92f4793bdb5b Mon Sep 17 00:00:00 2001 From: Andrew Chen Date: Fri, 17 Jan 2025 16:47:35 -0500 Subject: [PATCH 03/10] updated API to tvmaze --- .../java/edu/brown/cs/student/main/server/ActivityHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java b/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java index 662dacc..de6fcce 100644 --- a/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java +++ b/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java @@ -74,7 +74,7 @@ private String sendRequest() throws URISyntaxException, IOException, Interrupted // TODO 1.1: complete the TODO in Activity.java HttpRequest buildWeatherApiRequest = HttpRequest.newBuilder() - .uri(new URI("https://goweather.herokuapp.com/weather/Providence")) + .uri(new URI("https://api.tvmaze.com/search/shows?q=squid")) .GET() .build(); From daaf84107fa5e9c0a7a020abc7a6ee7c23fbe3ce Mon Sep 17 00:00:00 2001 From: Andrew Chen Date: Sat, 18 Jan 2025 14:58:06 -0500 Subject: [PATCH 04/10] adding tvShow API --- README.md | 42 ++++++++++--------- ...es.java => ActivityAPIUtilities copy.java} | 0 ...ctivityHandler.java => TVShowHandler.java} | 24 ++++++----- .../cs/student/main/television/TVShow.java | 26 ++++++++++++ .../main/television/TVShowAPIUtilities.java | 40 ++++++++++++++++++ 5 files changed, 102 insertions(+), 30 deletions(-) rename src/main/java/edu/brown/cs/student/main/activity/{ActivityAPIUtilities.java => ActivityAPIUtilities copy.java} (100%) rename src/main/java/edu/brown/cs/student/main/server/{ActivityHandler.java => TVShowHandler.java} (85%) create mode 100644 src/main/java/edu/brown/cs/student/main/television/TVShow.java create mode 100644 src/main/java/edu/brown/cs/student/main/television/TVShowAPIUtilities.java diff --git a/README.md b/README.md index a5c116a..ef66d3f 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,23 @@ -# Serializing and Deserializing Json +# Serializing and Deserializing Json This is a rough example of: -* using the Moshi Json library to serialize/deserialize; and -* using the SparkJava library to run an API server. -* making HTTP requests to external APIs. + +- using the Moshi Json library to serialize/deserialize; and +- using the SparkJava library to run an API server. +- making HTTP requests to external APIs. It should contain most of the programmatic reference you need to do Sprint 2. E.g.: -* running an API server; -* integration/system testing an API server via HTTP requests; -* serializing/deserializing classes; and -* serializing/deserializing generic classes; + +- running an API server; +- integration/system testing an API server via HTTP requests; +- serializing/deserializing classes; and +- serializing/deserializing generic classes; However, keep in mind that this code isn't _exactly_ what you need for Sprint 2. We expect you to use this as a reference, but not to borrow too heavily (you'll need to work with different types of JSON response, requests, etc.). Historical note: 0320 had previously used Gson for serializing/deserializing Json, but Gson seems to now be in maintenance mode, and doesn't support records well. So we switched starting in Fall 2022. -## Setup +## Setup You'll need two dependencies for handling Json: `moshi` and `moshi-adapters`, both from `com.squareup.moshi`. You should be able to copy and paste them from the `pom.xml` of this project. Similarly, you'll depend on SparkJava: `spark-core` from `com.sparkjava`. You should be able to use this pom.xml going forward! @@ -24,32 +26,35 @@ You'll need two dependencies for handling Json: `moshi` and `moshi-adapters`, bo We're building an application that serves two (disjointed) purposes: a functioning soup restaurant, and an [idea generator](https://www.youtube.com/watch?v=RtRg9BSGNMk&ab_channel=Deadaccount). The application is an API server that responds to "order" requests. The response is a serialized Soup. In its current form, the response always provides the first soup (if any exist). If no -recipe exists, the server replies with an error response. +recipe exists, the server replies with an error response. The idea generator works by providing any random idea for something to do today. However, it's a little too unconstrained, so it's your job to narrow down the search a bit! -## Running -You can run the example by executing the `server.edu.brown.cs.student.main.Server` class `main` method. This starts up a real webserver on your computer. By default, it's set to use port `3232`, so you should be able (while the server is running!) to send requests via `localhost:3232` in your browser. One endpoint is `order`, so `localhost:3232/order` will produce an order result (or an error). The other one is `activity` where `localhost:3232/activity` gives a random activity! +## Running + +You can run the example by executing the `server.edu.brown.cs.student.main.Server` class `main` method. This starts up a real webserver on your computer. By default, it's set to use port `3232`, so you should be able (while the server is running!) to send requests via `localhost:3232` in your browser. One endpoint is `order`, so `localhost:3232/order` will produce an order result (or an error). The other one is `weather` where `localhost:3232/weather` gives the weather for Providence! In order to run the server, run `mvn package` in your terminal then `./run` (using Git Bash for Windows users). This will be the same as the first Sprint. Take notice when transferring this run sprint to your Sprint 2 implementation that the path of your Server class matches the path specified in the run script. Currently, it is set to execute Server at `edu/brown/cs/student/main/server/Server`. Running through terminal will save a lot of computer resources (IntelliJ is pretty intensive!) in future sprints. There are also two test classes! Check these out for an idea of a new shape of testing! -## Exercise +## Exercise ### Code Walk Take a minute to familiarize yourself with the project. Start at the entry point of the project `Server.java` and explore the different handlers. + ### Run and Query Run the `server.edu.brown.cs.student.main.Server` and confirm that you are able to make web queries from your browser. Visit the endpoints specified in `Server.java`. What do they return right now? ### Making HTTP requests -See places labeled `TODO 1` in `ActivityHandler.java` and `TODO 1.1` in `Activity.java`. -Try to find the places in the code that correspond to the Architecture Diagram Hunt from the slides. +See places labeled `TODO 1` in `WeatherHandler.java` and `TODO 1.1` in `Weather.java`. + +Try to find the places in the code that correspond to the Architecture Diagram Hunt from the slides. -Then, once you are familiar with the shape of the HTTP request, see if you can use the parameters of an Activity object and the different endpoints of the BoredAPI to narrow down your search a little bit. Perhaps you could search for activities by their specific key! +Then, once you are familiar with the shape of the HTTP request, see if you can use the parameters of an Weather object and the different endpoints of the GoWeather API to narrow down your search a little bit. Perhaps you could search for activities by their specific key! ### Handling and manipulating more complex data @@ -57,12 +62,11 @@ See places labeled `TODO 2` in `OrderHandler.java` Right now, the `order` request produces whichever Soup appears first in the menu list. How would you modify the code so someone could order a soup based on its name? Perhaps start by getting the value of the query parameter given in the class! - ### Testing What other integration tests should have been written in the `edu.brown.cs.student.main.TestSoupAPIHandlers` class? -Add at least one. +Add at least one. ## Additional Info for Sprint 2 @@ -84,4 +88,4 @@ If you see the error below appear in your run console, you can feel free to igno `SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation -SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.` \ No newline at end of file +SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.` diff --git a/src/main/java/edu/brown/cs/student/main/activity/ActivityAPIUtilities.java b/src/main/java/edu/brown/cs/student/main/activity/ActivityAPIUtilities copy.java similarity index 100% rename from src/main/java/edu/brown/cs/student/main/activity/ActivityAPIUtilities.java rename to src/main/java/edu/brown/cs/student/main/activity/ActivityAPIUtilities copy.java diff --git a/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java b/src/main/java/edu/brown/cs/student/main/server/TVShowHandler.java similarity index 85% rename from src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java rename to src/main/java/edu/brown/cs/student/main/server/TVShowHandler.java index de6fcce..535a42c 100644 --- a/src/main/java/edu/brown/cs/student/main/server/ActivityHandler.java +++ b/src/main/java/edu/brown/cs/student/main/server/TVShowHandler.java @@ -1,7 +1,9 @@ package edu.brown.cs.student.main.server; import edu.brown.cs.student.main.activity.Activity; -import edu.brown.cs.student.main.activity.ActivityAPIUtilities; +import edu.brown.cs.student.main.television.TVShow; +import edu.brown.cs.student.main.television.TVShowAPIUtilities; + import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -19,10 +21,10 @@ * This class is used to illustrate how to build and send a GET request then prints the response. It * will also demonstrate a simple Moshi deserialization from online data. */ -// TODO 1: Check out this Handler. How can we make it only get activities based on specific keys? -// See Documentation here: https://bored-api.appbrewery.com +// TODO 1: Check out this Handler. How can we search up TV shows based on a specific keyword? +// See Documentation here: https://www.tvmaze.com/api -public class ActivityHandler implements Route { +public class TVShowHandler implements Route { /** * This handle method needs to be filled by any class implementing Route. When the path set in * edu.brown.cs.examples.moshiExample.server.Server gets accessed, it will fire the handle method. @@ -40,19 +42,19 @@ public Object handle(Request request, Response response) { // to be fulfilled. // If you specify a queryParam, you can access it by appending ?parameterName=name to the // endpoint - // ex. http://localhost:3232/activity?key=num + // ex. http://localhost:3232/show?keyword=squid Set params = request.queryParams(); // System.out.println(params); - String city = request.queryParams("city"); - // System.out.println(city); + String keyword = request.queryParams("keyword"); + // System.out.println(keyword); // Creates a hashmap to store the results of the request Map responseMap = new HashMap<>(); try { // Sends a request to the API and receives JSON back - String activityJson = this.sendRequest(); - // Deserializes JSON into an Activity - Activity activity = ActivityAPIUtilities.deserializeActivity(activityJson); + String showJson = this.sendRequest(); + // Deserializes JSON into an TVShow + TVShow show = TVShowAPIUtilities.deserializeActivity(showJson); // Adds results to the responseMap responseMap.put("result", "success"); responseMap.put("activity", activity); @@ -74,7 +76,7 @@ private String sendRequest() throws URISyntaxException, IOException, Interrupted // TODO 1.1: complete the TODO in Activity.java HttpRequest buildWeatherApiRequest = HttpRequest.newBuilder() - .uri(new URI("https://api.tvmaze.com/search/shows?q=squid")) + .uri(new URI("https://api.tvmaze.com/search/shows?q=")) .GET() .build(); diff --git a/src/main/java/edu/brown/cs/student/main/television/TVShow.java b/src/main/java/edu/brown/cs/student/main/television/TVShow.java new file mode 100644 index 0000000..bb9e326 --- /dev/null +++ b/src/main/java/edu/brown/cs/student/main/television/TVShow.java @@ -0,0 +1,26 @@ +package edu.brown.cs.student.main.television; + +/** + * This is a class that models an Activity received from the BoredAPI. It doesn't have a lot but + * there are a few fields that you could filter on if you wanted! + */ +public class TVShow { + private String temperature; + private String wind; + private String description; + private Object forecast; + + public TVShow() {} + + @Override + public String toString() { + return "The temperature is " + this.temperature; + } + + // TODO 1.1: Replace the top function with this one below once you have modified the URI in TODO 1 + + // @Override + // public String toString() { + // return "key " + this.key + " corresponds to this activity: " + this.activity; + // } +} diff --git a/src/main/java/edu/brown/cs/student/main/television/TVShowAPIUtilities.java b/src/main/java/edu/brown/cs/student/main/television/TVShowAPIUtilities.java new file mode 100644 index 0000000..5004298 --- /dev/null +++ b/src/main/java/edu/brown/cs/student/main/television/TVShowAPIUtilities.java @@ -0,0 +1,40 @@ +package edu.brown.cs.student.main.television; + +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; + +import java.io.IOException; + +/** + * This class shows a possible implementation of deserializing JSON from the TVMaze API into an + * TVShow. + */ +public class TVShowAPIUtilities { + + /** + * Deserializes JSON from the TVMaze into an TVShow object. + * + * @param jsonShow + * @return + */ + public static TVShow deserializeTVShow(String jsonTVShow) { + try { + // Initializes Moshi + Moshi moshi = new Moshi.Builder().build(); + + // Initializes an adapter to TVShow class then uses it to parse the JSON. + JsonAdapter adapter = moshi.adapter(TVShow.class); + + TVShow show = adapter.fromJson(jsonTVShow); + + return show; + } + // Returns an empty TVShow... Probably not the best handling of this error case... + // Notice an alternative error throwing case to the one done in OrderHandler. This catches + // the error instead of pushing it up. + catch (IOException e) { + e.printStackTrace(); + return new TVShow(); + } + } +} From 52b03256f093496d7c7927ee50f9438d4bbd22ad Mon Sep 17 00:00:00 2001 From: Andrew Chen Date: Sat, 18 Jan 2025 14:58:53 -0500 Subject: [PATCH 05/10] filename fix --- .../{ActivityAPIUtilities copy.java => ActivityAPIUtilities.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/edu/brown/cs/student/main/activity/{ActivityAPIUtilities copy.java => ActivityAPIUtilities.java} (100%) diff --git a/src/main/java/edu/brown/cs/student/main/activity/ActivityAPIUtilities copy.java b/src/main/java/edu/brown/cs/student/main/activity/ActivityAPIUtilities.java similarity index 100% rename from src/main/java/edu/brown/cs/student/main/activity/ActivityAPIUtilities copy.java rename to src/main/java/edu/brown/cs/student/main/activity/ActivityAPIUtilities.java From 85867296b7721a071117f0fe4ba7ecd4b4117aa2 Mon Sep 17 00:00:00 2001 From: Andrew Chen Date: Sat, 18 Jan 2025 15:14:35 -0500 Subject: [PATCH 06/10] updated TVShowHandler --- .../cs/student/main/server/OrderHandler.java | 2 +- .../cs/student/main/server/TVShowHandler.java | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/edu/brown/cs/student/main/server/OrderHandler.java b/src/main/java/edu/brown/cs/student/main/server/OrderHandler.java index 98205e6..d43c1e3 100644 --- a/src/main/java/edu/brown/cs/student/main/server/OrderHandler.java +++ b/src/main/java/edu/brown/cs/student/main/server/OrderHandler.java @@ -47,7 +47,7 @@ public Object handle(Request request, Response response) throws Exception { // TODO 2: Right now, we only serialize the first soup, let's make it so you can choose which // one you want! // Get Query parameters, can be used to make your search more specific - String soupname = request.queryParams("soupName"); + String soupName = request.queryParams("soupName"); // Initialize a map for our informative response. Map responseMap = new HashMap<>(); // Iterate through the soups in the menu and return the first one diff --git a/src/main/java/edu/brown/cs/student/main/server/TVShowHandler.java b/src/main/java/edu/brown/cs/student/main/server/TVShowHandler.java index 535a42c..c002751 100644 --- a/src/main/java/edu/brown/cs/student/main/server/TVShowHandler.java +++ b/src/main/java/edu/brown/cs/student/main/server/TVShowHandler.java @@ -1,6 +1,5 @@ package edu.brown.cs.student.main.server; -import edu.brown.cs.student.main.activity.Activity; import edu.brown.cs.student.main.television.TVShow; import edu.brown.cs.student.main.television.TVShowAPIUtilities; @@ -54,10 +53,11 @@ public Object handle(Request request, Response response) { // Sends a request to the API and receives JSON back String showJson = this.sendRequest(); // Deserializes JSON into an TVShow - TVShow show = TVShowAPIUtilities.deserializeActivity(showJson); - // Adds results to the responseMap + TVShow show = TVShowAPIUtilities.deserializeTVShow(showJson); + // Adds the data we care about to the responseMap responseMap.put("result", "success"); - responseMap.put("activity", activity); + responseMap.put("name", show.name); + responseMap.put("summary", show.summary); return responseMap; } catch (Exception e) { e.printStackTrace(); @@ -70,27 +70,27 @@ public Object handle(Request request, Response response) { } private String sendRequest() throws URISyntaxException, IOException, InterruptedException { - // Build a request to this Weather API. Try out this link in your browser, what do you see? - // TODO 1: Looking at the documentation, how can we modify the URI to query based on specific activity keys? + // Build a request to this TVMaze API. Try out this link in your browser, what do you see? + // TODO 1: Looking at the documentation, how can we modify the URI to search for shows based on a specific keyword that we specify? // HINT: you will want to replace random with a different endpoint! - // TODO 1.1: complete the TODO in Activity.java - HttpRequest buildWeatherApiRequest = + // TODO 1.1: complete the TODO in TVShow.java + HttpRequest buildTVShowApiRequest = HttpRequest.newBuilder() - .uri(new URI("https://api.tvmaze.com/search/shows?q=")) + .uri(new URI("https://api.tvmaze.com/search/shows?q=squid")) .GET() .build(); // Send that API request then store the response in this variable. Note the generic type. - HttpResponse sentWeatherApiResponse = + HttpResponse sentTVShowApiResponse = HttpClient.newBuilder() .build() - .send(buildWeatherApiRequest, HttpResponse.BodyHandlers.ofString()); + .send(buildTVShowApiRequest, HttpResponse.BodyHandlers.ofString()); // What's the difference between these two lines? Why do we return the body? What is useful from // the raw response (hint: how can we use the status of response)? - System.out.println(sentWeatherApiResponse); - System.out.println(sentWeatherApiResponse.body()); + System.out.println(sentTVShowApiResponse); + System.out.println(sentTVShowApiResponse.body()); - return sentWeatherApiResponse.body(); + return sentTVShowApiResponse.body(); } } From d8c169362faec636340d4ae51cde5a089763ad58 Mon Sep 17 00:00:00 2001 From: Andrew Chen Date: Sat, 18 Jan 2025 15:49:26 -0500 Subject: [PATCH 07/10] updated api endpoints to show --- src/main/java/edu/brown/cs/student/main/server/Server.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/brown/cs/student/main/server/Server.java b/src/main/java/edu/brown/cs/student/main/server/Server.java index 04901a6..5ccbd89 100644 --- a/src/main/java/edu/brown/cs/student/main/server/Server.java +++ b/src/main/java/edu/brown/cs/student/main/server/Server.java @@ -61,7 +61,7 @@ public static void main(String[] args) { // Setting up the handler for the GET /order and /activity endpoints Spark.get("order", new OrderHandler(menu)); - Spark.get("weather", new ActivityHandler()); + Spark.get("show", new TVShowHandler()); Spark.init(); Spark.awaitInitialization(); From 0a504f6cc6f775c90a2ca6435283b57e9ba554b2 Mon Sep 17 00:00:00 2001 From: AshtonGlover <113224225+AshtonGlover@users.noreply.github.com> Date: Sat, 18 Jan 2025 16:30:02 -0500 Subject: [PATCH 08/10] updated moshi parsing --- .../brown/cs/student/main/server/Server.java | 1 + .../cs/student/main/television/TVShow.java | 24 +++++++------------ .../main/television/TVShowAPIUtilities.java | 18 ++++++++++---- .../main/television/TVShowResponse.java | 8 +++++++ 4 files changed, 31 insertions(+), 20 deletions(-) create mode 100644 src/main/java/edu/brown/cs/student/main/television/TVShowResponse.java diff --git a/src/main/java/edu/brown/cs/student/main/server/Server.java b/src/main/java/edu/brown/cs/student/main/server/Server.java index 5ccbd89..9ba2400 100644 --- a/src/main/java/edu/brown/cs/student/main/server/Server.java +++ b/src/main/java/edu/brown/cs/student/main/server/Server.java @@ -62,6 +62,7 @@ public static void main(String[] args) { // Setting up the handler for the GET /order and /activity endpoints Spark.get("order", new OrderHandler(menu)); Spark.get("show", new TVShowHandler()); + Spark.init(); Spark.awaitInitialization(); diff --git a/src/main/java/edu/brown/cs/student/main/television/TVShow.java b/src/main/java/edu/brown/cs/student/main/television/TVShow.java index bb9e326..c29b6ad 100644 --- a/src/main/java/edu/brown/cs/student/main/television/TVShow.java +++ b/src/main/java/edu/brown/cs/student/main/television/TVShow.java @@ -4,23 +4,15 @@ * This is a class that models an Activity received from the BoredAPI. It doesn't have a lot but * there are a few fields that you could filter on if you wanted! */ +// Main TVShow class public class TVShow { - private String temperature; - private String wind; - private String description; - private Object forecast; - public TVShow() {} - - @Override - public String toString() { - return "The temperature is " + this.temperature; - } + //When looking at the raw response, notice that there are many additional fields beyond name and + //summary. Moshi allows us to pick just the fields we want to examine from our JSON, in this case, + //just name and summary. - // TODO 1.1: Replace the top function with this one below once you have modified the URI in TODO 1 + public String name; + public String summary; - // @Override - // public String toString() { - // return "key " + this.key + " corresponds to this activity: " + this.activity; - // } -} + public TVShow() {} +} \ No newline at end of file diff --git a/src/main/java/edu/brown/cs/student/main/television/TVShowAPIUtilities.java b/src/main/java/edu/brown/cs/student/main/television/TVShowAPIUtilities.java index 5004298..ef92a2c 100644 --- a/src/main/java/edu/brown/cs/student/main/television/TVShowAPIUtilities.java +++ b/src/main/java/edu/brown/cs/student/main/television/TVShowAPIUtilities.java @@ -2,8 +2,11 @@ import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.Moshi; +import com.squareup.moshi.Types; import java.io.IOException; +import java.lang.reflect.Type; +import java.util.List; /** * This class shows a possible implementation of deserializing JSON from the TVMaze API into an @@ -14,7 +17,7 @@ public class TVShowAPIUtilities { /** * Deserializes JSON from the TVMaze into an TVShow object. * - * @param jsonShow + * @param jsonTVShow * @return */ public static TVShow deserializeTVShow(String jsonTVShow) { @@ -22,11 +25,18 @@ public static TVShow deserializeTVShow(String jsonTVShow) { // Initializes Moshi Moshi moshi = new Moshi.Builder().build(); - // Initializes an adapter to TVShow class then uses it to parse the JSON. - JsonAdapter adapter = moshi.adapter(TVShow.class); + //Looking at the JSON response, we notice that the structure is a JSON array. In order to parse with moshi, + //we need to create a new parameterized type to deal with this list format. This is not necessary when the + //response is not a list of JSONs. + Type listType = Types.newParameterizedType(List.class, TVShowResponse.class); - TVShow show = adapter.fromJson(jsonTVShow); + // Create an adapter for the list of TVShowResponse + JsonAdapter> adapter = moshi.adapter(listType); + // Parse the JSON into a list of TVShowResponse objects + List showResponses = adapter.fromJson(jsonTVShow); + + TVShow show = showResponses.get(0).show; return show; } // Returns an empty TVShow... Probably not the best handling of this error case... diff --git a/src/main/java/edu/brown/cs/student/main/television/TVShowResponse.java b/src/main/java/edu/brown/cs/student/main/television/TVShowResponse.java new file mode 100644 index 0000000..a775596 --- /dev/null +++ b/src/main/java/edu/brown/cs/student/main/television/TVShowResponse.java @@ -0,0 +1,8 @@ +package edu.brown.cs.student.main.television; +import com.squareup.moshi.Json; + +public class TVShowResponse { + public TVShow show; + + public TVShowResponse() {} +} From afedfa9ecd78ccc80e43307d50c1474f24a6015c Mon Sep 17 00:00:00 2001 From: Andrew Chen Date: Sun, 19 Jan 2025 11:37:16 -0500 Subject: [PATCH 09/10] updated docs and comments for TVMaze --- README.md | 18 +++++++++--------- .../cs/student/main/activity/Activity.java | 2 +- .../cs/student/main/server/TVShowHandler.java | 17 +++++++++-------- .../cs/student/main/television/TVShow.java | 12 +++++++++--- .../cs/student/main/TestSoupAPIHandlers.java | 4 ++-- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index ef66d3f..e191590 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This is a rough example of: - using the Moshi Json library to serialize/deserialize; and -- using the SparkJava library to run an API server. +- using the Spring Boot library to run an API server. - making HTTP requests to external APIs. It should contain most of the programmatic reference you need to do Sprint 2. E.g.: @@ -23,16 +23,16 @@ You'll need two dependencies for handling Json: `moshi` and `moshi-adapters`, bo ## Demo Framing -We're building an application that serves two (disjointed) purposes: a functioning soup restaurant, and an [idea generator](https://www.youtube.com/watch?v=RtRg9BSGNMk&ab_channel=Deadaccount). +We're building an application that serves two (disjointed) purposes: a functioning soup restaurant, and a TV Show Querier. The application is an API server that responds to "order" requests. The response is a serialized Soup. In its current form, the response always provides the first soup (if any exist). If no recipe exists, the server replies with an error response. -The idea generator works by providing any random idea for something to do today. However, it's a little too unconstrained, so it's your job to narrow down the search a bit! +The TV Show Querier should be given a keyword to search for and returns the show name and a brief summary. However, the current implementation is missing some of these aspects, so it's your job to improve the search a bit! ## Running -You can run the example by executing the `server.edu.brown.cs.student.main.Server` class `main` method. This starts up a real webserver on your computer. By default, it's set to use port `3232`, so you should be able (while the server is running!) to send requests via `localhost:3232` in your browser. One endpoint is `order`, so `localhost:3232/order` will produce an order result (or an error). The other one is `weather` where `localhost:3232/weather` gives the weather for Providence! +You can run the example by executing the `server.edu.brown.cs.student.main.Server` class `main` method. This starts up a real webserver on your computer. By default, it's set to use port `3232`, so you should be able (while the server is running!) to send requests via `localhost:3232` in your browser. One endpoint is `order`, so `localhost:3232/order` will produce an order result (or an error). The other one is `show` where `localhost:3232/show` gives the TV Show Squid Game! In order to run the server, run `mvn package` in your terminal then `./run` (using Git Bash for Windows users). This will be the same as the first Sprint. Take notice when transferring this run sprint to your Sprint 2 implementation that the path of your Server class matches the path specified in the run script. Currently, it is set to execute Server at `edu/brown/cs/student/main/server/Server`. Running through terminal will save a lot of computer resources (IntelliJ is pretty intensive!) in future sprints. @@ -46,15 +46,15 @@ Take a minute to familiarize yourself with the project. Start at the entry point ### Run and Query -Run the `server.edu.brown.cs.student.main.Server` and confirm that you are able to make web queries from your browser. Visit the endpoints specified in `Server.java`. What do they return right now? +Run the `server.edu.brown.cs.student.main.Server` and confirm that you are able to make web queries from Postman. Visit the endpoints specified in `Server.java`. What do they return right now? ### Making HTTP requests -See places labeled `TODO 1` in `WeatherHandler.java` and `TODO 1.1` in `Weather.java`. +See places labeled `TODO 1.1` in `TVShowHandler.java` and `TODO 1.2` in `TVShow.java`. Try to find the places in the code that correspond to the Architecture Diagram Hunt from the slides. -Then, once you are familiar with the shape of the HTTP request, see if you can use the parameters of an Weather object and the different endpoints of the GoWeather API to narrow down your search a little bit. Perhaps you could search for activities by their specific key! +Then, once you are familiar with the shape of the HTTP request, see if you can use the parameters of the TVShow object and the TVMaze API endpoint to expand your search functionality. Perhaps you could search using a keyword that the user of our Server can specify, and return a summary in addition to just the show name! ### Handling and manipulating more complex data @@ -70,7 +70,7 @@ Add at least one. ## Additional Info for Sprint 2 -You can deserialize a Json object into a Java object with fewer fields. E.g., if you've got a Json object with 26 different fields: +You can deserialize a Json object into a Java object with fewer fields. E.g., if you have a Json object with 26 different fields: ```json { @@ -80,7 +80,7 @@ You can deserialize a Json object into a Java object with fewer fields. E.g., if } ``` -You can deserialize this into an object with only `"A"` and `"B"` fields. This is useful when processing very large, verbose response Json from other APIs, but only need a few fields. +You can deserialize this into an object with only `"A"` and `"B"` fields. This redues complexity when you're processing very large, verbose response Json from other APIs, but you only need a few fields. ## Note about SLF4J Error diff --git a/src/main/java/edu/brown/cs/student/main/activity/Activity.java b/src/main/java/edu/brown/cs/student/main/activity/Activity.java index 64238b8..4273ea1 100644 --- a/src/main/java/edu/brown/cs/student/main/activity/Activity.java +++ b/src/main/java/edu/brown/cs/student/main/activity/Activity.java @@ -17,7 +17,7 @@ public String toString() { return "The temperature is " + this.temperature; } - // TODO 1.1: Replace the top function with this one below once you have modified the URI in TODO 1 + // TODO 1.2: Replace the top function with this one below once you have modified the URI in TODO 1 // @Override // public String toString() { diff --git a/src/main/java/edu/brown/cs/student/main/server/TVShowHandler.java b/src/main/java/edu/brown/cs/student/main/server/TVShowHandler.java index c002751..3eb0d78 100644 --- a/src/main/java/edu/brown/cs/student/main/server/TVShowHandler.java +++ b/src/main/java/edu/brown/cs/student/main/server/TVShowHandler.java @@ -20,8 +20,7 @@ * This class is used to illustrate how to build and send a GET request then prints the response. It * will also demonstrate a simple Moshi deserialization from online data. */ -// TODO 1: Check out this Handler. How can we search up TV shows based on a specific keyword? -// See Documentation here: https://www.tvmaze.com/api +// TODO 1.1: Check out this Handler. The current logic will return the top result of searching "squid". public class TVShowHandler implements Route { /** @@ -51,7 +50,7 @@ public Object handle(Request request, Response response) { Map responseMap = new HashMap<>(); try { // Sends a request to the API and receives JSON back - String showJson = this.sendRequest(); + String showJson = this.sendRequest(keyword); // Deserializes JSON into an TVShow TVShow show = TVShowAPIUtilities.deserializeTVShow(showJson); // Adds the data we care about to the responseMap @@ -69,14 +68,16 @@ public Object handle(Request request, Response response) { return responseMap; } - private String sendRequest() throws URISyntaxException, IOException, InterruptedException { + private String sendRequest(String keyword) throws URISyntaxException, IOException, InterruptedException { // Build a request to this TVMaze API. Try out this link in your browser, what do you see? - // TODO 1: Looking at the documentation, how can we modify the URI to search for shows based on a specific keyword that we specify? - // HINT: you will want to replace random with a different endpoint! - // TODO 1.1: complete the TODO in TVShow.java + // TODO 1.1: Looking at the documentation, how can we modify the URI to search for shows based on a specific keyword that we specify? + // See Documentation here: https://www.tvmaze.com/api + String uri = "https://api.tvmaze.com/search/shows?q=" + keyword; + + // TODO 1.2: complete the TODO in TVShow.java HttpRequest buildTVShowApiRequest = HttpRequest.newBuilder() - .uri(new URI("https://api.tvmaze.com/search/shows?q=squid")) + .uri(new URI(uri)) .GET() .build(); diff --git a/src/main/java/edu/brown/cs/student/main/television/TVShow.java b/src/main/java/edu/brown/cs/student/main/television/TVShow.java index c29b6ad..44f8ea7 100644 --- a/src/main/java/edu/brown/cs/student/main/television/TVShow.java +++ b/src/main/java/edu/brown/cs/student/main/television/TVShow.java @@ -7,12 +7,18 @@ // Main TVShow class public class TVShow { - //When looking at the raw response, notice that there are many additional fields beyond name and - //summary. Moshi allows us to pick just the fields we want to examine from our JSON, in this case, - //just name and summary. + // Using Postman, examine the response JSon. When looking at the raw response, notice that there are many additional fields beyond name. + // Moshi allows us to pick just the fields we want to examine from our JSON and omit the rest. + + // TODO 1.2: Include a summary of the TVShow in addition to the name. Update toString() to display this summary. public String name; public String summary; public TVShow() {} + + @Override + public String toString() { + return "The TV Show is " + this.name; + } } \ No newline at end of file diff --git a/src/test/java/edu/brown/cs/student/main/TestSoupAPIHandlers.java b/src/test/java/edu/brown/cs/student/main/TestSoupAPIHandlers.java index 20ddf4f..af4147e 100644 --- a/src/test/java/edu/brown/cs/student/main/TestSoupAPIHandlers.java +++ b/src/test/java/edu/brown/cs/student/main/TestSoupAPIHandlers.java @@ -3,8 +3,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import com.squareup.moshi.Moshi; -import edu.brown.cs.student.main.server.ActivityHandler; import edu.brown.cs.student.main.server.OrderHandler; +import edu.brown.cs.student.main.server.TVShowHandler; import edu.brown.cs.student.main.soup.Soup; import java.io.IOException; import java.net.HttpURLConnection; @@ -77,7 +77,7 @@ public void setup() { // In fact, restart the entire Spark server for every test! Spark.get("order", new OrderHandler(menu)); - Spark.get("activity", new ActivityHandler()); + Spark.get("show", new TVShowHandler()); Spark.init(); Spark.awaitInitialization(); // don't continue until the server is listening } From 0228bf026f9318fbd042a716978d82d06b90902c Mon Sep 17 00:00:00 2001 From: Andrew Chen <113056266+andrewzchen66@users.noreply.github.com> Date: Sun, 19 Jan 2025 11:39:04 -0500 Subject: [PATCH 10/10] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e191590..7e89946 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ You can deserialize a Json object into a Java object with fewer fields. E.g., if { "A": 1, "B": 2, + "C": 3, + "D": 4, ... } ```