Wednesday, December 19, 2018

5. Replacing tomcat with jetty

By default when we run spring boot application, it runs a tomcat server. I have personally found tomcat too heavyweight and I prefer to use Jetty for writing a webservices backend.
2018-12-19 10:54:08.403  INFO 16029 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)

2018-12-19 10:54:08.424  INFO 16029 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]

2018-12-19 10:54:08.424  INFO 16029 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/9.0.12

To replace tomcat with Jetty, we need to make a couple of changes.  The first step is to add Jetty dependencies in the pom.xml.
  
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-jetty</artifactId>
  </dependency>
  <dependency>
   <groupId>org.eclipse.jetty</groupId>
   <artifactId>jetty-deploy</artifactId>
  </dependency>
  <dependency>
   <groupId>org.eclipse.jetty</groupId>
   <artifactId>jetty-rewrite</artifactId>
  </dependency>
  <dependency>
   <groupId>org.eclipse.jetty</groupId>
   <artifactId>jetty-util</artifactId>
  </dependency>

Since springframework boot bom automatically includes a dependency on tomcat in spring-boot-starter-web, we specifically need to exclude it. So we change
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

to
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
   <exclusions>
    <exclusion>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-tomcat</artifactId>
    </exclusion>
   </exclusions>
  </dependency>


The next step is to add a customizer for jetty which will allow us to set some parameters related to Jetty.
As we can see the customizer uses a set of variables that we can override in application.properties file to modify the behavior of the server.

2018-12-19 11:06:44.577  INFO 16219 --- [           main] o.e.jetty.server.AbstractConnector       : Started ServerConnector@42ebece0{HTTP/1.1,[http/1.1]}{0.0.0.0:8081}
2018-12-19 11:06:44.580  INFO 16219 --- [           main] o.s.b.web.embedded.jetty.JettyWebServer  : Jetty started on port(s) 8081 (http/1.1) with context path ''
Now the logs clearly show that in place of tomcat, it is running jetty.

Wednesday, November 28, 2018

4. More on CrudRepository

In the previous post, we used the CrudRepository interface. We only used the methods already provided by the interface. In this post, we look at how we can extend the interface with custom queries. Let's go back to our UserEndpoint. In the GET method, we can currently get the details of a user given his id. This is an impractical scenario. Most users' would not know what their id is. It is an internal identifier generated by our service and it makes no sense for our users.
Let's say we want to extend the existing GET/DELETE interface to allow query by id, username, and email address. Since we intend to query the table using the username and email columns, we need some kind of index on those columns. Since these fields are expected to be unique, we put a unique constraint in the @Table annotation.

When this change is deployed, the corresponding changes in database schema would be as below.
mysql> desc user;
+----------+--------------+------+-----+---------+-------+
| Field    | Type         | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id       | bigint(20)   | NO   | PRI | NULL    |       |
| email    | varchar(255) | YES  | UNI | NULL    |       |
| fullname | varchar(255) | YES  |     | NULL    |       |
| password | varchar(255) | YES  |     | NULL    |       |
| username | varchar(255) | YES  | UNI | NULL    |       |
+----------+--------------+------+-----+---------+-------+
5 rows in set (0.01 sec)
mysql> show create table user\G
*************************** 1. row ***************************
       Table: user
