DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Coding
  3. Frameworks
  4. JSON API Using Katharsis and Spring Boot

JSON API Using Katharsis and Spring Boot

This tutorial details how to build a RESTful Hello World API that complies to the JSON API specifications using the Katharsis, OkHttp, Spring Boot, and Maven frameworks.

[deleted] user avatar by
[deleted]
·
Apr. 27, 17 · Tutorial
Like (2)
Save
Tweet
Share
16.63K Views

Join the DZone community and get the full member experience.

Join For Free

JSON API is a specification for building APIs using JSON. It details how clients should request resources to be fetched or modified, and how servers should respond to those requests. JSON API is designed to minimize both the number of requests and the amount of data transmitted between clients and servers.

Katharsis is a Java library that implements the JSON API specification. It is an additional layer that can be plugged on top of existing server-side Java implementations in order to provide easy HATEOAS support. Katharsis defines resources which can be shared over a RESTful interface and a repository for handling them.

The below tutorial details how to configure and build a RESTful Hello World API that complies to the JSON API specification. Frameworks used are Katharsis, OkHttp, Spring Boot and Maven.

Tools used:

  • Katharsis 3.0.
  • OkHttp 3.6.
  • Spring Boot 1.5.
  • Maven 3.5.

General Project Setup

The example will be built and run using Apache Maven. In order to use the Katharsis framework, we need to include the katharsis-core dependency. As Spring Boot will be used for running the server part we also need to include katharsis-spring. For implementing the client part, the katharsis-client dependency is needed.

Katharsis aims to have as few dependencies as possible, and as such an HTTP client library is not included by default. It needs to be provided on the classpath where it will be automatically picked up by the framework. Both OkHttp and Apache Http Client are supported. For this example, we will use the okhttp library.

Running and testing of the example is based on the spring-boot-starter and spring-boot-starter-testSpring Boot starters. The spring-boot-maven-plugin is used to spin up an embedded Tomcat server that will host the RESTful Hello World API.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.codenotfound</groupId>
  <artifactId>json-api-katharsis-helloworld</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <name>json-api-katharsis-helloworld</name>
  <description>JSON API - Katharsis Spring Boot Hello World Example</description>
  <url>https://www.codenotfound.com/2017/04/json-api-katharsis-spring-boot-example.html</url>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.2.RELEASE</version>
  </parent>

  <properties>
    <java.version>1.8</java.version>

    <katharsis.version>3.0.1</katharsis.version>
    <okhttp.version>3.6.0</okhttp.version>
  </properties>

  <dependencies>
    <!-- spring-boot -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <!-- katharsis -->
    <dependency>
      <groupId>io.katharsis</groupId>
      <artifactId>katharsis-core</artifactId>
      <version>${katharsis.version}</version>
    </dependency>
    <dependency>
      <groupId>io.katharsis</groupId>
      <artifactId>katharsis-spring</artifactId>
      <version>${katharsis.version}</version>
    </dependency>
    <dependency>
      <groupId>io.katharsis</groupId>
      <artifactId>katharsis-client</artifactId>
      <version>${katharsis.version}</version>
    </dependency>
    <!-- okhttp -->
    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp</artifactId>
      <version>${okhttp.version}</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <!-- spring-boot-maven-plugin -->
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>


Spring Boot is used in order to make a stand-alone Katharsis example application that we can "just run." The SpringKatharsisApplication class contains the main() method that uses Spring Boot’s SpringApplication.run() method to launch the application.

The @SpringBootApplication annotation is a convenience annotation that adds: @Configuration, @EnableAutoConfiguration and @ComponentScan.

package com.codenotfound.katharsis;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringKatharsisApplication {

  public static void main(String[] args) {
    SpringApplication.run(SpringKatharsisApplication.class, args);
  }
}


Creating the Domain Model

We start by defining a simple model that will represent a Greeting resource. It contains an id in addition to the actual greeting content. We also need to define the constructors and getters/setters for the two fields.

The @JsonApiResource annotation defines a resource. It requires the type parameter to be set which will be used to form the URI and populate the type field, which is passed as part of the resource object. According to JSON API standard, the name defined in type can be either plural or singular. However, the same value should be used consistently throughout an implementation.

