Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Create and Publish Your Rest API Using Spring Boot and Heroku (Part 2)

DZone 's Guide to

Create and Publish Your Rest API Using Spring Boot and Heroku (Part 2)

In part two of this tutorial, you will learn how to store our bucket lists in the MySQL database and deploy it to Heroku.

· Integration Zone ·
Free Resource

In part one of creating and publishing your Rest API using Spring Boot and Heroku, we built an imaginary bucket list of places we wish to travel to or visit in our lifetime. However, the buckets were not stored in a database. This means that whenever we restart our server our buckets information get lost.

Let’s fix that.

In part two of this tutorial, you will learn how to store our bucket lists in the MySQL database and deploy it to Heroku.

To get the finished code, scroll down to the bottom of this page. If you don’t know what a REST API is or want a refresher on what we have covered so far, please read part 1 of the tutorial here.

Tools used in the tutorial:

  1. IDE: IntelliJ
  2. Framework: Spring Boot
  3. Dependency: Spring boot starter web
  • Web: It provides with tomcat server which handles request and response mapping among other things.
  • MySQL: This provides a connector for connect to MySQL database
  • JPA: This is the ORM, Hibernate to be precise. It provides a wrapper for mapping Java classes to tables in the database.

4. Build Tool: Maven

5. Language: Java

6. Hosting platform: Heroku

7. Database: Mysql

8. Database GUI: Sequel Pro. You can use any tool of your choice.

This tutorial will be divided into two sections. In section 1, we will be using start.spring.io to specify the dependencies we need and generate the boilerplate code. In the next section, we will write the code.

Section 1

  1. Head over to start.spring.io and provide the group and artifact name for your app. It is a Maven project written in Java 8.
  2. The dependencies are MySQL, JPA, and Web.
  3. The group Id is com.zerotoproduction. Yours can be anything.
  4. The artifact id is bucketlist.
  5. Click on generate project
  6. Extract to your computer and import the downloaded maven project to your favorite Editor
  7. Open extracted folder in your editor.selection on start.spring.io

My dependencies:

Maven dependencies

Section 2

We need to create two Java classes. One will serve as a controller for receiving request and responding with response. The second will serve as a data model.

Here is what our Data Model(BucketList) looks like:

package com.zerotoproduction.bucketlist;

import javax.persistence.*;

@Entity
public class BucketList {

    @Id
    @Column(name = "id", unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "name", length = 60, nullable = false)
    private String name;

    @Column
    private  String description;

    BucketList() {

    }

    BucketList(String name, String description){
        this.name = name;
        this.description = description;
    }

    BucketList(long id, String name, String description){
        this.id = id;
        this.name = name;
        this.description = description;
    }

    public long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

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

    @Override
    public String toString() {
        return "BucketList{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", description='" + description + '\'' +
                '}';
    }
}

An explanation for each of the annotations:

1. @Entity: with this annotation, we have specified that this class represents an entity in the DB.

2. @Id: this specifies that this attribute is a primary key

3. @Column(name = “id”, unique = true, nullable = false): @Column specifies that this field should be column, its name should be id, the values should be unique and it cannot be null.

4. @GeneratedValue(strategy = GenerationType.IDENTITY). We are specified that the values should be generated by DB using Identity generation type.

We also need Data Access Object (DAO). Luckily for us, Spring comes with lots of options from CrudRepository to JPARepository. These interfaces provide CRUD functionalities out of the box for Objects annotated with @Entity annotation. However, the caveat is that your DAO interface must extend them and specify the entity and data type of the primary key for that entity. In our example, we are extending JPARepository like so: JpaRepository<BucketList, Long>. The entity is BucketList and data type of its primary key is Long. Now we have all we need to persist our buckets in the DB.

Here is what our BucketListRepository looks like:

package com.zerotoproduction.bucketlist;

import org.springframework.data.jpa.repository.JpaRepository;

public interface BucketRepository extends JpaRepository<BucketList, Long> {
}

Here is what the controller looks like:

package com.zerotoproduction.bucketlist;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;

@RestController
public class BucketListController {

    @Autowired
    BucketRepository bucketRepository;

    @GetMapping(value = "/")
    public ResponseEntity index() {
        return ResponseEntity.ok(bucketRepository.findAll());
    }

    @GetMapping(value = "/bucket")
    public ResponseEntity getBucket(@RequestParam(value="id") Long id) {
        Optional<BucketList> foundBucketList = bucketRepository.findById(id);

        if(foundBucketList.isPresent()){
            return ResponseEntity.ok(foundBucketList.get());
        }else {
            return ResponseEntity.badRequest().body("No bucket with specified id " + id + " found");
        }
    }