Create Table: CREATE TABLE `user` (
  `id` bigint(20) NOT NULL,
  `email` varchar(255) DEFAULT NULL,
  `fullname` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `username` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_email` (`email`),
  UNIQUE KEY `uq_username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

As we can see from the schema both the columns have unique constraints attached to them. The next step is to add methods in the UserRepository.java to query the user for a given username or email.

Now that we have all the required changes in place, we modify the UserEndpoint to handle the changes. We first create a private method retrieveUser which will retrieve a user from repository given an id, username or email.

In this method, we take an argument of type String, we first assume it to be the id if id fails we try with email and then with the username.
$ curl -X GET http://localhost:8080/user/jdoe@example.com
{"id":6,"fullname":"John Doe","username":"jdoe","password":"JohnDoe123","email":"jdoe@example.com"}
Here is the complete UserEndpoint class after modification.



Tuesday, November 27, 2018

3. All the methods in endpoint

In the previous post, we defined a single method for an endpoint. In a typical web application, each endpoint will have multiple methods. To build an example of a complete endpoint, we need to have a persistence layer that can support these endpoints. To enable MySQL support for spring framework, we need to update pom.xml file with following dependencies.


Now we need to define data sources for MySQL. The first step is to create a database and user in the MySQL database. To do that log in to MySQL using the following command.
$ mysql -u root
Now run following set of commands to create a database named tutorial with username tutorial and password tutorial123.

Now we can initialize a data source in spring framework by putting properties in the application.properties file.

As we can see in the properties, the value ddl-auto is set to update. This will cause the database schema to be updated based on the definition of entity objects. This is a good practice while developing the system but normally should not be used while in production.
Let's say we want to define a simple endpoint that supports an entity called User. We define the entity in Java as below.

As we can see, the key to an entity class is the annotation @Entity.  You can also add an optional annotation @Table which will allow you control over the name of the table that gets created within the database. By default, if you omit the @Table annotation, the table name would be automatically generated.
The next step is to generate a Repository interface for accessing the entity from the database. We typically create a subclass of CrudRepository.

An empty repository interface provides sufficient functionality for this example. We will see how to add more functionality to repository class in a  different post. The Javadoc of CrudRepository provides details of all the methods that are readily available without any addition to the interface.
Let's run the server to see whether the server can connect to the database. As we run the server, we check what happened to our database.
$ mysql -u tutorial -ptutorial123 tutorial
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 8.0.12 Homebrew

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show tables;
+--------------------+
| Tables_in_tutorial |
+--------------------+
| hibernate_sequence |
| user               |
+--------------------+
2 rows in set (0.01 sec)

mysql> desc user;
+----------+--------------+------+-----+---------+-------+
| Field    | Type         | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id       | bigint(20)   | NO   | PRI | NULL    |       |
| email    | varchar(255) | YES  |     | NULL    |       |
| fullname | varchar(255) | YES  |     | NULL    |       |
| password | varchar(255) | YES  |     | NULL    |       |
| username | varchar(255) | YES  |     | NULL    |       |
+----------+--------------+------+-----+---------+-------+
5 rows in set (0.01 sec)

mysql> 

The database has the user table created mapping our entity class to a table. Now we have confirmed that the server is able to connect to our database server. Now we go back to the old endpoint class that we created in the previous post and create a similar endpoint class called UserEndpoint. In this class, we will define all the methods required for managing users.


$ curl -X POST \
>   http://localhost:8080/user \
>   -H 'Content-Type: application/json' \
>   -H 'Postman-Token: d0298724-86d2-49da-a0c0-067ed9e18e1e' \
>   -H 'cache-control: no-cache' \
>   -d '{
> "fullname":"John Doe",
> "username":"jdoe",
> "password":"JohnDoe123",
> "email":"johndoe@example.com"
> }'
{"id":1,"fullname":"John Doe","username":"jdoe","password":"JohnDoe123","email":"johndoe@example.com"}
We can also verify the record in the database.
$ mysql -u tutorial -ptutorial123 tutorial -e "select * from user"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+---------------------+----------+------------+----------+
| id | email               | fullname | password   | username |
+----+---------------------+----------+------------+----------+
|  1 | johndoe@example.com | John Doe | JohnDoe123 | jdoe     |
+----+---------------------+----------+------------+----------+
Now we can perform other operations on User record.
$ curl -X GET http://localhost:8080/user/1
{"id":1,"fullname":"John Doe","username":"jdoe","password":"JohnDoe123","email":"johndoe@example.com"}

curl -X DELETE http://localhost:8080/user/1
{"id":1,"fullname":"John Doe","username":"jdoe","password":"JohnDoe123","email":"johndoe@example.com"}

