Runtime Link

Back-end Java Spring MVC Files

Java Database

A POJO is the foundation for making an Entity that is turned into a Database. The Java Persistent API (JPA) allows Developer to interact with the Database with fairly straightforward code. An API allows you to share and store data from your community of users. The pieces are described in this blog.

Architectural Picture

POJO and @Entity Definition

This code shows power of Spring Annotations and Java, with a little bit of code a Developer is opening up persistent data storage, a database.

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Data  // Annotations to simplify writing code (ie constructors, setters)
@NoArgsConstructor
@AllArgsConstructor
@Entity // Annotation to simplify creating an entity, which is a lightweight persistence domain object. Typically, an entity represents a table in a relational database, and each entity instance corresponds to a row in that table.
public class Jokes {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;  // Unique identifier

    @Column(unique=true)
    private String joke;  // The Joke

    private int haha;  // Store joke likes
    private int boohoo;  // Store joke jeers
}

Java Persistence API (JPA)

The JPA is created to access the database. The JokesJpaRepository interface extends JpaRepository. This allows the developer access predefined and additionally define useful interfaces to access their persistent storage.

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

// JPA is an object-relational mapping (ORM) to persistent data, originally relational databases (SQL). Today JPA implementations has been extended for NoSQL.
public interface JokesJpaRepository extends JpaRepository<Jokes, Long> {
    // JPA has many built in methods, these few have been prototyped for this application
    void save(String Joke);

    // A
    List<Jokes> findAllByOrderByJokeAsc();  // returns a List of Jokes in Ascending order
    List<Jokes> findByJokeIgnoreCase(String joke);  // look to see if Joke(s) exist
}

List and ArrayList

List is a super class to ArrayList. This illustration shows relationship. In the JPA code you can see that List of Jokes is common result from JPA. As a database is a series of rows, accessing a List or and ArrayList is done through similar iteration. Here is illustration of List and ArrayList from GeeksForGeeks

List ArrayList

Controller and APIs

The last backend piece of the process of accessing the database is building out the RESTful API services to access the data. Below is the JokesApiController, this is commented extensively. This has many AP and PBL elements.

  • @Autowired annotation provides full access to JokesJpaRepository, what we made with the code above. Review repository., there are actions for set, get, save and more.
  • @GetMapping and @PutMapping which establishes endpoints for RESTful web services to access the data.
  • API data structuring elements @PathVariable and “return new ResponseEntity” these are keys for obtaining and returning data from the accessor.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController // annotation to simplify the creation of RESTful web services
@RequestMapping("/api/jokes")  // all requests in file begin with this URI
public class JokesApiController {

    // Autowired enables Control to connect URI request and POJO Object to easily for Database CRUD operations
    @Autowired
    private JokesJpaRepository repository;

    /* GET List of Jokes
     * @GetMapping annotation is used for mapping HTTP GET requests onto specific handler methods.
     */
    @GetMapping("/")
    public ResponseEntity<List<Jokes>> getJokes() {
        // ResponseEntity returns List of Jokes provide by JPA findAll()
        return new ResponseEntity<>( repository.findAll(), HttpStatus.OK);
    }

    /* Update Like
     * @PutMapping annotation is used for mapping HTTP PUT requests onto specific handler methods.
     * @PathVariable annotation extracts the templated part {id}, from the URI
     */
    @PutMapping("/like/{id}")
    public ResponseEntity<Jokes> setLike(@PathVariable long id) {
        /* 
        * Optional (below) is a container object which helps determine if a result is present. 
        * If a value is present, isPresent() will return true
        * get() will return the value.
        */
        Optional<Jokes> optional = repository.findById(id);
        if (optional.isPresent()) {  // Good ID
            Jokes joke = optional.get();  // value from findByID
            joke.setHaha(joke.getHaha()+1); // increment value
            repository.save(joke);  // save entity
            return new ResponseEntity<>(joke, HttpStatus.OK);  // OK HTTP response: status code, headers, and body
        }
        // Bad ID
        return new ResponseEntity<>(HttpStatus.BAD_REQUEST);  // Failed HTTP response: status code, headers, and body
    }

    /* Update Jeer
     */
    @PutMapping("/jeer/{id}")
    public ResponseEntity<Jokes> setJeer(@PathVariable long id) {
        Optional<Jokes> optional = repository.findById(id);
        if (optional.isPresent()) {  // Good ID
            Jokes joke = optional.get();
            joke.setBoohoo(joke.getBoohoo()+1);
            repository.save(joke);
            return new ResponseEntity<>(joke, HttpStatus.OK);
        }
        // Bad ID
        return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
    }
}

Front End

This database was setup to allow people to HaHa or Boohoo a collection of Computer Jokes. The entirety has lot of limitation.

  • People can vote more than once and in both categories.
  • There is no auto refresh if several are voting and updating as you are looking at your static page.
  • Perhaps Q and A style could hide punch line.
  • Perhaps we could accept new jokes, or have interface for adding them.

Amazingly, though … the front-end code is in a completely different project. The front end project GETs and PUTs using the back end APIs. The key element that makes this different than other public APIs, like RapidAPI, is the “reaction” function. This function updates the elementID of the like or jeer as soon as you impact the button.

Frontend JavaScript Code

// Reaction function to likes or jeers user actions
  function reaction(type, put_url, elemID) {

    // fetch the API
    fetch(put_url, put_options)
    // response is a RESTful "promise" on any successful fetch
    .then(response => {
      // check for response errors
      if (response.status !== 200) {
          error("PUT API response failure: " + response.status)
          return;  // api failure
      }
      // valid response will have JSON data
      response.json().then(data => {
          console.log(data);
          // Likes or Jeers updated/incremented
          if (type === HAHA) // like data element
            document.getElementById(elemID).innerHTML = data.haha;  // fetched haha data assigned to haha Document Object Model (DOM)
          else if (type === BOOHOO) // jeer data element
            document.getElementById(elemID).innerHTML = data.boohoo;  // fetched boohoo data assigned to boohoo Document Object Model (DOM)
          else
            error("unknown type: " + type);  // should never occur
      })
    })
    // catch fetch errors (ie Nginx ACCESS to server blocked)
    .catch(err => {
      error(err + " " + put_url);
    });
    
  }

Hacks

AP required. Review the lambok annotations (https://projectlombok.org/features/).

  • Write the POJO without using lambok

PBL foundational. Establish a POJO, JPA and APIs in your own project. You can begin with Jokes.

  • Make new POJO attribute. FYI, as there is not database upgrade. I suggest deleting /volumes/sqlite.db to ensure schema is updated.
  • Make a new API endpoint.
  • Test your API using Postman. You should be able to test with localhost:port.
  • Build frontend in different system.

Resources

Googling will find some references.