Exercise Wednesday

Now that we have established the basic functionality for our API, and put it through rigorous testing, it's time to take the next step and hook up our frontend.

Wait, but didn't we say in this lesson that we would not be focusing on .hbs and routing for our API - that we are providing raw data for users to query and not on frontend?

Yes, that is true: We won't be touching any .hbs templates this week, but we still need to create routes that fire the correct methods to add, read, update and delete data the API serves, so we'll still be working with our App.java controller file - they are in a sense our frontend!

Let's get started on that now by creating an App.java file in our src/main/java directory and adding our main method to it.

Our App.java file will be the file that communicates with the our DAO files, so we'll need to supply basic data in order to connect to our database, just as we did for To Do List.

Let's also declare our first route. There will be a lot of new concepts and code here, but we'll take it step by step.

Adding Data to our API

The first route we'll need to have and handle is the ability for Restaurants to get added to the API - after all, what is an API if it doesn't return any data?

Make your build.gradle look like the one below, and refresh your gradle imports.

build.gradle
...

dependencies {
   testCompile group: 'junit', name: 'junit', version: '4.12'
   compile "com.sparkjava:spark-core:2.6.0"
   compile 'org.slf4j:slf4j-simple:1.7.21'
   compile 'org.sql2o:sql2o:1.5.4'
   compile 'com.google.code.gson:gson:2.5'  // to be explained shortly
}
...

Next, add the following code to your App.java file, so that it looks like this:

src/main/java/App.java

import com.google.gson.Gson;
import dao.Sql2oFoodtypeDao;
import dao.Sql2oRestaurantDao;
import models.Restaurant;
import org.sql2o.Connection;
import org.sql2o.Sql2o;
import static spark.Spark.*;

public class App {

public static void main(String[] args) {
   Sql2oFoodtypeDao foodtypeDao;
   Sql2oRestaurantDao restaurantDao;
   Sql2oReviewDao reviewDao;
   Connection conn;
   Gson gson = new Gson();

   String connectionString = "jdbc:h2:~/jadle.db;INIT=RUNSCRIPT from 'classpath:db/create.sql'";
   Sql2o sql2o = new Sql2o(connectionString, "", "");

   restaurantDao = new Sql2oRestaurantDao(sql2o);
   foodtypeDao = new Sql2oFoodtypeDao(sql2o);
   reviewDao = new Sql2oReviewDao(sql2o);
   conn = sql2o.open();


   post("/restaurants/new", "application/json", (req, res) -> {
       Restaurant restaurant = gson.fromJson(req.body(), Restaurant.class);
       restaurantDao.add(restaurant);
       res.status(201);
       res.type("application/json");
       return gson.toJson(restaurant);
   });
  }
}

Understanding our New Route Handler

The upper portion of App.java, before the the route handler should look familiar: We are importing things, setting up our main() method, making our Sql2o objects, and setting up our database connection. Cool.

Notice that, just like To Do List, we opted to use an in-memory database for testing, but here we are actually writing to the filesystem to persist data (if the computer should shut down, for example). Make sure you adjust that string here.

But then the code looks similar, yet also quite different from our previous routes. There is lot to unpack.

Let's jump right in.

In our previous applications, our routes looked something like this:

...
//post: process new category form
post("/categories/new", (request, response) -> { //new
   Map<String, Object> model = new HashMap<>();
   String name = request.queryParams("name");
   Category newCategory = new Category(name);
   categoryDao.add(newCategory);

   List<Category> categories = categoryDao.getAll(); //refresh list of links for navbar.
   model.put("categories", categories);

   return new ModelAndView(model, "success.hbs");
}, new HandlebarsTemplateEngine());
...

Because we were interacting with our backend through a web-based frontend, we were able to capture data submitted by a form (the queryParams part). Then, we performed a set of actions, and sent the user a nice template to see the result of those actions. But because we now no longer have a web-based frontend, we have to explore a new way of getting data both IN and OUT of our application. How are we gonna go that? ALL in good time.

Once more, this is the new format for our route, this time, with some comments:

post("/restaurants/new", "application/json", (req, res) -> { //accept a request in format JSON from an app
   Restaurant restaurant = gson.fromJson(req.body(), Restaurant.class);//make java from JSON with GSON
   restaurantDao.add(restaurant);//Do our thing with our DAO
   res.status(201);//A-OK! But why 201??
   res.type("application/json");
   return gson.toJson(restaurant);//send it back to be displayed
});
  • In order to store data, we will: Send a request to our server using JSON, then transform that JSON to java objects, and write those Java objects into our database with SQL.

  • In order to retrieve data, we will: Retrieve data with SQL, build Java objects out of them, then transform those into JSON, and return them to the user.

