Jersey is a framework we can use for creating HTTP APIs.
HTTP is a protocol used for transferring content, like a web page, over a network. In the case of web pages, content is structured using HTML. In our case, we'll structure data using JSON.
Jersey implements a pattern called REST, which organizes APIs using HTTP and URL conventions. For example, we can use the HTTP verb GET to get feature switch configuration from a URL like http://example.com/feature_switch_config.
Run the Maven archetype command from the Creating a Web Application that can be deployed on Heroku section of Jersey's getting started documentation:
$ mvn archetype:generate -DarchetypeArtifactId=jersey-heroku-webapp \
-DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
-DgroupId=com.example -DartifactId=simple-heroku-webapp -Dpackage=com.example \
-DarchetypeVersion=2.17
Heroku, btw, is a fantastic hosting platform. We'll explore it later in this section.
This will create a directory called "simple-heroku-webapp".
Create a new IntelliJ project by importing simple-heroku-webapp/pom.xml and accepting all the defaults, as we've done before with our other Maven projects.
Open the Main
class (IntelliJ tip: type <ctrl> + N to search by class name) and observe we're setting the port to "8080" by default and the base path to "/":
...
String webPort = System.getenv("PORT");
if (webPort == null || webPort.isEmpty()) {
webPort = "8080";
}
final Server server = new Server(Integer.valueOf(webPort));
final WebAppContext root = new WebAppContext();
root.setContextPath("/");
...
This configures the service to respond to HTTP requests for URLs beginning with http://localhost:8080/
Open the MyResource
class and observe we're defining code to return "Hello, Heroku!" in response to an HTTP GET request for myresource:
...
@Path("myresource")
public class MyResource {
...
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return "Hello, Heroku!";
...
We should be able to call http://localhost:8080/myresource when the server is running and get "Hello, Heroku!" back.
In your terminal, change into the simple-heroku-webapp directory:
$ cd simple-heroku-webapp
Once we start the server, it will "take over" the terminal and we want to work while the server is running, so open a new terminal tab.
Compile and run your server:
$ mvn compile jetty:run
The jetty:run
command starts a web server called Jetty. Jersey works with a number of web servers. This project's pom.xml file specifies Jetty, which is advantageous because Jetty is also used by projects like Google AppEngine and Drop Wizard, so our experience will be portable.
Change to your other tab and make a request to the server using the curl tool:
$ curl http://localhost:8080/myresource
Hello, Heroku!
Congratulations! You've just defined a RESTful API endpoint.
Take a look at the test defined by MyResourceTest
and observe how it asserts the value of the response is "Hello, Heroku!".
Run your tests to verify the generated tests work:
$ mvn test
All right. We've got a working version, so let's commit it. Initialize a new repository:
$ git init
See what's in it:
$ git status
On branch master
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
.idea/
Procfile
pom.xml
simple-heroku-webapp.iml
src/
system.properties
target/
Create a .gitignore file to ignore IntelliJ's .idea directory and iml file, and the target directory, which contains our compiled code:
.idea
*.iml
target
Now add and commit everything:
$ git add .
$ git commit -m "Generate Jersey app"
Rename your service to something more self-descriptive:
$ cd ..
$ mv simple-heroku-webapp feature-switch-service
$ cd feature-switch-service
Edit pom.xml to match your directory name:
...
<groupId>com.example</groupId>
<artifactId>feature-switch-service</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>feature-switch-service</name>
...
Modify the resource path to be more self-descriptive:
...
@Path("feature_switch_config")
...
Use IntelliJ's refactoring tools to rename the request handler and test classes to ConfigResource
and ConfigResourceTest
, respectively. Rename the request handler function from getIt
to get
.
Your diff will look like this:
$ git diff
diff --git a/Procfile b/Procfile
index 3da6f26..8314a3f 100644
--- a/Procfile
+++ b/Procfile
@@ -1 +1 @@
-web: java -cp target/classes:target/dependency/* com.example.heroku.Main
\ No newline at end of file
+web: java -cp target/classes:target/dependency/* com.example.featureswitchservice.Main
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index dca6042..1af7682 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,10 +4,10 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
- <artifactId>simple-heroku-webapp</artifactId>
+ <artifactId>feature-switch-service</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
- <name>simple-heroku-webapp</name>
+ <name>feature-switch-service</name>
<dependencyManagement>
<dependencies>
@@ -61,7 +61,7 @@
</dependencies>
<build>
- <finalName>simple-heroku-webapp</finalName>
+ <finalName>feature-switch-service</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
diff --git a/src/main/java/com/example/featureswitchservice/ConfigResource.java b/src/main/java/com/example/featureswitchservice/ConfigResource.java
index 7d05472..8392f6c 100644
--- a/src/main/java/com/example/featureswitchservice/ConfigResource.java
+++ b/src/main/java/com/example/featureswitchservice/ConfigResource.java
@@ -19,7 +19,7 @@ public class ConfigResource {
*/
@GET
@Produces(MediaType.TEXT_PLAIN)
- public String getIt() {
+ public String get() {
return "Hello, Heroku!";
}
}
diff --git a/src/test/java/com/example/featureswitchservice/ConfigResourceTest.java b/src/test/java/com/example/featureswitchservice/ConfigResourceTest.java
index 51afde3..849230e 100644
--- a/src/test/java/com/example/featureswitchservice/ConfigResourceTest.java
+++ b/src/test/java/com/example/featureswitchservice/ConfigResourceTest.java
@@ -19,8 +19,8 @@ public class ConfigResourceTest extends JerseyTest {
* Test to see that the message "Got it!" is sent in the response.
*/
@Test
- public void testGetIt() {
- final String responseMsg = target().path("myresource").request().get(String.class);
+ public void testGet() {
+ final String responseMsg = target().path("feature_switch_config").request().get(String.class);
assertEquals("Hello, Heroku!", responseMsg);
}
In the terminal, type the <ctrl> + C to stop the server. Recompile and run your server, and functionally test via curl:
$ curl http://localhost:8080/feature_switch_config
Hello, Heroku!
See what's changed:
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: src/main/java/com/example/heroku/MyResource.java -> src/main/java/com/example/featureswitchservice/ConfigResource.java
renamed: src/main/java/com/example/heroku/Main.java -> src/main/java/com/example/featureswitchservice/Main.java
renamed: src/test/java/com/example/heroku/MyResourceTest.java -> src/test/java/com/example/featureswitchservice/ConfigResourceTest.java
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: Procfile
modified: pom.xml
modified: src/main/java/com/example/featureswitchservice/ConfigResource.java
modified: src/test/java/com/example/featureswitchservice/ConfigResourceTest.java
Add your changes (using the --all
flag to include the deleted files):
$ git add --all .
Re-run git status
to verify git has interpreted file deletion and creation as a rename:
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: Procfile
modified: pom.xml
renamed: src/main/java/com/example/heroku/MyResource.java -> src/main/java/com/example/featureswitchservice/ConfigResource.java
renamed: src/main/java/com/example/heroku/Main.java -> src/main/java/com/example/featureswitchservice/Main.java
renamed: src/test/java/com/example/heroku/MyResourceTest.java -> src/test/java/com/example/featureswitchservice/ConfigResourceTest.java
Commit:
$ git commit -m "Reformat project to be more self-descriptive"