Skip to content

Commit

Permalink
[WFLY-14563] todo-backend quickstart
Browse files Browse the repository at this point in the history
Add a new quickstart `todo-backend` to showcases a typical use of
WildFly: a backend that exposes a Web API (using JAX-RS) and connects to
a DB (using JPA).

The quickstart focuses on local and cloud deployment with Bootable Jar
and showcase the following features:
* use the wildfly-datasources-galleon-pack to connect to an external
  PostgreSQL database
* Execute a CLI script at build time to specialize the WildFly runtime
  provisioned by the Bootable Jar
* Use of Helm Charts for cloud deployment

JIRA: https://issues.redhat.com/browse/WFLY-14563

Signed-off-by: Jeff Mesnil <jmesnil@redhat.com>
  • Loading branch information
jmesnil committed Mar 18, 2021
1 parent 52fd07d commit 410ab52
Show file tree
Hide file tree
Showing 14 changed files with 1,002 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.adoc
Expand Up @@ -504,6 +504,7 @@ NOTE: Some of these quickstarts use the H2 database included with WildFly. It is
| link:tasks-rs/README{outfilesuffix}[tasks-rs]|JPA, JAX-RS | The `tasks-rs` quickstart demonstrates how to implement a JAX-RS service that uses JPA persistence. | Intermediate | _none_
| link:temperature-converter/README{outfilesuffix}[temperature-converter]|CDI, JSF, SLSB EJB | The `temperature-converter` quickstart does temperature conversion using an EJB Stateless Session Bean (SLSB), CDI, and a JSF front-end client. | Beginner | _none_
| link:thread-racing/README{outfilesuffix}[thread-racing]|Batch, CDI, EE Concurrency, JAX-RS, JMS, JPA, JSON, Web Sockets | A thread racing web application that demonstrates technologies introduced or updated in the latest Jakarta EE specification. | Beginner | _none_
| link:todo-backend/README{outfilesuffix}[todo-backend]|JPA, JAX-RS, OpenShift, Galleon | The `todo-backend` quickstart demonstrates how to deploy a backend on OpenShift that exposes a HTTP API with JAX-RS and persists data in an external database with JPA | Intermediate | _none_
| link:websocket-client/README{outfilesuffix}[websocket-client]|Web Socket, CDI Events, JSON, SSL | Demonstrates use of a Javascript WebSocket client, WebSocket configuration, programmatic binding, and secure WebSocket. | Intermediate | _none_
| link:websocket-endpoint/README{outfilesuffix}[websocket-endpoint]|CDI, WebSocket, JSON-P | Shows how to use WebSockets with JSON to broadcast information to all open WebSocket sessions in {productName}. | Beginner | _none_
| link:websocket-hello/README{outfilesuffix}[websocket-hello]|WebSocket, CDI, JSF | The `websocket-hello` quickstart demonstrates how to create a simple WebSocket application. | Beginner | _none_
Expand Down
4 changes: 4 additions & 0 deletions pom.xml
Expand Up @@ -80,6 +80,9 @@
<version.server.bom>24.0.0.Beta1-SNAPSHOT</version.server.bom>
<version.microprofile.bom>24.0.0.Beta1-SNAPSHOT</version.microprofile.bom>

<version.server.bootable-jar>23.0.0.Final</version.server.bootable-jar>
<version.wildfly-jar.maven.plugin>4.0.0.Final</version.wildfly-jar.maven.plugin>

<!-- Versions of unmanaged dependencies -->
<version.arquillian.angularjs.graphene>1.2.0.Beta1</version.arquillian.angularjs.graphene>
<version.com.nimbusds.jose.jwt>5.4</version.com.nimbusds.jose.jwt>
Expand Down Expand Up @@ -448,6 +451,7 @@
<module>tasks-jsf</module>
<module>tasks-rs</module>
<module>temperature-converter</module>
<module>todo-backend</module>
<module>thread-racing</module>
<module>websocket-client</module>
<module>websocket-endpoint</module>
Expand Down
304 changes: 304 additions & 0 deletions todo-backend/README.adoc
@@ -0,0 +1,304 @@
include::../shared-doc/attributes.adoc[]

= todo-backend: quickstart for backend deployment on OpenShift
:toc: left
:icons: font
:idprefix:
:idseparator: -
:keywords: openshift,galleon,helm
:level: Intermediate
:technologies: JPA, JAX-RS, OpenShift, Galleon

[abstract]
The `todo-backend` quickstart demonstrates how to implement a backend that exposes a HTTP API with JAX-RS
to manage a list of ToDo which are persisted in a database with JPA.

This quickstart shows how to setup a local deployment of this backend as well as a deployment on OpenShift to connect
to a PostgreSQL database also hosted on OpenShift.


== What is it?

The `todo-back` quickstart demonstrates how to implement a backend that exposes a HTTP API with `JAX-RS`
to manage a list of ToDo which are persisted in a database with `JPA`.

