Web App Development: Java Spring & Postgres REST API

Luke Ostrander
CodeX
Published in
11 min readNov 22, 2021

After talking to people at companies I could potentially intern for, I kept hearing about web development concepts of which I was barely familiar. One of the companies strongly suggested that I learn Java Spring, since it’s what they use for developing their web applications. I thought it would be great to learn, since I wanted to gain more exposure to web development in general as it is a significant subsection of software engineering. I am taking a software development course this fall through Siena College, and have a basic understanding of the Java programming language so far.

Up until now, I have only used VS Code for personal use and BlueJ for my software development course. While I really enjoy VS Code, I found out that when it comes to Java Spring, it’s capabilities were more limited despite having the option for Spring add-ons. After researching, I found out that IntelliJ would be the best to use for this project and is now one of the most in demand Java IDEs. Compared to what I used prior, I found that there were many ways that IntelliJ stood out, such as some of the unique features it offered. I found the efficiency and intelligence of the IDE to be superior, such as being able to generate all of my getters and setters on a whim instead of only having the ability to create them one by one. Along with this, I really liked the labeling feature, which specified what type of attribute I typed based on a constructor I made.

Figure A

Main process of project creation:

The first thing I needed to do was connect to PostgreSQL, which I decided to do through psql (the interactive SQL shell). In IntelliJ, where I am using Java Spring, I set up the configuration needed for connecting to the database. The username and password are left empty for local development, otherwise information needed. Create-drop makes it so there’s a clean state every time the application is run.

Figure B

I had trouble connecting to the database at first with PostgreSQL shell since my password wasn’t showing up or anything as I typed. I learned that passwords will not be echoed when I type for security reasons and that even asterisks (****) won’t be seen. I realized I just needed to try typing it correctly and press return when done and that ended up working.

Figure C has an example showing a successfully typed password, along with the ability to view a list of databases using the “\l” command. Each of the databases shown are stored separately in their own directory within the data directory of the server.

Figure C

Below is an example of what it looks like to create a new database and assign access to the username specified so changes are able to be made to the database. Now when I use the “\l” command, there are additional databases that show up, and the privileges are now updated to show that the user postgres has access to multiple databases. To then use a database, I would connect to it using “\c” followed by the name of the database. Using the “\d” command is equivalent to using DESCRIBE and will only show additional information if the database isn’t null.

Figure D

I experienced an issue when connecting to the database in IntelliJ for Java spring. I kept getting this error below.

Figure E

I realized however that this was a very simple issue. In order to fix this, I needed to update my application.properties file. Since Spring is asking for the data source username and password, which is associated with psql now, I need to provide the username and password in the application.properties file. As a result, the Java Spring console now shows that spring has connected to the database successfully.

Figure F

In order to map the student class to a table in our database, I created this sequence generator. This means that each student’s ID is automatically incremented by one, starting from one for the first student entered into the database.

Figure G

Java Spring console now shows its connection to the database with sequencing for the student class, and creates the student table upon running the application.

Figure H

To connect IntelliJ to our Postgres database, I needed to change the name of the database as well as insert the username and password. Then after that I tested the connection, with this message showing that I successfully have connected.

Figure I

As a result of doing this, I am able to access the table and sequence I created in IntelliJ.

Figure J

Also, in psql I am able to see that when using the “\d” command, my database contains the table and sequence I created prior.

Figure K

I now needed to create a data access layer for the database to be fully functional with Java Spring. To do this, I created a Java Persistence API repository. This contains an API for basic database operations along with sorting and numbering of records. Aside from this, the type of object and its ID need to be specified in the method header. The annotation @Repository is added, which serves as metadata and explains to the user that the repository is used for searching, storing, and retrieving objects.

Figure L

The student service class has now been modified to enable dependency injection, which means that objects are injected into other objects by the Java Spring container. Each object is not dependent upon other objects, and can be replaced over time. The container is used for managing the life cycle of the objects from their creation to their destruction.

Figure M

After this, the @Configuration class is needed. This represents how the Java Spring container assembles the objects in the application. Inside this class, there is a minimum of one bean defined and oftentimes many more that the Spring container manages. Objects that are created by the Spring container are what are called beans, and done so through their dependency injection.

Figure N

Now there’s additional data logging when the server is run on Java Spring due to calling the saveAll method. This represents the SQL that Hibernate, which is used for making Java application development interaction with Postgres more simplified, is running to instantiate objects when the server starts running.

Figure O

