Skip to main content

Create and Deploy Spring Boot Todo App to Google Cloud Run

· 5 min read
Huseyin BABAL
Software Developer

Introduction

In the rapidly evolving world of software development, deploying applications in a scalable and efficient manner is critical. With the rise of cloud computing, services like Google Cloud Run have become essential for developers looking to deploy containerized applications quickly and effortlessly. In this blog post, we'll walk through deploying a simple todo app built with Spring Boot and PostgreSQL to Google Cloud Run. We'll cover setting up the project, integrating PostgreSQL, and deploying to the cloud, ensuring your app is ready to handle varying loads efficiently.

Why Connection Pooling is Essential for Serverless?

When deploying applications in a serverless environment like Google Cloud Run, managing database connections efficiently becomes crucial. Traditional connection management can lead to issues such as exhausting database connections, especially under load. This is where PgBouncer, a lightweight connection pooler for PostgreSQL, comes into play. It optimizes the usage of database connections, reducing latency and improving the performance of your serverless app. Additionally, it ensures that the application can handle sudden spikes in traffic without overwhelming the database.

In this article, we will be using PostgreSQL as our database. You can maintain your database in any database management system. For a convenient deployment option, consider cloud-based solutions like Rapidapp, which offers managed PostgreSQL databases, simplifying setup and maintenance.

tip

Create a free database with connection pooling support for the serverless use-cases in Rapidapp in seconds here

Step-by-Step Guide to Creating the Todo App

Project Initialization and Dependencies

We will be using Spring Boot and PostgreSQL to build a todo application. You can initialize a spring boot project by using Spring Boot CLI. Once installed, you can use following command to initialize a project with required dependencies.

spring init \
--dependencies=web,data-jpa,postgresql \
--type=maven-project \
--javaVersion=21 \
cloud-run-todo

Line 2: web for implementing REST endpoints, data-jpa for database persistence, and postgresql for PostgreSQL driver.

Line 3: --type=maven-project for creating a Maven project.

Line 4: --javaVersion=21 we will use Java 21 in Google Cloud Run environment.

Now that we initialized the project, go to the folder cloud-run-todo and open it with your favourite IDE.

Implementing Entity and Repository

We have only one entity here, Todo, which will be used to store our todo items. Let's create a new entity called Todo as follows.

@Entity
class Todo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String description;
private Boolean completed;

public Todo(String description, Boolean completed) {
this.description = description;
this.completed = completed;
}

public Todo() {

}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public Boolean getCompleted() {
return completed;
}

public void setCompleted(Boolean completed) {
this.completed = completed;
}
}

In order to manage Todo entity in database, we will use following repository interface.

interface TodoRepository extends CrudRepository<Todo, Integer>{}

TodoRepository will be used to do crud operations for the Todo entity

Implementing Rest Endpoints

Since we have only one entity, we will have one root endpoint /api/v1/todos inside one controller and implement 2 actions for create and listing todo entities as follows

@RestController
@RequestMapping("/api/v1/todos")
class TodoController {

private final TodoRepository todoRepository;

TodoController(TodoRepository todoRepository) {
this.todoRepository = todoRepository;
}

@PostMapping
void create(@RequestBody CreateTodoRequest request) {
this.todoRepository.save(new Todo(request.getDescription(), false));
}

@GetMapping
Iterable<Todo> list() {
return this.todoRepository.findAll();
}
}

create method accepts a request CreateTodoRequest as shown below.

class CreateTodoRequest {
private String description;

public CreateTodoRequest(String description) {
this.description = description;
}

public CreateTodoRequest() {
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}
}

Now we have persistence layer and rest endpoints ready and we are ready to configure application.

Application Configuration

In serverless environment, it is best practice to expect PORT environment variable since it might be managed by the serverless provider. We can add following configuration to application.properties

application.properties
server.port=${PORT:8080}

By doing this, if there is an env variable PORT, it will take precedence over the default value of 8080. In order to create tables out of entities automatically, we can use following config.

application.properties
spring.jpa.hibernate.ddl-auto=update

As a final step, we need to create a file called project.toml in the root of the project to tell Cloud Run to use Java 21

project.toml
[[build.env]]
name = "GOOGLE_RUNTIME_VERSION"
value = "21"

Deploying to Google Cloud Run

We will be using gcloud cli to deploy our application to Google Cloud Run. Before running deployment command, you need to prepare datasource url, username, and password for PostgreSQL to pass as an environment variable to application. Use following command to deploy.

gcloud run deploy \
--source . \
--update-env-vars SPRING_DATASOURCE_URL=jdbc:postgresql://<host>:<port>/<db>,SPRING_DATASOURCE_USERNAME=<user>,SPRING_DATASOURCE_PASSWORD=<password>

If you are using Rapidapp as your managed database, do not forget to use Pooling Port as port value to use connection pooling for your database to handle highly concurrent requests.

It will prompt for the name of service, you can press enter to accept default one. It will also prompt for the region, select the number of desired region. If there is no problem, it will deploy your application and print the service url.

Demo

Create Todo

curl -XPOST -H "Content-Type: application/json" https://<your>.a.run.app/api/v1/todos -d '{"description": "buy milk"}'

List Todos

curl -XGET https://<your>.a.run.app/api/v1/todos

Conclusion

Deploying a Spring Boot application to Google Cloud Run is straightforward and efficient, allowing developers to leverage the power of serverless computing. By integrating PostgreSQL with connection pooling using PgBouncer and considering services like RapidApp, you can ensure your application is robust and scalable. With this guide, you're now equipped to deploy your todo app to the cloud, ready to handle real-world workloads with ease.

tip

You can find the complete source code for this project on GitHub.