* The backend exposes a HTTP API to manage a list of todos that complies with the specs defined at https://todobackend.com/specs/index.html[todobackend.com].
* It requires a connection to a PostgreSQL database to persist the todos.
* It uses the Bootable Jar for local and cloud deployment
* It is deployed on OpenShift using the https://docs.wildfly.org/wildfly-charts/[Helm Chart for ${productName}].

== Architecture

// System Requirements
include::../shared-doc/system-requirements.adoc[leveloffset=+1]

This backend is built and deployed as Bootable Jar that provisions the {productName} application server and all the feature packs it needs for its features.
The layers are defined in the `pom.xml` file in the `<configuration>` section of the `org.wildfly.plugins:wildfly-jar-maven-plugin` plugin:

[source,xml]
----
<layers>
<layer>cloud-server</layer>
<layer>postgresql-datasource</layer>
<layer>ejb</layer>
</layers>
----

The `cloud-server` and `ejb` layers provides everything need to run the backend on OpenShift. This also includes access to
Jakarta EE APIs such as CDI, JAX-RS, JPA, etc. These two layers comes from the {productName} feature pack provided by the Bootable Jar plugin:

[source,xml]
----
<feature-pack>
<location>wildfly@maven(org.jboss.universe:community-universe)#${version.server.bootable-jar}</location>
</feature-pack>
----

The `postgresql-datasource` layer provides a JDBC driver and DataSource to connect to a PostgreSQL database. It is not provided
by the {productName} feature pack but by an extra feature pack:

[source,xml]
----
<feature-pack>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-datasources-galleon-pack</artifactId>
<version>${version.wildfly-datasources-galleon-pack}</version>
</feature-pack>
----

The Git repository for this feature pack is hosted at https://github.com/wildfly-extras/wildfly-datasources-galleon-pack.
It provides JDBC drivers and datasources for different databases but for this quickstart, we will only need the `postgresql-datasource`.

=== Connection to the PostgreSQL database

As mentioned, the JDBC drivers and datasource configuration that the backend uses to connect to the PostgreSQL database
is provided by the `org.wildfly:wildfly-datasources-galleon-pack` feature pack. By default, it exposes a single datasource.
In the backend, the name of this datasource is `ToDos` and is specified in the `persistence.xml` to configure JPA:

[source,xml]
----
<persistence-unit name="primary">
<jta-data-source>java:jboss/datasources/ToDos</jta-data-source>
</persistence-unit>
----

At runtime, we only need a few environment variables to establish the connection from {productName} to the external PostgreSQL database:

* `POSTGRESQL_DATABASE` - the name of the database (that will be called `todos`)
* `POSTGRESQL_SERVICE_HOST` - the host to connect to the database
* `POSTGRESQL_SERVICE_PORT` - The port to connecto to the database
* `POSTGRESQL_USER` & `POSTGRESQL_PASSWORD` - the credentials to connect to the database
* `POSTGRESQL_DATASOURCE` - The name of the datasourcs (as mentioned above, it will be `ToDos`)

=== Filters for Cross-Origin Resource Sharing (CORS)

The Web frontend for this quickstart uses JavaScript calls to query the backend's HTTP API.
We must enable Cross-Origin Resource Sharing (CORS) filters in the `undertow` subsystem of {productName}.

As we use Bootable Jar to build the application, we provide a CLI script that contains all the commands to
create and configure the CORS filters in Undertow. This script is located in the `src/scripts/cors_filters.cli`.

This script is executed at build time and will provide the following HTTP headers to enabled CORS:

* `Access-Control-Allow-Origin: *`
* `Access-Control-Allow-Methods: GET, POST, OPTION, PUT, DELETE, PATCH`
* `Access-Control-Allow-Headers: accept, authorization, content-type, x-requested-with`
* `Access-Control-Allow-Credentials: true`
* `Access-Control-Max-Age: 1`

