Running Spring Boot Applications on Choreo
With the introduction of Buildpacks, Choreo now offers the flexibility to host services written in various languages, enabling development teams to leverage the benefits of Choreo while working on polyglot applications. With these recent updates, deploying applications written in Node, Java, Go, or Ruby on Choreo has become effortless.
In this post, I will guide you through the steps to deploy a Spring Boot application on Choreo. Before we begin, please make sure that you have the following prerequisites in place.
Prerequisites
- An active Choreo account. Ensure you have not exceeded your free component limit. Create a new account here if you don’t have one already
- Java 17 or higher.
The Spring Boot Application
For this guide, I’ve chosen a popular Spring Boot example: employee service. This service facilitates the management of employee details. You can access the code for this application here. Feel free to fork it and change it.
Our Spring Boot application provides a simple REST API with the following four operations;
@RestController
@RequestMapping("/api")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@ResponseStatus(HttpStatus.OK)
@GetMapping("/employees")
public List<Employee> getEmployees() {
return employeeService.getEmployees();
}
@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/employees")
public Employee createEmployee(@RequestBody EmployeeRequest employee) {
return employeeService.createEmployee(employee);
}
@ResponseStatus(HttpStatus.OK)
@PutMapping("/employees/{employeeId}")
public Employee updatedEmployee(@RequestBody EmployeeRequest employee, @PathVariable int employeeId) {
return employeeService.updateEmployee(employeeId, employee);
}
@ResponseStatus(HttpStatus.NO_CONTENT)
@DeleteMapping("/employees/{employeeId}")
public void deleteEmployee(@PathVariable int employeeId) {
employeeService.deleteEmployee(employeeId);
}
}
I have enabled an in-memory H2 database with the hope of replacing it with a proper DB later. When you read through the code, you’ll notice that I have used JPA for data persistence.
To test the application locally, clone the repository and run the application using the following commands:
git clone git@github.com:jaadds/employee.git
cd employee
./mvnw spring-boot:run
You should see the application starting up.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.1.4)
2023-10-23T15:46:41.186+05:30 INFO 20491 --- [ main] c.example.employee.EmployeeApplication : Starting EmployeeApplication using Java 19.0.2 with PID 20491
2023-10-23T15:46:41.188+05:30 INFO 20491 --- [ main] c.example.employee.EmployeeApplication : No active profile set, falling back to 1 default profile: "default"
2023-10-23T15:46:41.654+05:30 INFO 20491 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2023-10-23T15:46:41.699+05:30 INFO 20491 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 37 ms. Found 1 JPA repository interfaces.
2023-10-23T15:46:42.166+05:30 INFO 20491 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-10-23T15:46:42.178+05:30 INFO 20491 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
....
Let’s give it a try:
curl http://localhost:8080/api/employees | jq
You should get the following output:
[
{
"id": 1,
"firstName": "Bilbo",
"lastName": "Baggins",
"email": "bilbo@bagend.me"
}
]
Let’s add a second employee and check the results:
curl -H "Content-Type: application/json" -X POST http://localhost:8080/api/employees -d '{"firstName":"Frodo","lastName":"Baggins","email":"frodo@bagend.me"}'
Output:
{"id":2,"firstName":"Frodo","lastName":"Baggins","email":"frodo@bagend.me"}
Now that we know our service is working, let’s continue with deploying it on Choreo.
Preparing the Repository for Deployment
Choreo needs certain details to create an endpoint for your service, such as the service port, context path, and service definition. Additionally, you need to specify the endpoint’s visibility level, choosing between public (accessible over the internet) or internal (available only to services running within Choreo). All these details should be defined in the endpoints.yaml file.
For this tutorial, we will expose our employee service as a public endpoint.
Create a .choreo/endpoints.yaml file in your project and add the following content:
version: 0.1
endpoints:
- name: Employee API
port: 8080
type: REST
networkVisibility: Public
context: /
schemaFilePath: openapi.yaml
This is a short description of the attributes. For a detailed explanation, you can refer to the official documentation.
name : The name Choreo will use to create the endpoint. This name will also be used in the Developer Portal if you decide to publish a Managed API later.
port : The port on which your service is running. Update this value if you have changed the port using the `server.port` property.
type : The type of API/interface you are exposing. Valid values are REST, GraphQL, and gRPC. Since this is a REST service, we use REST.
networkVisibility: The level of visibility for the service over the network. Valid values are Project, Organization, and Public. We'll set this to Public for this tutorial.
context : The context path of your application. If you have changed the context path using the `server.servlet.context-path` property, use that value here. Since we haven't changed it for this tutorial, we'll leave it as /.
schemaFilePath : The schema of the Service. For a REST API, this will be the OpenAPI Specification. For GraphQL and gRPC, you can specify SDL and proto files, respectively. The location is read from the repository root, not from the `./.choreo` folder.
Since we specified a schema file path, we need to generate and place the OpenAPI Specification in the specified location.
Generating the OAS
While it’s possible to manually create the OpenAPI Specification (OAS) for a small API like this, Spring’s rich ecosystem provides tools to do this easily. Add the springdoc-openapi dependency to your pom.xml, and start your application.
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.1.0</version>
</dependency>
Get the OAS in YAML format using the following command:
curl http://localhost:8080/v3/api-docs.yaml > openapi.yaml
Commit these changes to your repository.
Deploying Changes to Choreo
Now that everything is set up, it’s time to deploy our Spring Boot application on Choreo. In case you missed any step, you can cross-check your work with the main branch. In addition to the steps mentioned here, I’ve updated the snakeyaml dependency to avoid security scan failures.
Before deploying our Spring Boot Application on Choreo, we’ll have to create a component on Choreo. As our Application behaves as a service, we’ll be creating a Service type component.
Creating a Service Component
- Select the “Service” Tile.
2. Provide the following details:
Component Name : Employee Service
Description : Service for managing employee details
Organization : Your GitHub account ID
Repository : The repository containing your code
Branch : The branch with the deployable changes (in this case, "main")
Build Preset : Java
Java Project Directory : Leave the default as is
Language Version : Select the Java version from your POM (only LTS versions are available)
3. Click “Create” to finalize the component.
Deploying the Service
- Navigate to the Deploy page.
- In the Build Area section, verify component details and the latest commit.
3. Click “Configure & Deploy”, which will initiate a three-step wizard.
- First screen: Screen for adding environment variables. We’ll skip this for now.
- Second screen: For specifying file mounts. We can skip this too.
- Final step: Verify details from `endpoints.yaml` and click “Deploy.”
4. Clicking Deploy will initiate the build process. Choreo will compile the source code, build a container out of it, do a vulnerability scan and deploy it to the development environment. This will take a minute or two to complete.
5. Wait for the status to change to “Active.”
Viewing Logs
Once you see the Active label on the Development environment, your service should be up and running. If you want to further confirm whether the service got started properly, you can check the logs.
Go to the Observability section to view logs. You’ll see logs similar to those you saw when running locally.
Testing the Service
Let’s test the service. The Test section provides a variety of tools for this purpose. For our case, we will choose the Swagger Console. You may notice that the endpoint you specified in the YAML file appears in the drop-down menu. If you have defined multiple endpoints, they will all be displayed in this drop-down. Additionally, observe that an API Key has been generated. This is because when exposing endpoints for consumption, Choreo automatically secures them, requiring consumers to use a proper token.
You can expand on a resource and click Execute.
This will give the response like this.
Congratulations!! You’ve successfully deployed a Spring Boot application on Choreo.
What’s Next?
Learning and experimenting with the platform will help you to use Choreo better and develop production-grade applications in no time. Here are a few things you can do to familiarize yourself with the platform:
- Add logs to your resources and use the Logs view in Choreo to trace requests end-to-end. This can be invaluable for debugging and understanding the behavior of your application in a real-world scenario.
- Promote your Service to Production and check whether everything runs smoothly. Experience how easily you can propagate changes across environments.
- Publish your service as an API in the Developer Portal. Manage, document, and share your API with other developers or teams.
- Follow the official documentation of Choreo to learn more about concepts like Projects, Components, and Environments.
Stay tuned for the next post, where I will talk about connecting a DB and securely storing configs for you application.
Happy Coding!