Something that I found to be really useful is that I’m able to have a Postgres console inside of IntelliJ. So this means rather than using the psql to run queries, I can do this inside of Java Spring. Along with this, I discovered that the format of the query outputs can be changed to a variety of options. This included being able to export the data in file formats such as CSV, HTML, JSON. For viewing the data itself, I found the table option to be my favorite, especially due to my past experience of using MySQL and MS Access.

Figure P

In order for age to automatically be calculated from the DOB of each record, the annotation @Transient must be used. The reason it is used is to avoid serialization, which means that the age attribute will be calculated from the DOB attribute instead. Otherwise, the age would have to be updated every time someone gets older, and it would be easy to experience data entry errors. In order to have the age be calculated properly, it must be removed from the parameters for creating the object, and the get method must be updated. Doing this will also remove the age column from Figure P (which showed the table output for the query) since the age is no longer serialized.

Figure Q

To be able to generate POST requests, which makes it possible to save new objects to our database, the annotation @PostMapping is used. Inside of the method the annotation @RequestBody is needed to allow mapping of the HTTP request body into a new object. Together, these annotations enable a new object to be created as per the HTTP POST request sent.

Figure R

In Figure S, there is an example of a POST request. When this is run successfully, it is logged to the Java Spring console. In order to determine this, the response code 200 should appear below.

Figure S

Along with this, business logic needs to be created. This represents the handling of the information exchanged between a user interface and a database. In this case, we want to make sure that no two students have the same email, so when new users are added to the database, the same email doesn’t accidentally get assigned to more than one person. To do this, I needed to create an optional, which is a container object. This checks to see if the email is present, and if so, it will return the optional describing the email. After adding that to the student class repository, I then needed to create this logic inside the service class method for adding new students. If the optional contains the specific email that is entered for a new student, there will be a message returned to explain that the email is taken.

Figure T

Now the POST request method has all of the features it needs, and when testing it I can only run this request once before I get a status code of 500, which means that there was an internal server error. I manually had to add to the application properties the line:

server.error.include-message=always

This was done in order for the email taken exception message to be shown, and any other server error exception messages I create in the future will then show up in their respective status code as well.

In order to create the DELETE request method I needed to use the annotation @DeleteMapping with the path set specified to the student ID. To set this up, I created the logic in the student services class as shown below. This checks if the student ID already exists in the database, and if it doesn’t, an exception is thrown.

Figure U

This means that in order to delete a specific object, I would type the student ID I wish to delete after the local web server address. For example, to delete the first ID number I would type

DELETE http://localhost:8080/api/v1/student/1.

As a result, the server would now look like this:

Figure V

The final request method to be created in this Java Spring API is the PUT method. The annotation @PutMapping is used, and just like the DELETE method, a file path is set specified to the student ID. In the update student method inside the student service class, the annotation @Transactional is used. This gives the API the capability to manage transaction boundaries declaratively on objects that are generated. Along with this I also created exception messages to check if the student ID and email exist in the database. The exception for the student ID is the same as for the DELETE method, where it’s looking to see if it doesn’t exist, and the email exception is looking to see if the email that the user wishes to change to has been taken, otherwise they are unable to change their email.

Figure W

The most confusing part about the step I just did was the → operator, since I have never used or even seen this before. I could only find an example of what I needed to do for this step that used this operator. After looking this up, I found out that this is a lambda expression, where the left side of the arrow contains the parameters and the right side contains the expression body. So in my situation, there are actually no parameters, and then the expression body contains the exception that is thrown. I found this page, as well as this one to be very helpful in explaining what the arrow operator is more in depth.

In order to test this, I ran the HTTP request:

PUT http://localhost:8080/api/v1/student/4?email=liverpoolfan11@gmail.com 

This results in the email being updated accordingly on the local web server. The first number specifies the student ID that is being updated, with the contents after the question mark explaining what specific attribute for the object that is being changed.

Figure X

The final thing that I need to do is package up the application into a .jar file for it to run inside of Java Spring. In order to do this, I needed to clean and install the application in IntelliJ as well as use the jar command. Now I am able to deploy the .jar file to a server, and can test different instances of the application through changing the web server port. For example, if I want to test port 8081 I would run:

java -jar demo-0.0.1-SNAPSHOT.jar — server.port=8081

This would result in the local server under that port number to change.

Figure Y

TLDR version: I learned a lot of different things about Java Spring, Postgres, Rest APIs, along with web development and programming in general in the process of building a simple web application for performing HTTP requests. This included GET, POST, PUT, and DELETE methods for managing the contact information of college students.

Most useful sources for this project:

--

--

Luke Ostrander
CodeX
Writer for

Assistant Technical Director - Software Engineering & UX @ DNEG | Enhancing Experiences for Netflix, Apple, and other top clients