The @JsonApiIddefines a field which will be used as an identifier of the Greeting resource. Each resource requires this annotation to be present on a field which is of primitive type or a type that implements the Serializable interface.

package com.codenotfound.katharsis.domain.model;

import io.katharsis.resource.annotations.JsonApiId;
import io.katharsis.resource.annotations.JsonApiResource;

@JsonApiResource(type = "greetings")
public class Greeting {

  @JsonApiId
  private long id;

  private String content;

  public Greeting() {
    super();
  }

  public Greeting(long id, String content) {
    this.id = id;
    this.content = content;
  }

  public long getId() {
    return id;
  }

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

  public String getContent() {
    return content;
  }

  public void setContent(String content) {
    this.content = content;
  }
}


Creating the Repository

To allow Katharsis to operate on defined resources, a special type of class called repository needs to be created. Katharsis will scan for these classes and, using annotations, it will discover the available methods.

For our Greeting resource we will create a GreetingRepositoryImpl which extends the ResourceRepositoryBase implementation of the ResourceRepositoryV2 repository interface. The ResourceRepositoryBase is a base class that takes care of some boiler-plate code like for example implementing findOne() with findAll(). Note that when extending the ResourceRepositoryBase only findAll() needs to be implemented to have a working read-only repository.

In this example, we will store the greeting resources in a simple HashMap and add a “Hello World!” greeting as a resource via the constructor.

Katharsis passes JSON API query parameters to repositories through a QuerySpec parameter. The implementation of the findAll() uses the apply() method which evaluates the querySpec against the provided list and returns the result. Note that the @Component annotation is needed so that Katharsis is able to find the repository.

package com.codenotfound.katharsis.domain.repository;

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Component;

import com.codenotfound.katharsis.domain.model.Greeting;

import io.katharsis.queryspec.QuerySpec;
import io.katharsis.repository.ResourceRepositoryBase;
import io.katharsis.resource.list.ResourceList;

@Component
public class GreetingRepositoryImpl extends ResourceRepositoryBase<Greeting, Long> {

  private Map<Long, Greeting> greetings = new HashMap<>();

  public GreetingRepositoryImpl() {
    super(Greeting.class);

    greetings.put(1L, new Greeting(1L, "Hello World!"));
  }

  @Override
  public synchronized ResourceList<Greeting> findAll(QuerySpec querySpec) {
    return querySpec.apply(greetings.values());
  }
}


Setting Up the Server

Katharsis comes with out-of-the-box support for Spring Boot. The entry point is a KatharsisConfig class which configures Katharsis using Spring properties. Additionally, we have to make sure that each repository is annotated with @Component (as we did with the above GreetingRepositoryImpl).

Spring’s @RestController annotation is used to mark the KatharsisController class as a controller for handling HTTP requests. The KatharsisConfigV3 import will setup and expose the resource endpoints based on auto-scanning for specific annotations in addition to some properties which we will see further below.

Katharsis also ships with a ResourceRegistry which holds information on all the registered repositories. We expose this information on /resources-info by iterating over all the entries in the auto-wired ResourceRegistry.

package com.codenotfound.katharsis.server;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Import;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import io.katharsis.resource.registry.RegistryEntry;
import io.katharsis.resource.registry.ResourceRegistry;
import io.katharsis.spring.boot.v3.KatharsisConfigV3;

@RestController
@Import({KatharsisConfigV3.class})
public class KatharsisController {

  @Autowired
  private ResourceRegistry resourceRegistry;

  @RequestMapping("/resources-info")
  public Map<String, String> getResources() {
    Map<String, String> result = new HashMap<>();
    // Add all resources
    for (RegistryEntry entry : resourceRegistry.getResources()) {
      result.put(entry.getResourceInformation().getResourceType(),
          resourceRegistry.getResourceUrl(entry.getResourceInformation()));
    }

    return result;
  }
}


In addition to the above auto-configuration, a number of items are configured using the application.yml properties file:

  • The katharsis:resourcePackage property specifies which package(s) should be searched to find models and repositories used by the core and exception mappers. Multiple packages can be passed by specifying a comma separated string of packages.
  • The katharsis:domainName property specifies the domain name as well as protocol and optionally port number to be used when building links objects in responses. The value must not end with a backslash (/).
  • The katharsis:pathPrefix property defines the default prefix of the URL path used when building link objects in responses and when performing method matching.