    @PostMapping(value = "/")
    public ResponseEntity addToBucketList(@RequestParam(value="name") String name, @RequestParam(value="description") String desc) {
        return ResponseEntity.ok(bucketRepository.save(new BucketList(name, desc)));
    }

    @PutMapping(value = "/")
    public ResponseEntity updateBucketList(@RequestParam(value="name") String name, @RequestParam(value="id") Long id, @RequestParam(value="description") String desc) {
        Optional<BucketList> optionalBucketList = bucketRepository.findById(id);
        if(!optionalBucketList.isPresent()){
            return ResponseEntity.badRequest().body("No bucket with specified id " + id + " found");
        }

        BucketList foundBucketList = optionalBucketList.get();
        foundBucketList.setName(name);
        foundBucketList.setDescription(desc);

        return ResponseEntity.ok(bucketRepository.save(foundBucketList));
    }

    @DeleteMapping(value = "/")
    public ResponseEntity removeBucketList(@RequestParam(value="id") Long id) {
        bucketRepository.deleteById(id);
        return ResponseEntity.noContent().build();
    }
}

Here is what my folder structure looks like:

Since we are connecting to a database, we need the address of the database, username, and password.

We will test this locally on our pc before deploying it to Heroku. I have specified the properties in application.properties. 

spring.datasource.url=jdbc:mysql://localhost:3306/zero_to_production_bucketlist_jpa?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=Toor1234

# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto=update

#MySQL DIALECT
#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

server.port=9009

Let’s go over it

  1. spring.datasource.url specifies the connection string for connecting to the database
  2. spring.datasource.username specifies the username for connecting to the Db
  3. spring.datatsource.password specifies the password.
  4. spring.jpa.hibernate.ddl-auto specifies how hibernate will handle entities in your database. The create option means that all entities will be dropped and created at every restart while the update option adds changes to the entities without dropping it. In production, you need to use update else your data will be flushed.
  5. server.port specifies the port number our application will run on.

It’s time to test and we will do it this time locally. We will use Postman

Test 1: Add a bucket list

http://localhost:9009?name=Visit Big Ben&description=My first list

Add a bucket list
I also added a second bucket list. You can add as many as you want. 

Test 2: Get all bucket lists

http://localhost:9009

Test 3: get single bucket list

http://localhost:9009/bucket?id=1

Test 4: Update Bucket

http://localhost:9009?name=Visit Big Ben Updated&description=My first list&id=1

Test 5: Delete bucket

http://localhost:9009?id=2

Let’s deploy to Heroku

We need to use ClearDB Mysql Addon on Heroku

First, we prepare the Spring Boot for heroku like so:

  • git init to initialise the repository
  • git add . to add all files in folder
  • git commit -m ‘Commit name’: commit changes
  • heroku create: to create heroku app

Next, you need to add mysql DB like so in the terminal:

heroku addons:create cleardb:ignite

Note: heroku command works because we have installed heroku cli. 

Now that you have add clearDB, you need the connection url. To get this, type like so:

heroku config

It should return your connection string.

You need to replace the spring.datasource.url value in application.properites with the value return from heroku config.

One last thing though, to make it work, add a database config file like so:

package com.zerotoproduction.bucketlist;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class DatabaseConfig {

    @Value("${spring.datasource.url}")
    private String dbUrl;

    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(dbUrl);
        return new HikariDataSource(config);
    }
}

It’s time to deploy to heroku

git push heroku master

At the end of this process, you should have your app deployed to Heroku

To test, you remove the localhost and port number then you replace them with app name returned by Heroku.

My app name is: https://tranquil-mountain-81706.herokuapp.com/

For example to get all bucketlists on a deployed app, the url is like this:

https://tranquil-mountain-81706.herokuapp.com/

Just repeat the same process we followed for testing locally however you should remove localhost and port

That marks the end of part 2 of this guide. 

Going forward, I have decided to make this guide into a series where I work you through building an application using microservices architecture. 

Here are my plans going forward:

In part 3, I plan to introduce authentication and roles using Spring Security commencing with jwt.

In part 4, I will work you through the different approaches to creating authorisation and resource servers. 

In part 5, we will consume the rest api using a JS library like VueJS or React JS.

Stay tuned.

Share and leave your comments. I would be happy to help.

The complete code can be found here:

https://github.com/zero-to-production/bucketlist

Happy coding. 

Topics:
java ,spring boot 2 ,rest api ,heroku ,java ee

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}