Creating a spring boot app with a SPA frontend and end-to-end validation
In this three part tutorial we will be creating a simple JPA Rest Repository based application with spring boot.
In the upcoming parts we will connect a TypeScript frontend to it
and explore how to properly handle validation with Jakarta Bean Validation and zod on the client side.
In addition we will explore some best practices on Entity modeling
(e.g. the significance of equals/hashCode, choosing good primary keys, etc.).
Finally, we obviously are using the latest spring boot version 3.0.1 together with
hibernate 6.1.6.
Creating the server
To create the server go to https://start.spring.io and create a project with the
following dependencies
Lombok
Spring Data JPA
H2 database
Rest Repository
Validation
Spring Boot Actuator
Choosing a good ID
Typically we would be choosing either a Long or a UUID for the primary key of our
entities, however, Longs are problematic as they allow an attacker to easily
guess the ID of other entities, and UUIDs don’t have an inherent sorting order
which makes them a poor choice for B+Tree index structures (see also this article).
Therefore, we will be using Ulid as a primary key (see also this article, or this).
In addition we shamelessly copy the KeyGenerator class from the article.
Creating the data model
Let’s create our entity for the project:
Note that the equals and hashCode methods were created using the
JPA Buddy plugin and are in line with
the recommendations.
Further note that we will let Hibernate create the DB schema automatically, which is
good for a demo, but for production you would use something like
liquibase or flyway.
Finally, we are using a custom IdentifierGenerator to auto-populate the
id for newly created Club entities (see also this article).
In addition to the entity, we obviously need a Repository
Since we are using an in-memory h2 database, we should
ingest some data upon application startup.
So we simply add an ApplicationRunner into our SpringBootValidationApplication
Finally, we will disable open-in-view
in application.properties since this is
generally a good idea.
Creating the REST interface
We will be using spring data rest repositories,
therefore, the implementation is trivial.
All we need to do is add a single annotation to
our ClubRepository:
In addition, we make the repository available under the /api path
which will facilitate our client application integration.
Therefore, simply add the following line to application.properties
Testing the REST interface
Now we should have everything ready to be able
to query our REST interface. We will be using httpie
and get the following result:
This looks already quite good, but we are missing the id which
we would like to use in the client (without having to parse it out
of the self link).
Adding id to the responses
This can be achieved by implementing RepositoryRestConfigurer like so
This basically exposes the id for all JPA entities.
If we try the httpie call from above we should now get
the ids along with the rest of the data
Testing the validation
To check whether our validation annotations work we will
try to insert invalid data into the database via the REST interface.
Since the clubName must be at least 3 characters long
we will try to insert one with 2 characters:
and we get the following response
Well thats not very helpful. In the completed application
we want to annotate the entry form with the validation
errors. Therefore, a blank 500 error won’t do.
Serializing validation errors
In order to be able to control the error responses we need to implement
ResponseEntityExceptionHandler as documented here.
If we now try our POST again
we now get a nicely formatted 400 error:
So with this the server is now fully prepared to serve content for our frontend app.
Continue to part 2 of this tutorial.
Hi, I'm Rainer. I'm a software engineer based in Salzburg.
You can follow me on
Twitter, see
some of my work on
GitHub, or read
more about me on
my website.