katharsis:
  resourcePackage: com.codenotfound.katharsis.domain
  domainName: http://localhost:9090/codenotfound
  pathPrefix: /api

server:
  context-path: /codenotfound
  port: 9090


Setting Up the Client

Katharsis includes a Java client which allows communication with JSON-API compliant servers. To start using the client just create an instance of KatharsisClient and pass the service URL. Then use the client to create a repository that gives access to the different resource CRUD operations.

In the below GreetingClient we have created a findOne() method that returns a single Greeting based on the identifier.

package com.codenotfound.katharsis.client;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.codenotfound.katharsis.domain.model.Greeting;

import io.katharsis.client.KatharsisClient;
import io.katharsis.queryspec.QuerySpec;
import io.katharsis.repository.ResourceRepositoryV2;

@Component
public class GreetingClient {

  private static final Logger LOGGER = LoggerFactory.getLogger(GreetingClient.class);

  private KatharsisClient katharsisClient =
      new KatharsisClient("http://localhost:9090/codenotfound/api");
  private ResourceRepositoryV2<Greeting, Long> resourceRepositoryV2;

  @PostConstruct
  public void init() {
    resourceRepositoryV2 = katharsisClient.getRepositoryForType(Greeting.class);
  }

  public Greeting findOne(long id) {
    Greeting result = resourceRepositoryV2.findOne(id, new QuerySpec(Greeting.class));

    LOGGER.info("found {}", result.toString());
    return result;
  }
}


Testing the Hello World JSON API

Let’s test our greeting resource! If you are running Google Chrome you can simply do this from the browser. Make sure you start the application by starting up Spring Boot:

mvn spring-boot:run


Next, open the following URL which should show all our registered resources (in this example the greetings resource).

http://localhost:9090/codenotfound/resources-info
hello world resource registry







Go ahead and use the greetings endpoint as the next URL. This will show us all the available greetings.

http://localhost:9090/codenotfound/api/greetings
hello world greetings







For the details of our Hello World resource, we enter the below URL.

http://localhost:9090/codenotfound/api/greetings/1
hello world greeting 1







Notice that above flow is fully driven using hypermedia!


To wrap up we will also add a simple SpringKatharsisApplicationTest unit test case in which we lookup the Hello World greeting resource using it’s identifier.

package com.codenotfound.katharsis;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;

import com.codenotfound.katharsis.client.GreetingClient;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
public class SpringKatharsisApplicationTest {

  @Autowired
  GreetingClient greetingClient;

  @Test
  public void testFindOne() {
    assertThat(greetingClient.findOne(1L).getContent()).isEqualTo("Hello World!");
  }
}


Triggering the test case is done using the following Maven command.

mvn test


Output should be as shown below.

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.2.RELEASE)

09:35:41.763 [main] INFO  c.c.k.SpringKatharsisApplicationTest - Starting SpringKatharsisApplicationTest on cnf-pc with PID 1740 (started by CodeNotFound in c:\code\st\json-api\json-api-katharsis-helloworld)
09:35:41.765 [main] INFO  c.c.k.SpringKatharsisApplicationTest - No active profile set, falling back to default profiles: default
09:35:44.476 [main] INFO  c.c.k.SpringKatharsisApplicationTest - Started SpringKatharsisApplicationTest in 3.02 seconds (JVM running for 3.693)
09:35:44.900 [main] INFO  c.c.katharsis.client.GreetingClient - found com.codenotfound.katharsis.domain.model.Greeting@a52ca2e
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.574 sec - in com.codenotfound.katharsis.SpringKatharsisApplicationTest

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.963 s
[INFO] Finished at: 2017-04-21T09:35:45+02:00
[INFO] Final Memory: 28M/262M
[INFO] ------------------------------------------------------------------------


If you would like to run the above code sample, you can get the full source code here.

This wraps up the Katharsis JSON API tutorial in which we developed a simple Hello World resource from scratch and exposed it via a RESTful API.

API Spring Framework JSON Spring Boot

Published at DZone with permission of [deleted]. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • What Should You Know About Graph Database’s Scalability?
  • Why Every Fintech Company Needs DevOps
  • PostgreSQL: Bulk Loading Data With Node.js and Sequelize
  • Key Considerations When Implementing Virtual Kubernetes Clusters

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: