Build a Mobile App with React Native and Spring Boot
“I love writing authentication and authorization code.” ~ No Java Developer Ever. Tired of building the same login screens over and over? Try the Okta API for hosted authentication, authorization, and multi-factor auth.
React Native is a framework for building mobile applications with React. React allows you to use a declarative style of programming to describe how your UI should look. It uses embedded HTML (called JSX) to render buttons, lists, scrollable views, and many other components.
I’m a seasoned Java and JavaScript developer that loves Spring and TypeScript. Some might call me a Java hipster because I like JavaScript. In this post, I’m going to show you how to build a Spring Boot API that talks to a PostgreSQL database. You’ll use Elasticsearch to make your data searchable. You’ll also learn how to deploy it to Cloud Foundry, and Google Cloud Platform using Kubernetes.
The really cool part is you’ll see how to build a mobile app with React Native. React Native allows you to build mobile apps with the web technologies you know and love: React and JavaScript! I’ll show you how to test it on device emulators and deploy it to your phone. Giddyup!
Create a Spring Boot App
In my recent developer life, I built an app to help me track and monitor my health. I came up with the idea while writing the JHipster Mini-Book. I was inspired by Spring Boot’s Actuator, which helps you monitor the health of your Spring Boot app. The app is called 21-Points Health and you can find its source code on GitHub.
21-Points Health uses a 21-point system to see how healthy you are being each week. Its rules are simple: you can earn up to three points per day for the following reasons:
- If you eat healthy, you get a point. Otherwise, zero.
- If you exercise, you get a point.
- If you don’t drink alcohol, you get a point.
I’m going to cheat a bit in this tutorial. Rather than writing every component line-by-line, I’m going to generate the API and the app using JHipster and Ignite JHipster.
What is JHipster?
I’m glad you asked! It’s an Apache-licensed open source project that allows you to generate Spring Boot APIs, as well as Angular or React UIs. It includes support for generating CRUD screens and adding all the necessary plumbing. It even generates microservice architectures!
Ignite JHipster is a complementary feature of JHipster. It’s a blueprint template for the Ignite CLI project. Ignite CLI is open source and MIT licensed, produced by the good folks at Infinite Red. Ignite CLI allows you to generate React Native apps in seconds with a number of components pre-integrated. I was blown away the first time I saw a demo of it from Gant Laborde.
To get things moving quickly, I ran jhipster export-jdl
to export an entity definition from 21-Points Health. After exporting the entity definitions, I used JDL-Studio to create an application definition for my project. Then I clicked the download icon to save the file to my hard drive.
The code you see below is called JDL, or JHipster Domain Language. It was initially designed for JHipster to allow multiple entities and specifying all their attributes, relationships, and pagination features. It’s recently been enhanced to allow generating whole apps from a single file! 💥
application { config { applicationType monolith, baseName HealthPoints packageName com.okta.developer, authenticationType oauth2, prodDatabaseType postgresql, buildTool gradle, searchEngine elasticsearch, testFrameworks [protractor], clientFramework react, useSass true, enableTranslation true, nativeLanguage en, languages [en, es] } entities Points, BloodPressure, Weight, Preferences } // JDL definition for application 'TwentyOnePoints' generated with command 'jhipster export-jdl' entity BloodPressure { timestamp ZonedDateTime required, systolic Integer required, diastolic Integer required } entity Weight { timestamp ZonedDateTime required, weight Double required } entity Points { date LocalDate required, exercise Integer, meals Integer, alcohol Integer, notes String maxlength(140) } entity Preferences { weeklyGoal Integer required min(10) max(21), weightUnits Units required } enum Units { KG, LB } relationship OneToOne { Preferences{user(login)} to User } relationship ManyToOne { BloodPressure{user(login)} to User, Weight{user(login)} to User, Points{user(login)} to User } paginate BloodPressure, Weight with infinite-scroll paginate Points with pagination
Create a new directory, with a jhipster-api
directory inside it.
mkdir -p react-native-spring-boot/jhipster-api
Copy the JDL above into an app.jh
file inside the react-native-spring-boot
directory. Install JHipster using npm.
npm i -g generator-jhipster@5.4.2
Navigate to the jhipster-api
directory in a terminal window. Run the command below to generate an app with a plethora of useful features out-of-the-box.
jhipster import-jdl ../app.jh
Run Your Spring Boot App
This app has a number of technologies and features specified as part of its application configuration, including OIDC auth, PostgreSQL, Gradle, Elasticsearch, Protractor tests, React, and Sass. Not only that, it even has test coverage for most of its code!
To make sure your app is functional, start a few Docker containers for Elasticsearch, Keycloak, PostgreSQL, and Sonar. The commands below should be run from the jhipster-api
directory.
docker-compose -f src/main/docker/elasticsearch.yml up -d docker-compose -f src/main/docker/keycloak.yml up -d docker-compose -f src/main/docker/postgresql.yml up -d docker-compose -f src/main/docker/sonar.yml up -d
The containers might take a bit to download, so you might want to grab a coffee, or a glass of water.
While you’re waiting, you can also commit your project to Git. If you have Git installed, JHipster will run git init
in your jhipster-api
directory. Since you’re putting your Spring Boot app and React Native app in the same repository, remove .git
from jhipster-api
and initialize Git in the parent directory.
rm -rf jhipster-api/.git git init git add . git commit -m "Generate Spring Boot API"
Ensure Test Coverage with Sonar
JHipster generates apps with high code quality. Code quality is analyzed using SonarCloud, which is automatically configured by JHipster. The “code quality” metric is determined by the percentage of code that is covered by tests.
Once all the Docker containers have finished starting, run the following command to prove code quality is 👍 (from the jhipster-api
directory).
./gradlew -Pprod clean test sonarqube
If you don’t commit your project to Git, the sonarqube task might fail. |
Once this process completes, an analysis of your project will be available on the Sonar dashboard at http://127.0.0.1:9001
. Check it – you have a triple-A-rated app! Not bad, eh?
Create a React Native App for Your Spring Boot API
You can build a React Native app for your Spring Boot API using Ignite JHipster, created by Jon Ruddell. Jon is one of the most prolific JHipster contributors. ❤️
Install Ignite CLI:
npm i -g ignite-cli@2.1.2 ignite-jhipster@1.12.1
Make sure you’re in the react-native-spring-boot
directory, then generate a React Native app.
ignite new HealthPoints -b ignite-jhipster
When prompted for the path to your JHipster project, enter jhipster-api
.
When the project is finished generating, rename HealthPoints
to react-native-app
, then committed it to Git.
mv HealthPoints react-native-app rm -rf react-native-app/.git git add . git commit -m "Add React Native app"
You might notice that two new files were added to your API project.
create mode 100644 jhipster-api/src/main/java/com/okta/developer/config/ResourceServerConfiguration.java create mode 100644 jhipster-api/src/main/java/com/okta/developer/web/rest/AuthInfoResource.java
These classes configure a resource server for your project (so you can pass in an Authorization
header with an access token) and expose the OIDC issuer and client ID via a REST endpoint.
Modify React Native App for OAuth 2.0 / OIDC Login
You will need to make some changes to your React Native app so OIDC login works. I’ve summarized them below.
Update Files for iOS
If you’d like to run your app on iOS, you’ll need to modify react-native-app/ios/HealthPoints/AppDelegate.m
to add an openURL()
method and an import at the top.
#import <React/RCTLinkingManager.h>
Then add the method before the @end
at the bottom of the file.
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { return [RCTLinkingManager application:application openURL:url options:options]; }
You’ll also need to configure your iOS URL scheme. Run open ios/HealthPoints.xcodeproj
to open the project in Xcode. Navigate to Project > Info > URL Types and specify healthpoints
like in the screenshot below.
You can also modify ios/HealthPoints/Info.plist
if you’d rather not use Xcode.
<key>CFBundleSignature</key> <string>????</string> + <key>CFBundleURLTypes</key> + <array> + <dict> + <key>CFBundleTypeRole</key> + <string>Editor</string> + <key>CFBundleURLName</key> + <string>healthpoints</string> + <key>CFBundleURLSchemes</key> + <array> + <string>healthpoints</string> + </array> + </dict> + </array> <key>CFBundleVersion</key>
Update Files for Android
To make the Android side of things aware of your URL scheme, add it to android/app/src/main/AndroidManifest.xml
. The following XML should go just after the existing <intent-filter>
.
<intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <data android:scheme="healthpoints" /> </intent-filter>
You’ll also need to add an android:launchMode
attribute to the main <application>
element. This is needed for Android to receive the deep link response in the existing MainActivity
instead of a new one.
<application android:name=".MainApplication" android:launchMode="singleTask"
Update Keycloak’s Redirect URI
You will also need to update Keycloak to know your app’s URL scheme because it’s used as a redirect URI. Open http://localhost:9080/auth/admin
in your browser and log in with admin/admin. Navigate to Clients > web_app and add healthpoints://authorize
as a valid redirect URI.
Run Your React Native App on iOS
To run your React Native app, you’ll need to start your Spring Boot app first. Navigate to the jhipster-api
directory and run ./gradlew
. In another terminal window, navigate to react-native-app
and run react-native run-ios
.
If you get an error Print: Entry, ":CFBundleIdentifier", Does Not Exist , run rm -rf ~/.rncache and try again. |
Verify you can log in by clicking the hamburger menu in the top left corner, then Login. Use “admin” for the username and password.
To enable live-reloading of your code in iOS Simulator, first click on the emulator, then press ⌘+R. |
Run Your React Native App on Android
To run your app on an Android emulator, run react-native run-android
. If you don’t have a phone plugged in or an Android Virtual Device (AVD) running, you’ll see an error:
Could not install the app on the device, read the error above for details.
To fix this, open Android Studio, choose open existing project, and select the android
directory in your project. If you’re prompted to “Install Build Tools and sync project,” do it.
To create a new AVD, navigate to Tools > Android > AVD Manager. Create a new Virtual Device and click Play. I chose a Pixel 2 as you can see from my settings below.
To make Keycloak and your API work with Android in an emulator, you’ll have to change all localhost links to your computer’s IP address (e.g., 192.168.0.2
).
This means you’ll need to update src/main/resources/config/application.yml
in the JHipster app to the following.
security: oauth2: client: access-token-uri: http://{yourIPAddress}:9080/auth/realms/jhipster/protocol/openid-connect/token user-authorization-uri: http://{yourIPAddress}:9080/auth/realms/jhipster/protocol/openid-connect/auth client-id: web_app client-secret: web_app scope: openid profile email resource: user-info-uri: http://{yourIPAddress}:9080/auth/realms/jhipster/protocol/openid-connect/userinfo
You’ll also need to update apiUrl
in your React Native app’s App/Config/AppConfig.js
.
export default { apiUrl: 'http://{yourIPAddress}:8080/', appUrlScheme: 'healthpoints' }
Run react-native run-android
again. You should be able to log in just like you did on iOS.
To enable live-reloading of code on Android, first click on the emulator, then press Ctrl+M (⌘+M on MacOS) or shake the Android device which has the running app. Then select the Enable Live Reload option from the popup. |
For the rest of this tutorial, I’m going to show all the examples on iOS, but you should be able to use Android if you prefer.
Generate CRUD Pages in React Native App
To generate pages for managing entities in your Spring Boot API, run the following command in the react-native-app
directory.
ignite generate import-jdl ../app.jh
Run react-native run-ios
, log in, and click the Entities menu item. You should see a screen like the one below.
Click on Points and you should be able to add points.
Tweak React Native Points Edit Screen to use Toggles
The goal of my 21-Points Health app is to count the total number of health points you get in a week, with the max being 21. For this reason, I think it’s a good idea to change the integer inputs on exercise, meals, and alcohol to be toggles instead of raw integers. If the user toggles it on, the app should store the value as “1”. If they toggle it off, it should record “0”.
To make this change to the React Native app, open App/Containers/PointEntityEditScreen.js
in your favorite editor. Change the formModel
to use t.Boolean
for exercise, meals, and alcohol.
formModel: t.struct({ id: t.maybe(t.Number), date: t.Date, exercise: t.maybe(t.Boolean), meals: t.maybe(t.Boolean), alcohol: t.maybe(t.Boolean), notes: t.maybe(t.String), userId: this.getUsers() }),
Then change the entityToFormValue()
and formValueToEntity()
methods to save 1 or 0, depending on the user’s selection.
entityToFormValue = (value) => { if (!value) { return {} } return { id: value.id || null, date: value.date || null, exercise: value.exercise === 1 ? true : false, meals: value.meals === 1 ? true : false, alcohol: value.alcohol === 1 ? true : false, notes: value.notes || null, userId: (value.user && value.user.id) ? value.user.id : null } } formValueToEntity = (value) => { return { id: value.id || null, date: value.date || null, exercise: (value.exercise) ? 1 : 0, meals: (value.meals) ? 1 : 0, alcohol: (value.alcohol) ? 1 : 0, notes: value.notes || null, user: value.userId ? { id: value.userId } : null } }
While you’re at it, you can change the default Points
entity to have today’s date and true
for every point by default. You can make this happen by modifying componentWillMount()
and changing the formValue
.
componentWillMount () { if (this.props.entityId) { this.props.getPoint(this.props.entityId) } else { this.setState({formValue: {date: new Date(), exercise: true, meals: true, alcohol: true}}) } this.props.getAllUsers() }
Refresh your app in Simulator using ⌘+M. When you create new points, you should see your new defaults.
Tweak React App’s Points to use Checkboxes
Since your JHipster app has a React UI as well, it makes sense to change the points input/edit screen to use a similar mechanism: checkboxes. Open jhipster-api/src/main/webapp/…/points-update.tsx
and replace the TSX (the T is for TypeScript) for the three fields with the following. You might notice the trueValue
and falseValue
attributes handle converting checked to true and vise versa.
jhipster-api/src/main/webapp/app/entities/points/points-update.tsx
<AvGroup check> <AvInput id="points-exercise" type="checkbox" className="form-control" name="exercise" trueValue={1} falseValue={0} /> // (1) <Label check id="exerciseLabel" for="exercise"> <Translate contentKey="healthPointsApp.points.exercise">Exercise</Translate> </Label> </AvGroup> <AvGroup check> <AvInput id="points-meals" type="checkbox" className="form-control" name="meals" trueValue={1} falseValue={0} /> <Label check id="mealsLabel" for="meals"> <Translate contentKey="healthPointsApp.points.meals">Meals</Translate> </Label> </AvGroup> <AvGroup check> <AvInput id="points-alcohol" type="checkbox" className="form-control" name="alcohol" trueValue={1} falseValue={0} /> <Label check id="alcoholLabel" for="alcohol"> <Translate contentKey="healthPointsApp.points.alcohol">Alcohol</Translate> </Label> </AvGroup>
In the jhipster-api
directory, run npm start
(or yarn start
) and verify your changes exist. The screenshot below shows what it looks like when editing a record entered by the React Native app.
Use Okta’s API for Identity
Switching from Keycload to Okta for identity in a JHipster app is suuuper easy thanks to Spring Boot and Spring Security. First, you’ll need an Okta developer account. If you don’t have one already, you can signup at developer.okta.com/signup. Okta is an OIDC provider like Keycloak, but it’s always on, so you don’t have to manage it.
Log in to your Okta Developer account and navigate to Applications > Add Application. Click Web and click Next. Give the app a name you’ll remember, and specify http://localhost:8080/login
and healthpoints://authorize
as Login redirect URIs. Click Done, then edit it again to select “Implicit (Hybrid)” + allow ID and access tokens. Note the client ID and secret, you’ll need to copy/paste them into a file in a minute.
Create a ROLE_ADMIN
and ROLE_USER
group (Users > Groups > Add Group) and add users to them. I recommend adding the account you signed up with to ROLE_ADMIN
and creating a new user (Users > Add Person) to add to ROLE_USER
.
Navigate to API > Authorization Servers and click the one named default to edit it. Click the Claims tab and Add Claim. Name it “roles”, and include it in the ID Token. Set the value type to “Groups” and set the filter to be a Regex of .*
. Click Create to complete the process.
Create a file on your hard drive called ~/.okta.env
and specify the settings for your app in it.
#!/bin/bash export SECURITY_OAUTH2_CLIENT_ACCESS_TOKEN_URI="https://{yourOktaDomain}/oauth2/default/v1/token" export SECURITY_OAUTH2_CLIENT_USER_AUTHORIZATION_URI="https://{yourOktaDomain}/oauth2/default/v1/authorize" export SECURITY_OAUTH2_RESOURCE_USER_INFO_URI="https://{yourOktaDomain}/oauth2/default/v1/userinfo" export SECURITY_OAUTH2_CLIENT_CLIENT_ID="{yourClientId}" export SECURITY_OAUTH2_CLIENT_CLIENT_SECRET="{yourClientSecret}"
Make sure your *URI variables do not have -admin in them. This is a common mistake. |
In the terminal where your Spring Boot app is running, kill the process, run source ~/.okta.env
and run ./gradlew
again. You should be able to log in at http://localhost:8080
in your browser, and in your React Native app (after you refresh or restart it).
Debugging React Native Apps
If you have issues, or just want to see what API calls are being made, you can use Reactotron. Reactotron is a desktop app for inspecting your React and React Native applications. It should work with iOS without any changes. For Android, you’ll need to run adb reverse tcp:9090 tcp:9090
after your AVD is running.
Once it’s running, you can see API calls being made, as well as log messages.
If you’d like to log your own messages to Reactotron, you can use <console.tron.log('debug message')
.
Packaging Your React Native App for Production
The last thing I’d like to show you to deploy your app to production. Since there are many steps to getting your React Native app onto a physical device, I’ll defer to React Native’s Running on Device documentation. It should be as simple as plugging in your device via USB, configuring code signing, and building/running your app. You’ll also need to configure the URL of where your API is located.
You know what’s awesome about Spring Boot? There’s a bunch of cloud providers that support it! If a platform supports Spring Boot, you should be able to run a JHipster app on it!
Follow the instructions below to deploy your API to Pivotal’s Cloud Foundry and Google Cloud Platform using Kubernetes. Both Cloud Foundry and Kubernetes have multiple providers, so these instructions should work even if you’re not using Pivotal or Google.
Deploy Your Spring Boot API to Cloud Foundry
JHipster has a Cloud Foundry sub-generator that makes it simple to deploy to Cloud Foundry. It only requires you run one command. However, you have Elasticsearch configured in your API and the sub-generator doesn’t support automatically provisioning an Elasticsearch instance for you. To workaround this limitation, modify jhipster-api/src/main/resources/config/application-prod.yml
and find the following configuration for Spring Data Jest:
data: jest: uri: http://localhost:9200
Replace it with the following, which will cause Elasticsearch to run in embedded mode.
data: elasticsearch: properties: path: home: /tmp/elasticsearch
You’ll also need to remove a couple of properties, due to an issue I discovered in JHipster.
@@ -30,15 +30,12 @@ spring: url: jdbc:postgresql://localhost:5432/HealthPoints username: HealthPoints password: - hikari: - auto-commit: false jpa: database-platform: io.github.jhipster.domain.util.FixedPostgreSQL82Dialect database: POSTGRESQL show-sql: false properties: hibernate.id.new_generator_mappings: true - hibernate.connection.provider_disables_autocommit: true hibernate.cache.use_second_level_cache: true hibernate.cache.use_query_cache: false hibernate.generate_statistics: false
To deploy everything on Cloud Foundry with Pivotal Web Services, you’ll need to create an account, download/install the Cloud Foundry CLI, and sign-in (using cf login -a api.run.pivotal.io
).
You may receive a warning after logging in No space targeted, use 'cf target -s SPACE' . If you do, log in to https://run.pivotal.io in your browser, create a space, then run the command as recommended. |
Then run jhipster cloudfoundry
in the jhipster-api
directory. You can see the values I chose when prompted below.
CloudFoundry configuration is starting ? Name to deploy as? HealthPoints ? Which profile would you like to use? prod ? What is the name of your database service? elephantsql ? What is the name of your database plan? turtle
When prompted to overwrite build.gradle
, type a
.
The first time I ran jhipster cloudfoundry , it didn’t work. Running it a second time succeeded. |
source ~/.okta.env export CF_APP_NAME=healthpoints cf set-env $CF_APP_NAME FORCE_HTTPS true cf set-env $CF_APP_NAME SECURITY_OAUTH2_CLIENT_ACCESS_TOKEN_URI "$SECURITY_OAUTH2_CLIENT_ACCESS_TOKEN_URI" cf set-env $CF_APP_NAME SECURITY_OAUTH2_CLIENT_USER_AUTHORIZATION_URI "$SECURITY_OAUTH2_CLIENT_USER_AUTHORIZATION_URI" cf set-env $CF_APP_NAME SECURITY_OAUTH2_RESOURCE_USER_INFO_URI "$SECURITY_OAUTH2_RESOURCE_USER_INFO_URI" cf set-env $CF_APP_NAME SECURITY_OAUTH2_CLIENT_CLIENT_ID "$SECURITY_OAUTH2_CLIENT_CLIENT_ID" cf set-env $CF_APP_NAME SECURITY_OAUTH2_CLIENT_CLIENT_SECRET "$SECURITY_OAUTH2_CLIENT_CLIENT_SECRET" cf restage healthpoints
After overriding the default OIDC settings for Spring Security, you’ll need to add https://healthpoints.cfapps.io/login
as a redirect URI in your Okta OIDC application.
Then… you’ll be able to authenticate. Voila! 😃
Modify your React Native application’s apiUrl
(in App/Config/AppConfig.js
) to be https://healthpoints.cfapps.io/
and deploy it to your phone. Hint: use the “running on device” docs I mentioned earlier.
export default { apiUrl: 'https://healthpoints.cfapps.io/', appUrlScheme: 'healthpoints' }
I used Xcode on my Mac (open react-native-app/ios/HealthPoints.xcodeproj
) and deployed it to an iPhone X.
When I encountered build issues in Xcode, I ran rm -rf ~/.rncache and it fixed them. I also used a bit of rm -rf node_modules && yarn . |
Below are screenshots that show it worked!
Deploy Your Spring Boot API to Google Cloud Platform using Kubernetes
JHipster also supports deploying your app to the 🔥 hottest thing in production: Kubernetes!
To try it out, create a k8s
directory alongside your jhipster-api
directory. Then run jhipster kubernetes
in it. When prompted, specify the following answers:
- Type of application: Monolithic application
- Root directory: ../
- Which applications: jhipster-api
- Setup monitoring: No
- Kubernetes namespace: default
- Docker repository name: <your Docker Hub username>
- Docker command:
docker push
- Kubernetes service type: LoadBalancer
A number of commands will be printed out that you need to run. Run the following in the jhipster-api
directory.
docker login export USERNAME=<your username> ./gradlew bootWar -Pprod jibDockerBuild docker image tag healthpoints $USERNAME/healthpoints docker push $USERNAME/healthpoints
Google Cloud Platform (a.k.a., GCP) is a PaaS (Platform As A Service) that is built on Google’s core infrastructure. It’s naturally a good provider for Kubernetes in the cloud. Complete the steps below to deploy your JHipster API to Google Cloud.
- Create a Google Cloud project at console.cloud.google.com.
- Navigate to https://console.cloud.google.com/kubernetes/list to initialize the Kubernetes Engine for your project. If your project is not auto-selected, select it (in the nav bar) to start GKE initialization in GCP.
- Install Google Cloud SDK, log in, and set the project using:
gcloud auth login gcloud config set project <project-name>
- Create a cluster:
gcloud components install kubectl gcloud container clusters create <cluster-name> --machine-type n1-standard-2 --scopes cloud-platform --zone us-west1-a
To see a list of possible zones, run
gcloud compute zones list
. - Set the environment variables for your Spring Boot application to use Okta for Identity. You can do this by modifying
k8s/healthpoints/healthpoints-deployment.yml
, adding to theenv
list, and specifying yourSECURITY_OAUTH2_*
values for your Okta OIDC app. In other words, add the name/value pairs just afterJAVA_OPTS
.containers: - name: healthpoints-app image: mraible/healthpoints env: - name: SPRING_PROFILES_ACTIVE value: prod - name: SPRING_DATASOURCE_URL value: jdbc:postgresql://healthpoints-postgresql.default.svc.cluster.local:5432/HealthPoints - name: SPRING_DATA_JEST_URI value: http://healthpoints-elasticsearch.default.svc.cluster.local:9200 - name: JAVA_OPTS value: " -Xmx256m -Xms256m" - name: SECURITY_OAUTH2_CLIENT_ACCESS_TOKEN_URI value: "https://{yourOktaDomain}/oauth2/default/v1/token" - name: SECURITY_OAUTH2_CLIENT_USER_AUTHORIZATION_URI value: "https://{yourOktaDomain}/oauth2/default/v1/authorize" - name: SECURITY_OAUTH2_RESOURCE_USER_INFO_URI value: "https://{yourOktaDomain}/oauth2/default/v1/userinfo" - name: SECURITY_OAUTH2_CLIENT_CLIENT_ID value: "{yourClientId}" - name: SECURITY_OAUTH2_CLIENT_CLIENT_SECRET value: "{yourClientSecret}"
- Run
./kubectl-apply.sh
from thek8s
directory. You should see a bunch of created messages.deployment.apps "healthpoints" created deployment.extensions "healthpoints-elasticsearch" created service "healthpoints-elasticsearch" created deployment.extensions "healthpoints-postgresql" created service "healthpoints-postgresql" created service "healthpoints" created
You can use
kubectl get pods
andkubectl logs -f {podName}
to see the logs.$ kubectl get pods NAME READY STATUS RESTARTS AGE healthpoints-6b56d9d646-h9cn2 1/1 Running 0 3m healthpoints-elasticsearch-84cf759984-vwhv8 1/1 Running 0 18m healthpoints-postgresql-56ddd4bfc9-mptch 1/1 Running 0 18m
- Run
kubectl get svc healthpoints
to get the external IP of your application on Google Cloud. Openhttp://<external-ip>:8080
to view your running application. - Update your Okta application to have the app’s IP address as a Login redirect URI (e.g.,
http://<external-ip>:8080/login
). Then, verify everything works. - Scale your app as needed with
kubectl
:
kubectl scale --replicas=3 deployment/healthpoints
Run
kubectl get pods
to watch your pods startup.NAME READY STATUS RESTARTS AGE healthpoints-6b56d9d646-5lmjk 0/1 Running 0 14s healthpoints-6b56d9d646-h9cn2 1/1 Running 0 7m healthpoints-6b56d9d646-vsm4r 0/1 Running 0 14s healthpoints-elasticsearch-84cf759984-vwhv8 1/1 Running 0 23m healthpoints-postgresql-56ddd4bfc9-mptch 1/1 Running 0 23m
The result? A Spring Boot API running in production on GKE!! Wahoo!
React Native + Spring Boot on GCP
To make your React Native app work with your GCP instance, you just need to modify its AppConfig.js
file to point to its URI, then package and deploy.
export default { apiUrl: 'http://<external-ip>:8080', appUrlScheme: 'healthpoints' }
Secrets: Change the API URL for Different Environments
You might think it’s a pain that you had to change the API URL for the different environments (local development vs. Cloud Foundry vs. Google Cloud). I agree!
Luckily, react-native-config is already built-in to Ignite JHipster. This project allows you to expose config variables to your JavaScript code in React Native. You can store API keys, URLs, and other sensitive information in a .env
file.
API_URL=https://production-is-awesome.cfapps.io
To use react-native-config in your application, use the following steps:
- Copy
.env.example
to.env
and update.gitignore
to ignore it. - Add your config variables.
- Follow instructions at luggit/react-native-config#setup.
- Change your
AppConfig.js
to the following:
import Secrets from 'react-native-config' export default { apiUrl: Secrets.API_URL, appUrlScheme: 'healthpoints' }
Explore React Native, Spring Boot, and JHipster
This tutorial showed you how to build a secure Spring Boot API (powered by JPA, PostgreSQL, and Elasticsearch) with just a few commands. Then you learned how to run your app with Gradle, use Docker to run external services, and verify you had high-quality code with Sonar. And that was just the beginning!
I showed you how to build a React Native app, again with just a few commands. Heck, even deploying to the cloud only took a handful of interesting CLI commands.
The source code for this tutorial is available on GitHub @oktadeveloper/okta-react-native-spring-boot-example.
Don’t you feel hip playing with all these best-of-breed technologies? I sure do! 🤓
Wanna stay hip? Check out some of our other tutorials on React Native, Spring Boot, and JHipster.
- Build a React Native Application and Authenticate with OAuth 2.0 – uses React Native AppAuth, which is a planned integration for Ignite JHipster.
- Develop a Microservices Architecture with OAuth 2.0 and JHipster – includes instructions on how to deploy to Heroku.
- Use React and Spring Boot to Build a Simple CRUD App – CRUD apps can be cool when you’re planning JUG Tours!
- Build a Photo Gallery PWA with React, Spring Boot, and JHipster – build a Flickr clone with JHipster and React. Make it into a PWA.
- Use Ionic for JHipster to Create Mobile Apps with OIDC Authentication – not into React Native? How about Ionic?
Follow us, watch our videos, and connect with us if you’d like to learn more about best-of-breed open source technologies. We’re big fans of open source. 💙
Build a Mobile App with React Native and Spring Boot’ was originally published on the Okta developer blog on October 10, 2018.
“I love writing authentication and authorization code.” ~ No Java Developer Ever. Tired of building the same login screens over and over? Try the Okta API for hosted authentication, authorization, and multi-factor auth.