Building the API
We are ready to complete our API.
Recall the following HTTP verbs (operations):
- POST: to create a resource
- PUT: to update it
- GET: to read it
- DELETE: to delete it
We already handle one HTTP GET request.
Read Courses | |
---|---|
HTTP Method | GET |
API Endpoint | /api/courses |
Request Path Parameter | |
Request Query Parameter | |
Request Body | |
Response Body | JSON array of courses |
Response Status | 200 |
Here is the code that enables our server to listen for and handle the HTTP GET request directed to /api/courses
:
get("/api/courses", (req, res) -> {
res.type("application/json");
return courses;
}, gson::toJson);
The /api/courses
is known as a route and so the method above is called a route method. Spark supports route methods that correspond to all HTTP requests: get, post, and so on.
The callback (lambda function) provided as the second argument to the above route method is known as a route handler. We need to update this handler to use a CourseDao to connect our API to our database. Here is the updated ApiServer.main
method:
public static void main(String[] args) throws URISyntaxException {
port(getHerokuAssignedPort());
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
CourseDao courseDao = getCourseDao();
get("/api/courses", (req, res) -> {
try {
List<Course> courses = courseDao.readAll();
res.type("application/json");
return gson.toJson(courses);
} catch (DaoException ex) {
throw new ApiError(ex.getMessage(), 500);
}
});
}
Notice the use of getCourseDao()
method. Here is its implementation:
private static CourseDao getCourseDao() throws URISyntaxException {
String databaseUrl = System.getenv("DATABASE_URL");
URI dbUri = new URI(databaseUrl);
String username = dbUri.getUserInfo().split(":")[0];
String password = dbUri.getUserInfo().split(":")[1];
String dbUrl = "jdbc:postgresql://" + dbUri.getHost() + ':'
+ dbUri.getPort() + dbUri.getPath() + "?sslmode=require";
Sql2o sql2o = new Sql2o(dbUrl, username, password);
return new Sql2oCourseDao(sql2o);
}
Also notice the use of ApiError
. Here is its implementation:
/**
* A generic exception for API errors.
*/
public class ApiError extends RuntimeException {
private final int status;
/**
* Construct ApiError.
*
* @param message Error message.
* @param status API response code.
*/
public ApiError(String message, int status) {
super(message);
this.status = status;
}
/**
* Get Error code.
*
* @return the API response (error) code.
*/
public int getStatus() {
return status;
}
}
Aside: The response status is a "code" (number) returned to the client that signals the success/failure of their request. Here are the common status codes and their meaning:
Status | Meaning |
---|---|
200 (OK) | This is the standard response for successful HTTP requests. |
201 (CREATED) | This is the standard response for an HTTP request that resulted in an item being successfully created. |
204 (NO CONTENT) | This is the standard response for successful HTTP requests, where nothing is being returned in the response body. |
400 (BAD REQUEST) | The request cannot be processed because of bad request syntax, excessive size, or another client error. |
403 (FORBIDDEN) | The client does not have permission to access this resource. |
404 (NOT FOUND) | The resource could not be found at this time. It is possible it was deleted, or does not exist yet. |
500 (INTERNAL SERVER ERROR) | The generic answer for an unexpected failure if there is no more specific information available. |
Run the ApiServer
. Then, open Postman and make a GET request to http://localhost:4567/api/courses. This must return the list of courses stored in the database.