By default, the backend accepts requests from any origin (`*``). This is only simplicity. It is possible to restrict
the allowed origin using the environment variable `CORS_ORIGIN` at runtime.

== Package the backend as a Bootable Jar

The backend is packaged as a Bootable Jar and configured to be deployable on OpenShift with the Maven Profile `bootable-jar-openshift` which is active
by default:

[source,options="nowrap"]
----
$ mvn clean package
----

== Run the backend locally

=== Local PostgreSQL database

Before running the backend locally, we need to have a local PostgreSQL database that we can connect to.
We use the `postgresql` docker image to create one:

[source,options="nowrap"]
----
$ docker run --name todos-db \
-e POSTGRES_USER=todos \
-e POSTGRES_PASSWORD=mysecretpassword \
-p 5432:5432 \
postgres
----

This will create a database named `todos-db` that we can connect to on `localhost:5432` with the credentials `todos / mysecretpassword`.

=== Run the backend

With the PostgreSQL database running, we can start the backend by passing the required environment variables to connect to the database:

[source,options="nowrap"]
----
$ POSTGRESQL_DATABASE=todos \
POSTGRESQL_SERVICE_HOST=localhost \
POSTGRESQL_SERVICE_PORT=5432 \
POSTGRESQL_USER=todos \
POSTGRESQL_PASSWORD=mysecretpassword \
POSTGRESQL_DATASOURCE=ToDos \
java -jar target/todo-backend-bootable.jar
...
14:41:58,111 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0010: Deployed "todo-backend.war" (runtime-name : "ROOT.war")
...
----

The backend is running, and we can use the HTTP API to manage a list of todos:

[source,options="nowrap"]
----
# get a list of todos
$ curl http://localhost:8080
[]
# create a todo with the title "This is my first todo item!"
$ curl -X POST -H "Content-Type: application/json" -d '{"title": "This is my first todo item!"}' http://localhost:8080/
{"completed":false,"id":1,"order":0,"title":"This is my first todo item!","url":"https://localhost:8080/1"}%
# get a list of todos with the one that was just created
$ curl http://localhost:8080
[{"completed":false,"id":1,"order":0,"title":"This is my first todo item!","url":"https://localhost:8080/1"}
----

== Run the Backend on OpenShift

=== Prerequisites

* You must be logged in OpenShift and have an `oc` client to connect to OpenShift
* https://helm.sh[Helm] must be installed to deploy the backend on OpenShift.

Once you have installed Helm, you need to add the repository that provides Helm Charts for {productName}:

[source,options="nowrap"]
----
$ helm repo add wildfly https://docs.wildfly.org/wildfly-charts/
"wildfly" has been added to your repositories
$ helm search repo wildfly
NAME CHART VERSION APP VERSION DESCRIPTION
wildfly/wildfly 1.1.0 22.0 Build and Deploy WildFly applications on OpenShift
----

=== Deploy a PostgreSQL Database on OpenShift

[source,options="nowrap"]
----
$ oc new-app postgresql-ephemeral \
-p DATABASE_SERVICE_NAME=todos-db \
-p POSTGRESQL_DATABASE=todos
----

This will create a PostgreSQL database named `todos` on OpenShift that can be accessed on the port `5432` on the service `todos-db`.
We don't need to copy the credentials to connect to the database as we will retrieve them later using the `todos-db` secret that was created
when the database is deployed.

=== Build and Deploy the Backend on OpenShift

The backend will be built and deployed on OpenShift with a Helm Chart for {productName}.

[source,options="nowrap"]
----
$ helm install todo-backend -f todo-backend.yaml wildfly/wildfly
NAME: todo-backend
...
STATUS: deployed
REVISION: 1
----

The Helm Chart for this quickstart contains all the information to build an image from the source code using Bootable Jar:

[source,options="nowrap"]
----
build:
uri: https://github.com/wildfly/quickstart.git
mode: bootable-jar
----

The Helm Chart also contains the environment variables required to connect to the PostgreSQL database.
In local deployment the credentials were passed directly as the values of the environment variables.
For OpenShift, we rely on secrets so that the credentials are never copied outside OpenShift:

[source,options="nowrap"]
----
deploy:
env:
- name: POSTGRESQL_PASSWORD
valueFrom:
secretKeyRef:
key: database-password
name: todos-db
----

When the application is deployed, the value for the `POSTGRESQL_PASSWORD` will be taken from the key `database-password`
in the secrets `todos-db`.

Let's wait for the application to be built and deployed:

[source,options="nowrap"]
----
$ oc get dc/todo-backend -w
NAME REVISION DESIRED CURRENT TRIGGERED BY
todo-backend 0 3 0 config,image(todo-backend:latest)
...
todo-backend 1 3 3 config,image(todo-backend:latest)
----

=== Use the todobackend Web application

Once the backend is deployed on OpenShift, it can be accessed from the route `todo-backend`.
Let's find the host that we can use to connect to this backend:

[source,options="nowrap"]
----
$ oc get route todo-backend -o jsonpath="{.spec.host}"
todo-backend-jmesnil1-dev.apps.sandbox.x8i5.p1.openshiftapps.com
----

This value will be different for every installation of the backend.

[WARNING]
====
Make sure to prepend the host with `https://` to be able to connect to the backend from the ToDo Backend Specs or Client
====

We can verify that this application is properly working as a ToDo Backend by running its https://todobackend.com/specs/index.html[specs] on it.


Once all tests passed, we can use the https://todobackend.com/client/index.html[todobackend client] to have a Web application connected to the backend.

=== Clean up

==== Remove the Backend

The backend can be deleted from OpenShift by running the command:

[source,options="nowrap"]
----
$ helm delete todo-backend
release "todo-backend" uninstalled
----

==== Remove the Database

The PostresSQL database can be deleted from OpenShift by running the commands:

[source,options="nowrap"]
----
$ oc delete all -l template=postgresql-ephemeral-template
replicationcontroller "todos-db-1" deleted
service "todos-db" deleted
deploymentconfig.apps.openshift.io "todos-db" deleted
$ oc delete secret todos-db
secret "todos-db" deleted
----

0 comments on commit 410ab52

Please sign in to comment.