Now we can run the database query again and see that the record has vanished.
mysql> select * from user;
Empty set (0.00 sec)

Now we create the user again by running the POST command. Since we are using database autoincrement, the id of the user will be 2 now.
Now we change the email of the user using PATCH command.
curl -X PATCH   http://localhost:8080/user/2   -H 'Content-Type: application/json'   -H 'Postman-Token: d0298724-86d2-49da-a0c0-067ed9e18e1e'   -H 'cache-control: no-cache'   -d '{
"email":"jdoe@example.com"
}'
{"id":2,"fullname":"John Doe","username":"jdoe","password":"JohnDoe123","email":"jdoe@example.com"}

Here we have it. All the endpoints are functioning properly backed by MySQL as the database.

Tuesday, November 20, 2018

2. Adding an Endpoint

One of the primary reasons why one would be using spring framework would be to define rest based web services.  In this post, we will see how do we add an endpoint to our server. First, download and install your favorite IDE. I prefer IntelliJ IDEA but you can pick the IDE that you are comfortable with.
Let's open the project that we created in the previous blog post in the IDE. The source root for the project is <Project Name>/src/main/java. Once you open that directory, you will see the package of the project that you created. Within that, you will see the main for the spring application. The only thing that we change for now is to add scanBasePackages parameter in @SpringBootApplication annotation.

For now, we can leave the main as it is. The next step that we want to do is to add an endpoint. Create a new java class in your project. I call it HelloWorldEndpoint. To define an endpoint, we need to do the following things. The endpoint needs to have a path relative to the server root. We also need to know what operations are needed to be defined.
We will discuss the whole details of spring security later. So for now please remove security dependencies from your pom.xml. Following lines should be removed from pom.xml

It helps to look at a REST endpoint as an object with operations used to define their lifestyle state changes.

  • Path defines a class
  • Method GET is for reading the state of that object
  • Method POST is for creating a new object of that class
  • Method DELETE is for deleting an instance of that class
  • Method PUT is for updating the object
  • Method PATCH is for selectively updating the values.
Looking at our example, we are going to create a HelloWorld endpoint which will be used to manage the state of class Hello. Here is what class Hello looks like.

Now we look at our endpoint class. The class contains a single method GET which returns a temporarily created instance of Hello class.

Now we build the project.
$mvn clean package -DskipTests

And we can run the project.
$mvn spring-boot:run

Since maven build creates a single jar for each project. We can also run the project with the java command.
$java -jar target/tutorials-0.0.1-SNAPSHOT.jar

Most IDEs would allow you to build and run the project from within the IDE. You can do that as well. Now that the server is running we can test the endpoint that we had written. You can use tools like Postman but since it is a simple endpoint, we can just test it with curl command.
curl -X GET http://localhost:8080/hello

{"message":"Hello","name":"World"}
As we can see the JSON that is returned corresponds to the temporary object that we created and returned. Of course, this is too simplistic and we will look at doing something more substantial in the next blog post. 

Monday, November 19, 2018

1. Starting a springframework project

The best way to start a spring framework project is to use the spring initializer to do that. Visit Spring Initializer website. Provider values for group and artifact and select the dependencies that you want to initialize with. To start with you can start with minimum dependencies and then add them later on. These are just maven dependencies.

Here I have selected Web and Security to start with. Now we click on Generate Project. It downloads a zip file which is the starting project. We unzip the file and then we run following command.
$ mvn clean package -DskipTests

 It will download the dependencies and then compile the project. The finally built jar file is in the tutorials/target directory and is named tutorials-0.0.1-SNAPSHOT.jar. The name is created using the version number defined in the pom.xml file generated. We can run the project by running following command.
$ java -jar target/tutorials-0.0.1-SNAPSHOT.jar

It will run the project and the following output is displayed. The last line tells us that the project launch is successful.

So here it is. Our first springframework project.