Dockerize Spring Boot App with Frontend in React
Frontend for stoic application
Some time ago I created simple Spring Boot app with basic RESTful API and PostgreSQL backend (see this post in which I document my struggle with my first Docker app). Now is the time to create a simple frontend.
- display a list of quotes and a list of thoughts
- allow edition and deletion
I initially decided to start with Preact which somehow seems to be a bit less scary than React.
Set up preact application
I started with a template application as shown in preact.js guide:
Then I started the app in development mode and started to play.
I modified autogenerated Home component a bit. I wanted to display Quotes component (that would - when mounted - display a list of Quote components).
The Quote component’s code is really simple.
Here I assume that I would receive simple properties for display (quote, author) and
delete callback which I call when button is clicked.
The callback is received as a property from parent component (Quotes) that manages all quotes as its state. Here is hoq Quotes is implemented:
In order to fetch data from server and also to send other types of requests (
POST new quotes or
DELETE them), I use fetch API.
In order to be able to access responses from server I needed to use CORS in a very simple way:
- all requests - from all origins - are allowed
- methods allowed are: GET, POST and DELETE
After a while I changed my assumptions a bit:
- only allow connections from localhost
- and only from two ports:
- server application port for pure REST
- and also connections from gui application (also runnig on localhost)
Configuration in Spring Boot
In Spring Boot this is very simple. I just need to configure one
@Bean which uses CorsRegistration instances for specific cors rules.
- I don’t have any separation of cors rules for different parts of my app, therefore the mapping I define is for all paths (
- I want my app to be accessible from the browser, therefore I allow access from
- I also want to access the app from the Preact client application, which I want to run on
- All access is done from localhost, hence the
localhosthost is hardcoded
Note to self: have a look at Spring Cloud Config
React, not Preact
I wanted to experiment a bit with react component libraries and Preact with its compaibility layer was a bit inconvenient. So I used create-react-app.
React App issues
I had a lot of unknowns with my little app:
- in Dockerfile, how to pass environment variables to the application? I need to pass
server.port(for RESTful API) and
gui.port(to allow the client in COSR) …
- what happens if I
npm run buildinstead of
- how to write ENTRYPOINT ?
I just tried to follow this great tutorial which came first when I searched for
But I’ll be honest, I don’t know what I’m doing.
My Dockerfile for React app
And finally my docker-compose:
As you can see, I use two environment variables,
SERVER_PORT and pass them:
appservice so that the app can correctly configure cors for connections from server and from client
guiservice - it actually only needs
SERVER_PORTto know what port to hit when accessing app
During development of a simple gui client I stumbled upon several small “problems”. The solutions to those problems are certainly very well known for full stack devs, but for me they were just little obstacles that made my way to learn more. Here is what I have lerned:
Postresql default sequence allocation size is 1 and Hibernate (or JPA) by default uses value 50. I’ve noticed that an exception is raised when Hibernate tries to create the genrator on its side (see problem and its allocation size differs from the allocation size I defined in database sequence.
The solution and a good practice is this:
- be explicit when declaring allocation size in @SequenceGenerator:
1 2 3 4
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = GENERATOR_NAME) @SequenceGenerator(name = GENERATOR_NAME, sequenceName = SEQUENCE_NAME, allocationSize = 50) private Long id;
- use the same value in sql code and in JPA code; here is what I needed to do:
1 2 3
create sequence hibernate_sequence start 1 increment 1; -- (... and in separate changeset...) alter sequence hibernate_sequence increment by 50;
Who stole my port
I sometimes forgot that I started my app in the background and I’m supprised to see that the port I want to start another one is busy. In order to identify the PID of the java process I can use a very useful tool -
Stopping a spring-boot app
Once the PID is found, I can simply
which is a kind notification that the app should shut down (instead of
kill -9 <PID> which causes the OS to forcibly kill the app)
Of course, a more system-friendly way of sutting down the app, when it was started with
is to use:
This ensures proper closing of all resources, like connections to the database. When spring-boot app is run with
then it stays connected to the terminal and simple
See this article for a description of how to close spring-boot application.
Spring Boot testing
This is a very wide topic. How to structure and how to define tests?
- unit tests don’t depend on spring boot classes
- integration tests do; they either:
- test servlet layer (test annotated
MockMvc) These tests hit the APIs, pass the path parameters using
MockMvcRequestBuildersand verify the status response codes and response content using
- data tests (question: how to properly test? how to setup the database? how to use
- test servlet layer (test annotated
Don’t forget to properly build uris (e.g. when constructing
Reminder on how to test application exceptions in JUnit5:
My current solution can be improved by:
- writing docker-compose.yml such that it also uses environment variables and not hardcoded values for port mapping
- use the outside port in my (p)react client code that connects to that outside-facing service
- define an environment variable which says on which port my (p)react client is accessible as an external service (and perhaps then a port mapping for spring-boot app is not needed at all? - well, it would be nice to have e.g. monitoring entry point)
And it would be nice if I could use a dockerized DNS server so that I can have nice domain names. I wonder if this is doable. Let’s check it out…
Why useEffect is running twice?
This answer: useeffect-is-running-twice-on-mount-in-react explains a bit and moves on right direction, which is: go learn from the official documentation about effects
How to run POST from commandline
http I can run
Why npm build script hits 8080
I’m not sure why it happens but the Reeac app built using
npm build and started by exposing ./build in, let’s say, python3’s http.server , would nicely use environment variable passed to python process (perhaps this is not what happens).
This works: (i.e. hits 5000 when fetching data)
but this don’t:
Well, the reason is I should have build the app in proper environment first and then run it even withour that enviroment (previous values would be baked into the build app). So proper sequence of operations is:
- there may be more than two .env files (for example: for two different sets of variables which we want to apply for development and production) (see this SO answer)
How to correctly build react app image?
Inspiration: Creating your first react app using Docker
To be honest, I don’t “feel” how shoudl I use Docker:
- should I build everything locally and
docker-compose uponly when the build is done or
- should I leave the building to the container
How to dockerize Spring Boot?
I tried to build java app in Docker container in such a way that I copy
.mvnw scripts and then let the maven build the app, however, downloading Spring Boot dependencies took so much time that now I simply build locally the jar and rebuild the image using that changed jar.
The proper way to do this, I guess, is to
- use layered jar as explained in spring.io blog and then
- use multi-stage docker file to extract and copy separate layers
I have learned a lot. I’ve discovered huge areas of things I don’t know. I have practiced React and tried Docker. This is a green field for me, so I was having fun…
Ten wpis jest częścią serii docker.
- 2022-21-09 - Dockerize Spring Boot App with Frontend in React
- 2022-15-09 - Docker Volumes
- 2022-28-04 - Dockerize Spring Boot REST Service with Postgresql on Docker