What a trip! But why, I can hear you asking, can't we simply transform data directly from JSON to database data via SQL? What the blazes is GSON? I this a typo?

These are good questions. Let's answer them by learning a little more about JSON.

A Brief Introduction to JSON

You may have already heard the term JSON during Intro to Programming, and we will spend a significant amount of time on JSON in both JavaScript unit and React unit.

JSON stands for JavaScript Object Notation and is basically a way of representing data that looks like JavaScript objects.

One of our objects in JSON might look a bit like this:

{
  "restaurant": {
    "name": "Fish Witch",
    "address": "214 NE Broadway",
    "zipcode": "97232",
    "phone": "503-402-9874",
    "website": "http://fishwitch.com",
    "email": "[email protected]"
  }
}

Neat. This is fairly easy to read - our data is stored as key/value pairs, similar to a the HashMap that we are now familiar with. If it looks a lot like a JavaScript Object Literal - that's because it is! Sweet! But why do we care about this in Java?

JSON is everywhere in modern web applications. It's readable, it's lightweight, and it works super well with applications written in JavaScript, as it is JavaScript. But is also comparatively easy to get applications written in other languages to read it and generate it as well - including Java. This means that an API that returns JSON can be accessed by an application written in Java, Ruby, Python, JS, PHP and many more. This makes an API scalable and platform independent. Aha! Scalable! Platform Independent! Good words, powerful words, $$ words.

But because it is not Java per se, we cannot transform it directly to SQL, and as it is very difficult to connect to a SQL based database server with JavaScript (for reasons that are too complicated to explain here), we will have to transform our JSON data to Java first, then we can use our Java/SQL interface (JDBC) to write our data to the database server.

Our browser also can't understand Java or SQL commands. Because browsers can only parse HTML, CSS and JavaScript, and JSON is JavaScript, we need to transform Java back into JSON to present it to our user.

In order to easily move Java to JSON, we're going to ask for some help - this is what GSON is for.

GSON - A Google JSON library

GSON is a library created by Google in 2008 and freely available on Github. Give the repo a look; this is what a large scale project on a very professional level looks like. It's interesting to see. (Oh look! Their commit messages complete the phrase "it will" just like yours. Good job.)

In order to use Gson, we'll need instantiate a Gson object, call methods on that Gson object, passing Java objects to it as arguments.

The rest of the things you can see in the route - res.status(201); and return gson.toJson(restaurant) will be easier to understand once we view the result of what we are trying to submit.

But wait - if we don't have a UI, as in, no .hbs templates, no webpages, no forms - how do we interact with our routes?

Another good question! Another exciting new thing to learn about.

Meet Postman

We'll use an awesome, super cool and industry standard tool called Postman to fire JSON at our API and get JSON back when we make a request. You'll be using Postman pretty much any time you work with an API for the foreseeable future, so make sure you mention it on your LinkedIn profile as a tool you use!

Postman is already installed on Epicodus computers. You can download it for your home environment at the Postman website. You can choose to sign up for an account or use Postman without an account.

Using Postman

Let's go over the basics of making an API call in Postman. Let's query the Star Wars API to get some information about the planet Tatoouine. It's an API that returns JSON, just like ours is about to be!

Note: don't copy the URL shown in the image, use the URL mentioned in step 2.

postman-dashboard-image

  1. We choose the kind of request we'd like to make. In this case, it's a GET request.

  2. We can input the API URL in the URL box: https://swapi.co/api/planets/1/ You can then click on the Params button to add parameters as key-value pairs, but we do not need to do this for this simple query.

  3. Click on the Headers tab to add any headers. We don't need to add anything here. The Body field next to it is grayed-out because this is a GET request, but you can specify a request body if you're making a POST or PUT request.

  4. This is where you'll find the HTTP status code that accompanies the response. Aha! The call returned a 200 OK status. (why not 201? Google it.)

  5. The JSON format can be returned in "Pretty" form. This makes it very easy to read the JSON response and see how it's nested.

6.You can work with multiple API calls at once by using tabs.

  1. The Send button is self-explanatory. Once you've configured the call, click Send to make the request.

  2. You can even save API calls for later use. This is particularly useful when working on multi-day projects.

Go ahead and hit send, and you'll see a LOT of information returned to you - information in JSON that looks similar to what we are creating in our app!

Nice.

Let's use Postman to interface with our own app next!