GraphQL Tutorial: Understanding Spring Data JPA/SpringBoot

GraphQL Tutorial: Understanding Spring Data JPA/SpringBoot

Let's understand Spring Data JPA and Spring Boot with a practical example.

Let's understand Spring Data JPA and Spring Boot with a practical example.

GraphQL is a query language for APIs. Generally, while making REST endpoints in our APIs, the normal trend is to make an endpoint for a requirement. Let’s say your endpoint is returning a list of employees, and each employee has general properties, such as name, age, and address (suppose address is another model mapped to the employee in such a way that each employee has an address). Now, at one point in time, you require data only for their address i.e. a list of all addresses in the database (only country, city, and street). For this, you will require an all-new endpoint in your service.

Here comes the power of GraphQL, which lets you deal with only a single endpoint and that changes its output based on the body of the request. Each request will call the same endpoint but with a different RequestBody. It will receive only the result that it requires.

Refer to the code on GitHub for complete code files. It’s a maven project with an H2 database that has data.sql at classpath for database queries. This code rotates around getting a list of all employees from the database.

Now, let’s begin with a practical implementation with Spring Boot.

We have two model classes: employee and address with respective getters and setters.

@Entity
@Table
public class Employee {
String name;
@Id
String id;
int age;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "addid")
Address address;
  //......getters and setters....//
}

@Entity
@Table
public class Address {
@Id
@GeneratedValue
String addid;
String country;
String city;
String flat;
  //......getters and setters....//
}

To implement the repository, we have the EmployeeRepo as:

@Repository
public interface EmployeeRepo extends CrudRepository<Employee, String> {

public List<Employee> findAll();

}


Now, GraphQL requires a .graphqls file at the classpath, which it parses and understands the type of request it needs to handle. You will find employee.graphqls in the code. Let me explain that.

It contains:

type Employee{

.......Employee details

}

and type Address{

........Address Details

}

Here, we are defining the schema of our classes, which will, in one way or another, be returned as a response to the endpoint i.e either it will return all employees, the addresses of all employees, only the names of all employees, etc.

We also defined:

type Query{

allEmployee: [Employee]
}

Type of query (a query that will be sent by the client or that will be present in RequestBody) here is returning list of employees.

So, RequestBody to our endpoint will contain a root query as allEmployee.

Let’s discuss requests here:

  1. Requests that require all employees without their addresses:
{
allEmployee{
name
    age
id
}
}

  1. Requests that require only employee names and the country that they belong to:
{
allEmployee{
name
address {
country
}
}

}

  1. Requests that require only the address of all employees will be:
{
allEmployee{

address {
country
                city
                flat
                addid
}
}

}

For an explanation of the service layer of the code, read part 2, which is coming soon.

Meanwhile, you can access the full code on GitHub.

Learn More

Node.js - Express Persistent Session Store with PostgreSQL + Sequelize

Build a Simple Web App with Express, Angular, and GraphQL

How to Install PostgreSQL on Ubuntu 18.04

Understanding the basics of RESTful APIs

An Introduction to Queries in PostgreSQL

GraphQL with React: The Complete Developers Guide

GraphQL with Angular & Apollo - The Full-stack Guide

GraphQL: Learning GraphQL with Node.Js

Complete guide to building a GraphQL API

GraphQL: Introduction to GraphQL for beginners

Getting Started with GraphQL and Spring Boot

Getting Started with GraphQL and Spring Boot

GraphQL is a query language for APIs that allows clients to request limited data they need, making it possible for clients to gather data in a limited number of requests. In this article, we will build a simple GraphQL server with Spring Boot.

GraphQL is strongly typed protocol and all data operations are validated against a GraphQL schema.

Adding Maven Dependencies

Create a sample Spring Boot application and add the following dependencies.

  1. graphql-spring-boot-starter is used for enabling GraphQL servlet and it becomes available at a path /graphql. It initializes _GraphQLSchema_ bean.
  2. graphql-java allows to write schema with GraphQL schema language which is simple to understand.
  3. graphiql-spring-boot-starter provides user interface using which we could test our GraphQL queries and view query definition.
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-spring-boot-starter</artifactId>
            <version>5.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java-tools</artifactId>
            <version>5.2.4</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphiql-spring-boot-starter</artifactId>
            <version>5.0.2</version>
        </dependency>

Here is the complete POM file content.

<?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.techshard.graphql</groupId>
    <artifactId>springboot-graphql</artifactId>
    <version>1.0-SNAPSHOT</version>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-spring-boot-starter</artifactId>
            <version>5.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java-tools</artifactId>
            <version>5.2.4</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphiql-spring-boot-starter</artifactId>
            <version>5.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
Creating JPA Entity and Repository

Let’s create a simple entity called Vehicle and a corresponding JPA repository. We will use Lombok to avoid writing boilerplates such as getters, setters and so on.

package com.techshard.graphql.dao.entity;

import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDate;

@Data
@EqualsAndHashCode
@Entity
public class Vehicle implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ID", nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

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

    @Column(name = "model_code", nullable = false)
    private String modelCode;

    @Column(name = "brand_name")
    private String brandName;

    @Column(name = "launch_date")
    private LocalDate launchDate;

    private transient  String formattedDate;

    // Getter and setter
    public String getFormattedDate() {
        return getLaunchDate().toString();
    }
}

Here is the corresponding JPA repository.

package com.techshard.graphql.dao.repository;

import com.techshard.graphql.dao.entity.Vehicle;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface VehicleRepository extends JpaRepository<Vehicle, Integer> {
}

GraphQL Schema

GraphQL comes with its own language to write GraphQL Schema called Schema Definition Language (SDL). The schema definition consists of all the API functionalities available at an endpoint.

A typical example of GraphQL schema would look like this:

type Vehicle {
	id: ID!,
	type: String,
	modelCode: String,
	brandName: String,
	launchDate: String
}

type Query {
	vehicles(count: Int):[Vehicle]
	vehicle(id: ID):Vehicle
}

type Mutation {
	createVehicle(type: String!, modelCode: String!, brandName: String, launchDate: String):Vehicle
}

Create a folder graphql under src/main/resources and create a file vehicleql.graphqls under that folder. Copy the above contents and paste it in the vehicleql.graphqls file. Note that, the name of the file could be any name of your choice. Just make sure to keep the file extension as .graphqls.

In the above schema, each object is defined with type. The type system in GraphQL is the most basic component and it represents a kind of object that can be fetched from a service and the fields that the object contains within.

In our schema, we have an object called Vehicle which is our domain object. The type Query represents the query that can be made to the GraphQL server to fetch data. This query is interactive, they can be modified, and new results can be seen. The structure of query and result is same. This is important in GraphQL world, because we always get back the result that we expect.

We will see a working example in this article later.

The type Mutation represents the queries that are used to perform write operations on the data.

Root Query

Query or Mutation objects are root GraphQL objects, they don’t have any associated data class. In such cases, the resolver classes would implement GraphQLQueryResolver or GraphQLMutationResolver. These resolvers will be searched for methods that map to fields in their respective root types.

Let’s define root resolvers for Vehicle.

package com.techshard.graphql.query;

import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import com.techshard.graphql.dao.entity.Vehicle;
import com.techshard.graphql.service.VehicleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

@Component
public class VehicleQuery implements GraphQLQueryResolver {

    @Autowired
    private VehicleService vehicleService;

    public List<Vehicle> getVehicles(final int count) {
        return this.vehicleService.getAllVehicles(count);
    }

    public Optional<Vehicle> getVehicle(final int id) {
        return this.vehicleService.getVehicle(id);
    }
}

In this class, we have methods to get a single Vehicle object and a list of Vehicle objects. Note that, we have defined these methods in our schema above.

Now, let’s define a Mutation resolver.

package com.techshard.graphql.mutation;

import com.coxautodev.graphql.tools.GraphQLMutationResolver;
import com.techshard.graphql.dao.entity.Vehicle;
import com.techshard.graphql.service.VehicleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDate;

@Component
public class VehicleMutation implements GraphQLMutationResolver {

    @Autowired
    private VehicleService vehicleService;

    public Vehicle createVehicle(final String type, final String modelCode, final String brandName, final String launchDate) {
        return this.vehicleService.createVehicle(type, modelCode, brandName, launchDate);
    }
}

In this class, we only have one method to create a Vehicle object and this corresponds to type Mutation in our schema definition.

We will now define a service which would make actual transactions.

package com.techshard.graphql.service;

import com.techshard.graphql.dao.entity.Vehicle;
import com.techshard.graphql.dao.repository.VehicleRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class VehicleService {

    private final VehicleRepository vehicleRepository ;

    public VehicleService(final VehicleRepository vehicleRepository) {
        this.vehicleRepository = vehicleRepository ;
    }

    @Transactional
    public Vehicle createVehicle(final String type,final String modelCode, final String brandName, final String launchDate) {
        final Vehicle vehicle = new Vehicle();
        vehicle.setType(type);
        vehicle.setModelCode(modelCode);
        vehicle.setBrandName(brandName);
        vehicle.setLaunchDate(LocalDate.parse(launchDate));
        return this.vehicleRepository.save(vehicle);
    }

    @Transactional(readOnly = true)
    public List<Vehicle> getAllVehicles(final int count) {
        return this.vehicleRepository.findAll().stream().limit(count).collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public Optional<Vehicle> getVehicle(final int id) {
        return this.vehicleRepository.findById(id);
    }
}

Testing the Application

The application is now ready for testing. Run the Spring Boot application. Open the link http://localhost:8080/graphiql in the browser. We will see a nice user interface as below.

On the right side of user interface, we can also explore documentation.

Now, run the following query.

mutation {
  createVehicle(type: "car", modelCode: "XYZ0192", brandName: "XYZ", launchDate: "2016-08-16") 
  {
    id
  }
}

This will create a row in the Vehicle table. The result would be:

{
  "data": {
    "createVehicle": {
      "id": "1"
    }
  }
}

Let us now run a query to get the data.

query {
  vehicles(count: 1) 
  {
    id, 
    type, 
    modelCode
	}
}

The output will be:

{
  "data": {
    "vehicles": [
      {
        "id": "1",
        "type": "bus",
        "modelCode": "XYZ123"
      }
    ]
  }
}

Note that we are requesting for only limited number of fields. We can change our query by adding or removing fields and see the new results.

Conclusion

In this article, we looked at the basic concepts of GraphQL. Check out the detailed documentation here.

The complete source code for this tutorial can be found on GitHub.

Understand to Spring Boot: MySQL and JPA, Hibernate

Understand to Spring Boot: MySQL and JPA, Hibernate

Spring Boot uses Hibernate as the default JPA implementation. The property spring.jpa.hibernate.ddl-auto is used for database initialization. I've used the value “update” for this property.

Before we start, this post is mostly aimed at Java developers, specifically Java developers who use the Spring umbrella of frameworks for development. If you are not a Java developer, you can still read on, chances are you haven't found the love of your life - in terms of languages - yet.

Also, I apologise in advance for the markup mishaps that will pop up here and there in various code sections. You could check out the original blog post here Original Post if you have trouble understanding/copy pasting the code.

First off, what really is Spring?

If you are a java developer, you've probably stumbled upon the term 'Spring' at some point in your journey, and possibly fell face first at either its learning curve, or its complexity. One thing most developers fail to understand - I also struggled with this at first - is that Spring represents a collection of frameworks that are tailored to meet specific development needs. As an example, if you're a java web developer, Spring provides the Web Servlet Framework for web development where Spring MVC (Included in this framework) is built on top of the Servlet API. Therefore, you need not learn all the frameworks that Spring provides, but rather the frameworks that fit your specific use case. Yeah, that's a shortcut, and yes, you're welcome.

If you've never heard about Spring before, Spring is an Inversion of Control and Dependency injection framework. This are fairly big terms but this comprehensive post will help you understand the meanings of these two concepts: IoC and Dependency Injection

Now onto Spring Boot

If you have used Spring MVC before, you've definitely have had to wrestle with Spring MVC's pre-configurations like Setting up the Dispatcher Servlet etc. etc. before you were able to get the framework up and running. This is where Spring Boot comes in. Spring Boot is an auto-configuration tool for setting up your Spring-powered applications. You can now put away those boxing gloves cause you might not need to wrestle with Spring Boot.

To help you understand Spring Boot further, and shine a light on why you should be using it if you already aren't, we'll build a simple Netflix API that allows client devices to register themselves, suggest movies and query movies.

Let us begin

Step 1: Setting up Spring Boot on your application.

Spring offers a project initializer, Spring Initialzr that allows you to select your project specifications and download an already configured Spring Boot project as a zip file or a maven build file. You could skip to step 2 if you have done this.

If you're a more of a hands on type of person who enjoys understanding what's happening under the hood, you can continue with this step.

Folder Structure.

Create a new Java project with you favourite IDE and configure your folder structure to mimic the following design:

└── src
    └── main
        └── controllers
        └── models
        └── repositories
        └── resources
            └── templates
                └── error.html
            └── application.properties
        └── Application.java

contollers - This folder will contain the controllers we define for this project

repositories - This folder will contain the repositories we'll define for our models that will be used to fetch data from the database.

resources - this folder will contain our project resources. The templatesfolder contains our template files that will be rendered by Spring. You can include other folders like static which will be used to server static content like javascript and css files.

Maven dependencies

Spring Boot allows us to include in our pom.xml file all the Spring dependencies that we'll use in our project. Copy paste the following dependencies, together with the Spring Boot Maven Plugin to your pom.xml.

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
&lt;groupId&gt;org.springframework&lt;/groupId&gt;
&lt;artifactId&gt;gs-spring-boot&lt;/artifactId&gt;
&lt;version&gt;0.1.0&lt;/version&gt;

&lt;parent&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
    &lt;version&gt;2.1.6.RELEASE&lt;/version&gt;
&lt;/parent&gt;

&lt;dependencies&gt;
    &lt;!--Spring dependencies--&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-thymeleaf&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-devtools&lt;/artifactId&gt;
    &lt;optional&gt;true&lt;/optional&gt;
&lt;/dependency&gt;

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!--Spring JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>

&lt;properties&gt;
    &lt;java.version&gt;1.8&lt;/java.version&gt;
&lt;/properties&gt;


&lt;build&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/build&gt;

</project>

Our dependencies overview:

1. spring-boot-starter-web - When building web applications using java, we often need other external dependencies that we include in our pom.xml like tomcat and Spring MVC. What spring-boot-starter-web does is add all these dependencies through one single dependency.

2. spring-boot-starter-thymeleaf - If you've never used thymeleaf before, thymeleaf is a templating engine for processing and creating HTML, XML, JavaScript, CSS, and text whose template files retain the .html extension and therefore a better alternative to JSPs (Java Server Pages). What this basically means is that you can run thymeleaf template files like normal web pages without a backend server for template processing as in the case of JSPs.

3. spring-boot-devtools - These tools grease your gears of development therefore making the overall development process more bearable. To learn more about what these tools offer, you can check out this link: spring-boot-devtools

4. mysql-connector-java - These is the MySQL JDBC implementation that we'll use to make connections to our MySQL database.

5. spring-boot-starter-data-jpa - Most if not all web applications need some form of persistence, which in java cases, is often JPA (Java Persistence API). If spring-boot-data-jpa is in the classpath, Spring boot will automatically configure our data-source through reading our database configuration from the application.properties file that we will configure next.

Note that we've set our java version to 1.8 since JDK 11 does not offer a lot of things out of the box and therefore you may run into errors like: springboot: org.hibernate.MappingException: Could not get constructor for org.hibernate.persister.entity.SingleTableEntityPersister

Application.properties file

Spring boot automatically reads configuration settings from this file and configures our spring boot environment accordingly. We'll configure our database here and also at the same time disable Spring boot's whitelabel error page which we'll replace with our own custom error page. You can copy paste all this into your own application.properties file if you do not intended to make any changes.

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/netflix?useSSL=false
spring.datasource.username = netflix
spring.datasource.password = netflix

Hibernate Properties The SQL dialect makes Hibernate generate better SQL for the chosen database

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

Hibernate ddl auto (create, create-drop, validate, update)

spring.jpa.hibernate.ddl-auto = update

#Disabling the whitelabel error page
server.error.whitelabel.enabled=false

In the above application.properties file, We've configured our database, username and password to netflix . You can configure this if you want to. Spring JPA automatically uses the Hibernate implementation of JPA. 

We've set spring.jpa.hibernate.ddl-auto to update which will ensure that any changes we make to our models will be reflected in our Database, which also includes creating a new model. Please note that this option is only suitable for development environments rather than production environments. For more information, you can check this link: Database Initialization.

We've also set server.error.whitelabel.enabled to false to disable Spring boot's whitelabel error pages which we'll replace with our own custom error page.

Configuring our Application.java file

This file will contain the main method which we'll use to ignite our Spring Application with. Copy paste the following to your Application.java file:

package main;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableJpaRepositories(basePackages="main.repositories")
@EnableTransactionManagement
@EnableJpaAuditing
@EntityScan(basePackages={"main.entities","main.models"})
public class Application {

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

}

@SpringBootApplication is a combination of the following more specific spring annotations -

1. @Configuration : Any class annotated with @Configuration annotation is bootstrapped by Spring and is also considered as a source of other bean definitions.

2. @EnableAutoConfiguration : This annotation tells Spring to automatically configure your application based on the dependencies that you have added in the pom.xml file. For example, If spring-data-jpa or spring-jdbc is in the classpath, then it automatically tries to configure a DataSource by reading the database properties from application.properties file.

3. @ComponentScan : It tells Spring to scan and bootstrap other components defined in the current package (main) and all the sub-packages.

@EnableJpaAuditing is used to support the automatic filling of fields that we'll annotate with @CreatedDate.

@EnableJpaRepositories tells Spring where to find our defined Repositories, since we'll not be using the @Repository annotation.


Step 2. Coding our Controllers.

We'll create only 3 Contollers namely: CustomErrorController that we'll use to format and serve our custom error page, MoviesController that will perform movie related functions and UsersContoller that will perform user related functions.

CustomErrorController

In this controller, we'll register a route error that will be mapped to our renderErrorPage method. Therefore all requests made through the errorroute will be recieved by our method.

Note that here we'll use the @Controller annotation since we'd like to return a view rather than plain text and therefore our method returning a string will return the name of the view. To return plain text rather than views, use the @RestController annotation.

We will also format our error messages to make them more user friendly when we display them on our error page.

We've also implemented the ErrorController interface and overridden the getErrorPath() method which will automatically be invoked when Spring encounters an error.

@Controller
public class CustomErrorController implements ErrorController {

@RequestMapping(value = "error",produces = "application/json;charset=UTF-8")
public String renderErrorPage(HttpServletRequest request, Model model) {
     String errorMsg = "";
    Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
    int httpErrorCode = 404;
    if(status != null){
        httpErrorCode = Integer.valueOf(status.toString());
    }
    switch (httpErrorCode) {
        case 400: {
            errorMsg = "Http Error Code: 400. Bad Request";
            break;
        }
        case 401: {
            errorMsg = "Http Error Code: 401. Unauthorized";
            break;
        }
        case 404: {
            errorMsg = "Http Error Code: 404. Resource not found";
            break;
        }
        case 500: {
            errorMsg = "Http Error Code: 500. Internal Server Error";
            break;
        }
    }
    model.addAttribute("error",errorMsg);
    return "error";
}

@Override
public String getErrorPath() {
    return "/error";
}

}

Movies Controller

As we have stated earlier, this Controller will store functionalities related to our movies.

Since we are creating an api, we'll map api requests to url patterns that start with /api. Therefore, we add a @RequestMapping annotation on top of the class, rather than the method so that every request url we map on our methods will be appended to /api.

@RestController
@RequestMapping(value = "/api",produces = "application/json;charset=UTF-8") //All our api request URLs will start with /api and will return Json
public class MoviesController {

private MoviesRepository moviesRepository;
private CategoriesRepository categoriesRepository;
private UserRepository userRepository;

@Autowired
public MoviesController(MoviesRepository moviesRepository, CategoriesRepository categoriesRepository, UserRepository userRepository){
    this.moviesRepository = moviesRepository;
    this.categoriesRepository = categoriesRepository;
    this.userRepository = userRepository;
}

//Suggest A movie
@GetMapping(value = "/suggestMovie")
public String suggestMovie(@RequestParam(name = "category_id") Long categoryId,@RequestParam(name = "name")String name
,@RequestParam(name = "suggested_by")Long suggestedBy){
    //Movies added through this API route are automatically marked as suggested.
    String movieType = Movies.MovieType.SUGGESTED.getMovieType();
    Movies movies = new Movies();

    //Provided category id should be in our categories table.
    if(categoriesRepository.findById(categoryId).isPresent()){

        if(userRepository.findById(suggestedBy).isPresent()){
            movies.setCategoryId(categoryId);
            movies.setName(name);
            movies.setType(movieType);
            movies.setSuggestedBy(suggestedBy);
            return moviesRepository.save(movies).toString();
        } else {
            return "{'error':'The specified user id does not exist.'}";
        }

    } else {
        return "{'error':'The specified category id does not exist.'}";
    }



}

//delete a suggested movie
@GetMapping(value = "/deleteMovie")
public String deleteMovie(@RequestParam(name = "movie_id") Long movieId,@RequestParam(name = "user_id")Long userId) {
    if(userRepository.findById(userId).isPresent()){
        Optional&lt;Movies&gt; movies = moviesRepository.findById(movieId);
        if(movies.isPresent()){
            List&lt;Movies&gt; movie = moviesRepository.findBySuggestedByEqualsAndIdEquals(userId,movieId);
            if(movie.size()&gt;0){
                moviesRepository.delete(movie.get(0));
                return movie.toString();
            } else {
                return generateErrorResponse("The user specified cannot delete this movie");
            }


        } else {
            return  generateErrorResponse("Specified movie id does not exist");
        }

    } else {
        return generateErrorResponse("Specified user id does not exist");
    }
}

//update a suggested movie. Supports only updating of the movie name or category.
@GetMapping(value = "/updateMovie/{movie_id}")
public String updateMovie(@PathVariable(name = "movie_id") Long movieId,@RequestParam(name = "user_id")Long userId,
                          @RequestParam(name = "movie_name",required = false)String movieName, @RequestParam(name = "movie_category",required = false) Long movieCategory) {
    List&lt;Movies&gt; movie = moviesRepository.findBySuggestedByEqualsAndIdEquals(userId,movieId);
    if(!(movie.size()&gt;0)){
        return generateErrorResponse("The user specified cannot update this movie");
    }

    if(moviesRepository.findById(movieId).isPresent()){
        Movies movies = moviesRepository.findById(movieId).get();
        if(movieName != null &amp;&amp; !movieName.isEmpty()){
            movies.setName(movieName);
        }
        if(movieCategory != null &amp;&amp; categoriesRepository.findById(movieCategory).isPresent()){
            movies.setCategoryId(movieCategory);
        }

        return moviesRepository.save(movies).toString();
    } else {
        return generateErrorResponse("The specified movie id does not exist");
    }
}

//query available movies
@GetMapping(value = "/queryMovies/{categoryId}")
public String queryMovies(@PathVariable Long categoryId,@RequestParam(name = "type") String type){
    JsonObjectBuilder jsonResponse = Json.createObjectBuilder();
    JsonObjectBuilder temp = Json.createObjectBuilder();
    int count = 0;
    for(Movies movie:moviesRepository.findAllByCategoryIdEqualsAndTypeEquals(categoryId,type)){
        temp.add("id",movie.getId());
        temp.add("name",movie.getName());
        temp.add("type",movie.getType());
        temp.add("category_id",movie.getCategoryId());
        temp.add("created_at",movie.getCreatedAt().toString());
        jsonResponse.add(count + "",temp);
        temp = Json.createObjectBuilder();
        count++;
    }

    return jsonResponse.build().toString();
}

private String generateErrorResponse(String message){
    return "{\"error\":\"" + message + "\"";
}

//add categories
@GetMapping(value = "/addCategories")
public String addCategories(@RequestParam(name = "name") String name){
    Categories categories = new Categories();
    categories.setName(name);

    return categoriesRepository.save(categories).toString();
}

}

In this Class, you may have noticed annotations that you might have not seen before. Let's go through them quickly:

1. @Autowired - As the annotation itself suggests, this annotation automatically injects an implementation of the movies, users and categories repository interface which we assign the the field variables we have declared. As we mentioned earlier, you need a repository to be able to access database contents, which explains these three repositories. I'll explain this further when we reach the repositories section.

2. @GetMapping - This annotation is the same as @RequestMapping except that it only maps get requests to the specified url.

3. @RequestParam - This annotation automatically injects the specified query parameter name to this variable.

4. @PathVariable` - This annotation automatically injects the path value - enclosed in curly braces - to this variable.

Users Controller

This controller will contain functionalities related to users. In this case, we'll define only a single method that will be responsible for creating a user.

@RestController

@RequestMapping(value = "/api",produces = "application/json;charset=UTF-8") //All our api request URLs will start with /api and return Json

public class UsersController {

private UserRepository userRepository;

@Autowired
public UsersController(UserRepository userRepository){
this.userRepository = userRepository;
}

@GetMapping(path = "/addUser")
public String addUser(@RequestParam(name = "id")Long id, @RequestParam(name="name") String name) {
Users users = new Users();
users.setId(id);
users.setName(name);

users = userRepository.save(users);
return users.toString();

}
}

Our user IDs in this case will not be auto-generated but instead, we'll provide users with an option to define their own IDs.

Step 3. Defining our Repositories

Repositories will be used by our models to query data from the Database. spring-jpa comes with a JpaRepository interface that defines all CRUD operations that we can perform on an Entity. We'll use the CrudRepositoryimplementation of JpaRespository as it offers many CRUD operations out of the box through methods like findAll(), save() etc. At the same time, CrudRepository automatically generated for us dynamic queries based on method names as we'll see in the following example.

We'll define three repositories for our three entities: CategoriesRepository , MoviesRepository and UsersRepository, which will all be interfaces extending CrudRepository.

CategoriesRepository

public interface CategoriesRepository extends

CrudRepository<Categories,Long> {

}

MoviesRepository

public interface MoviesRepository extends CrudRepository {

List<Movies> findAllByCategoryIdEqualsAndTypeEquals(Long categoryId,String type);

List<Movies> findBySuggestedByEqualsAndIdEquals(Long suggestedBy,Long movieId);

In this repository, notice the abstract methods we have defined. Extending CrudRepository will automatically compel Spring to create an implementation of these methods automatically at run-time just from the definition of the method name. To add Custom methods, we can add them in the following ways:

  1. We can start our query method names with find...Byread...Byquery...Bycount...By, and get...By. Before By we can add expression such as Distinct . After By we need to add property names of our entity.
  2. To get data on the basis of more than one property we can concatenate property names using And and Or while creating method names.
  3. If we want to use completely custom name for our method, we can use @Query annotation to write query.

UsersRepository

@Repository

public interface UserRepository extends CrudRepository {

Final Step: Defining our models.

The models (Entities) that we define will be used to store our table structures as will be defined in the database. We will therefore have three models for our three tables: Categories , Movies and Users.

Categories Model

@Entity

@Table(name = "categories")

public class Categories {

@Id
@GeneratedValue
private Long id;

@NotBlank
private String name;

public Long getId() {
return id;
}

public String getName() {
return name;
}

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

@Override
public String toString() {
JsonObjectBuilder builder = Json.createObjectBuilder();

//serialize to Json only if the data was persisted.
if(!Objects.isNull(id)){
    builder.add("id",id);
}
if(!Objects.isNull(name)){
    builder.add("name",name);
}

return builder.build().toString();

}

}

`

An entity is a plain old Java object (POJO) class that is mapped to the database and configured for usage through JPA using annotations and/or XML.

Note that we've included a @Table annotation to explicitly define the name of our table. The @Id annotation automatically declares the created field as a primary key for our table in our database. At the same time, the @GeneratedValue annotation will automatically generate a value and store it in the database during saving of a record, pretty much like an auto-increment field. The @NotBlank annotation will automatically validate values that will be inserted into the name variable we defined and ensure that this field is not blank.

We've also defined our own toString method (overriding the superclass's toString method) that will convert our model to a Json string that we return as a response in our controllers.

Movies Model

@Entity

@Table(name = "movies")

@EntityListeners(AuditingEntityListener.class)

@JsonIgnoreProperties(value = {"createdAt"},allowGetters = true)

public class Movies implements Serializable {

@Id
@GeneratedValue
private Long id;

private Long categoryId;

@NotBlank
private String type;

@NotBlank
private String name;

private Long suggestedBy;

@Column(nullable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
@CreatedDate
private Date createdAt; //Stores the date at which a user was created.

@PrePersist
public void prePersist(){
createdAt = new Date();
}

public Long getId() {
return id;
}

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

public Long getCategoryId() {
return categoryId;
}

public void setCategoryId(Long categoryId) {
this.categoryId = categoryId;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public String getName() {
return name;
}

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

public Date getCreatedAt() {
return createdAt;
}

@Override
public String toString() {
JsonObjectBuilder builder = Json.createObjectBuilder();

//serialize to Json only if the data was persisted.
if(!Objects.isNull(id)){
    builder.add("id",id);
}
if(!Objects.isNull(name)){
    builder.add("name",name);
}

if(!Objects.isNull(categoryId)){
    builder.add("category_id",categoryId);
}

if(!Objects.isNull(createdAt)) {
    builder.add("created_at",createdAt.toString());
}
return builder.build().toString();

}

public Long getSuggestedBy() {
return suggestedBy;
}

public void setSuggestedBy(Long suggestedBy) {
this.suggestedBy = suggestedBy;
}

public enum MovieType{
SUGGESTED("suggested"),ORIGINAL("original");

private String movieType;

 MovieType(String movieType){
    this.movieType = movieType;
}

public String getMovieType() {
    return movieType;
}

}

In this model, note the annotations below:

1. @EntityListeners(AuditingEntityListener.class) - This will attach an entity listener to our model class that will automatically fill the fields we've annotated with @CreatedAt.

2. `@PrePersist - This annotation will ensure that the automatically generated value for the createdAt field is stored in this field whenever we'll need access. For more information on Database Auditing you can check this link: Database Auditing

Users Model

@Entity
@Table(name = "users")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = {"createdAt"},
allowGetters = true)
public class Users implements Serializable {
private static final long serialVersionUID = 2L;

@Column(updatable = false)
@Id
private Long id;

@NotBlank(message = "The field 'name' is mandatory.")
private String name;

@Column(nullable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
@CreatedDate
private Date createdAt; //Stores the date at which a user was created.

@PrePersist
public void prePersist(){
    createdAt = new Date();
}

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

public long getId() {
    return id;
}

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

public String getName() {
    return name;
}



@Override
public String toString() {
    JsonObjectBuilder builder = Json.createObjectBuilder();

    //serialize to Json only if the data was persisted.
    if(!Objects.isNull(id)){
        builder.add("id",id);
    }
    if(!Objects.isNull(name)){
        builder.add("name",name);
    }

    if(!Objects.isNull(createdAt)) {
        builder.add("created_at",createdAt.toString());
    }
    return builder.build().toString();
}


public Date getCreatedAt() {
    return createdAt;
}

}

The Custom Error Page Template

In the templates folder we defined, create a html page and name it error.html and copy paste the following code into it:

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Error</title>
</head>
<body>
    <div>Web Application. Error : th:text="${error}"</div>
</body>
</html>

thymeleaf will automatically parse this html page and render our error message by replacing the th:text attribute.

Finally

Run your Application.java's main method and test out your netflix api on your browser by navigation to localhost:8080/. You should be able to see your json responses on your browser. Alternatively, you can check out my git repository for the source code and a client you can test your code with: github repo

Conclusion

You've successfully made a netflix api using Spring boot, mysql and JPA. Congrats!

Thanks For Visiting, Keep Visiting.

Building a Secure API with GraphQL & Spring Boot

Building a Secure API with GraphQL & Spring Boot

Build a Secure API with Spring Boot and GraphQL. GraphQL is a data query language developed by Facebook in 2012 to solve a shortcoming of REST APIs and traditional database models.

GraphQL is a data query language developed by Facebook in 2012 to solve a shortcoming of REST APIs and traditional database models. All too often, when programmers write REST API data queries, they default to retrieving entire data structures when they need only a part of it. For example, if you want to find out the number of comments on a blog post, a developer might typically retrieve the entire post and all associated fields along with all the comments and all their associated fields only to count the number of comments in the resulting array.

This is pretty inefficient. However, modern computers are fast. Even a shared server these days is pretty damn fast, as long as you have hundreds or thousands of users. However, when you get to Facebook scale, reaching a sizeable portion of the human beings on the internet, this breaks down. This kind of inefficiency becomes either unworkable or expensive.

It is possible, of course, to write a better SQL query (or NoSQL query) and write a specific API front end call to count the number of blog posts that is far more efficient - but you have to do this for every specific data query case.

There’s also the problem of wanting more data. What if you want a set of users blog posts and their associated comments AND you also want another set of unrelated data? Typically you make two separate calls to the REST API. In fact, a REST API interaction can result in dozens of calls over the course of a specific API interaction as all necessary data is retrieved. Again, on modern broadband and with relatively few users, this is functional. With hundreds of millions or even billions of users, it breaks down. Milliseconds of efficiency matter. Reducing the number of network calls matters.

There has to be a better way, a more generalized way to allow a front end to request only the data it wants, and to reduce the number of network interactions by combining requests for data.

This is why Facebook developed GraphQL. It provides a framework to describe your data model and allow consumers of the data to ask for exactly what they want and to retrieve predictable results.

When Would I Use GraphQL?

GraphQL is enormously powerful and flexible, and when used at internet scale, can provide a significant performance improvement over traditional REST APIs. So why wouldn’t you use it? Well, in my experience, on smaller projects, I felt like I was often just moving a lot of REST logic into GraphQL schema definitions, where validation and authorization code ended up being nested into a fairly ugly gigantic schema. I also felt like I was duplicating my data type definitions: once in GraphQL and another time in my ORM (this may not be a problem with all implementations).

GraphQL also brings a unique set of security concerns - there’s nothing wrong with it; it’s just going to be different than using REST APIs or SQL queries so you need to spend a little time researching security. I would consider using it in a situation where an application was going to scale quickly or where the data set might evolve significantly over time. If I had a limited set of well defined data on a smaller project, I’d probably just stick with a REST API.

How Do I Use GraphQL?

From a developer perspective, there are two major components:

  • the type descriptions
  • the query language

The type descriptions end up looking a lot like ORMs (if you’re familiar with those). You define types and fields on those types. Later you also define functions to retrieve that information from your database.

For example, let’s look at a very simple blog post definition.

type Post {  
    id: ID!  
    text: String!  
}

Pretty basic. A post has an id and a text field. Let’s add some comments to the Post type definition.

type Post {  
    id: ID!  
    text: String!  
    comments: [Comment!]!  
}  

type Comment {
id: ID!
text: String!
}

Now the type Post contains an array of type Comments. How do we turn this into a usable GraphQL schema definition?

We need to do two things:

  1. Define a “Query” type–the entry point for all GraphQL queries into our data
  2. Write methods for each field on each type that return the requested field from the data type
Define Your GraphQL Schema Query

In the simple example application we’re building, we would want to be able to query for Posts, so lets add a Query type with a post field of type Post. Our GraphQL schema would now look like this:

type Query {
post(id: ID!): Post
}

type Post {
id: ID!
text: String!
comments: [Comment!]!
}

type Comment {
id: ID!
text: String!
}

Just to reiterate, the types Post and Comment directly describe our data structure, and the type Query is a GraphQL-ism, a special type that defines the read-only entry point for the schema. There is also a Mutation type that provides a mutable access point in the schema.

Another thing to note is that fields can have arguments. If you look at the post field on the Query type, you’ll notice it has an argument of type ID. This argument can be specified in the query and will be passed to the function that is called to retrieve the data.

The exclamation points, by the way, simply mean that the type is non-nullable.

Types in GraphQL

GraphQL is basically about defining fields on types and querying for those fields. It is strongly typed, and has 5 built in scalar types:

  • Int: a 32-bit integer
  • Float: A signed double-precision floating-point value
  • String: A UTF‐8 character sequence
  • Boolean: true or false
  • ID: unique identifier, serialized as a String

Custom Scalar types can also be defined, such as a Date type, for example, and methods must be provided for serialization, deserialization, and validation.

Enums and Lists/Arrays can also be specified. We created a List of Comments in our Post type above.

The official GraphQL documentation have more information on types and schemas.

Using GraphQL in Java

In this tutorial, we are going to use a project called graphql-tools to integrate GraphQL with Spring Boot. According to the project github page readme, graphql-tools “allows you to use the GraphQL schema language to build your graphql-java schema and allows you to BYOO (bring your own object) to fill in the implementations.”

It works great if you have, or want to have, plain old java objects (POJO) that define your data model. Which I do.

What would our POJOs look like?

class Post {

protected int id;  
protected String text;  

Post(int id) {  
    this.id = id;  
    this.text = "";  
    this.comments = new ArrayList&lt;Comment&gt;();  
}  

Post(int id, String text, ArrayList&lt;Comment&gt; comments) {  
    this.id = id;  
    this.text = text;  
    this.comments = comments;  
}  

protected ArrayList&lt;Comment&gt; comments;  

}

class Comment {

private int id;  
private String text;  

Comment(int id, String text) {  
    this.id = id;  
    this.text = text;  
}  

}

These classes would define the basic types of our data model, and would correspond to the types in the GraphQL schema. They would be defined in separate java class files. (See what I mean about having duplicate data definitions?)

We would also need to define a couple “Resolvers”. Resolvers are used by graphql-tools to resolve non-scalar types. Each type in our GraphQL schema that contains non-scalar types needs to have an associated Resolver. Thus our Query type and our Post type need resolvers, but our Comment` type does not.

Here is what the Post Resolver might look like:

class PostResolver implements GraphQLResolver<Post> {

public List&lt;Comment&gt; getComments(Post post) {  
    return post.comments;  
}  

}

And here is a skeleton for the Query Resolver:

class Query implements GraphQLQueryResolver {

Post getPost(int id) {
    // Do something to retrieve the post
}  

}

Download the Spring Boot Example App

So now we get to the exciting part! Building a Spring Boot application that uses GraphQL, and securing that application with Okta (which we’ll get to last, and which Okta has made super easy).

Now would be a great time to go ahead and download our example application. It’s based on the example-graphql-tools project from this awesome project on the graphql-java github page.

git clone https://github.com/oktadeveloper/okta-springboot-graphql-example.git

This project is actually two sub-projects:

  • OktaShowToken: used to retrieve a working authorization token from an Okta OAuth OIDC application
  • OktaGraphQL: Spring Boot resource server based on GraphQL (to which we’ll be adding Okta Auth at the end
Create Okta OAuth Application and Install HTTPie

This tutorial makes the assumption that you already have a free Okta Developer account (if not, why don’t you head over to developer.okta.com and create one).

Why Okta?

At Okta, our goal is to make identity management a lot easier, more secure, and more scalable than what you’re used to. Okta is a cloud service that allows developers to create, edit, and securely store user accounts and user account data, and connect them with one or multiple applications. Our API enables you to:

  • Authenticate and authorize your users
  • Store data about your users
  • Perform password-based and social login
  • Secure your application with multi-factor authentication
  • And much more! Check out our product documentation

Create a New OIDC App in Okta

To create a new OIDC app on Okta, you can begin with the default settings, then:

  1. Log in to your developer account, navigate to Applications, and click on Add Application.
  2. Select Web and click Next.
  3. Give the application a name, add http://localhost:8080/login as a Login redirect URI, and click Done.

We’re going to use HTTPie, a great HTTP command line client. So if you don’t have that installed, check it out and follow the installation instructions on httpie.org.

Check Out the OktaGraphQL Example App

Let’s ignore the OktaShowToken project for a moment and take a look at the OktaGraphQL, which is initially configured to run without authentication.

You’ll notice that there isn’t really much to it, beyond the POJO classes and resolvers in the com.okta.springbootgraphql.resolvers package, as well as the GraphQL schema definition found in src/main/resources/graphql-tools.graphqls.

Most of this should be pretty self-explanatory at this point. I’ll simply point out that our Query class (the query resolver) is a bit of a quick and dirty hack to avoid having to setup an actual database data source. We’re just generating the Posts and Comments on the fly based on their ID number. In the real implementation, you’d be adding some more business layer logic here, such as authorization, and looking up the data in your data source.

class Query implements GraphQLQueryResolver {

Post getPost(int id) {  

    if (id == 1) {  
        ArrayList&lt;Comment&gt; comments = new ArrayList&lt;Comment&gt;() {{  
            add(new Comment(1, "GraphQL is amazing!"));  
        }};  
        return new Post(id, "Okta + GraphQL is pretty sweet.", comments);  
    }  
    else if (id == 2) {  
        ArrayList&lt;Comment&gt; comments = new ArrayList&lt;Comment&gt;() {{  
            add(new Comment(1, "I can't believe how easy this is."));  
        }};  
        return new Post(id, "Is GraphQL better than a REST API?", comments);  
    }  
    else {  
        return null;  
    }  
}

}

Run Your First GraphQL Query

Open a terminal and from the OktaGraphQL project directory, start the Spring Boot application using the ./gradlew bootRuncommand.

It may take a few seconds to get started. You should see some output that ends like this:

Tomcat started on port(s): 9000 (http) with context path ''
Started GraphQLToolsSampleApplication in 19.245 seconds (JVM running for 19.664)

Leave that terminal window open and open another terminal window. Navigate again to the project root. Use the following command to run our first GraphQL Query:

http POST http://localhost:9000/graphql/ < json-requests/post1-all-data.json

Here we’re making a POST request with content type application/json (because this is the default for HTTPie) and we’re sending the query found in the json-requests/post1-all-data.json file as the request body.

The request body from json-requests/post1-all-data.json:

{
"query": "{ post(id: '1') { id, text, comments { id, text} } }"
}

The expected result:

HTTP/1.1 200
Content-Length: 122
Content-Type: application/json;charset=UTF-8
Date: Fri, 03 Aug 2018 21:50:25 GMT
{
"data": {
"post": {
"comments": [
{
"id": "1",
"text": "GraphQL is amazing!"
}
],
"id": "1",
"text": "Okta + GraphQL is pretty sweet."
}
}
}

At this point you could play around with the JSON request files, asking for less data or requesting a different post.

We’re going to move on to adding authentication.

Add Okta for OAuth

At this point we’re gonna need a few things from your Okta OAuth application settings:

The client ID and client secret can be found in the general settings for your application (select the Application menu, select the application you want to use, and finally select the General tab).

In the OktaGraphQL project, create a gradle.properties file and fill in the following properties:

oktaClientId={yourClientId}
oktaBaseUrl=https://{yourOktaDomain}

In the src/main/resources/application.yml file, add the following properties:

okta:
oauth2:
issuer: ${oktaBaseUrl}/oauth2/default
clientId: ${oktaClientId}
scopes: 'email profile openid'

Add the following dependencies to the build.gradle file in the OktaGraphQL project. These are the Spring Boot OAuth dependencies and the Okta Spring Boot starter.

compile group: 'com.okta.spring', name: 'okta-spring-boot-starter', version: '0.6.0'
compile group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: '2.3.3.RELEASE'
compile ('org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.1.RELEASE')

Now let’s add two annotations (@EnableResourceServer and @EnableOAuth2Sso) to the GraphQLToolsSampleApplication class. It should look like this:

package com.okta.springbootgraphql;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;

@SpringBootApplication
@EnableResourceServer
@EnableOAuth2Sso
public class GraphQLToolsSampleApplication {

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

}

Stop your Spring Boot app (if it’s still running) and restart it using ./gradlew bootRun.

Run a query against the GraphQL server and you’ll see a 401 error:

HTTP/1.1 401
Cache-Control: no-store
Content-Type: application/json;charset=UTF-8
Date: Fri, 03 Aug 2018 22:10:50 GMT
Pragma: no-cache
Transfer-Encoding: chunked
WWW-Authenticate: Bearer realm="api://default", error="unauthorized", error_description="Full authentication is required to access this resource"
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}
Get an Access Token

To access our protected GraphQL server now, we need an Okta access token. Typically this would be managed through the context of an application front end. For the purposes of this tutorial, we’re going to use our OktaShowToken application to retrieve an authorization token from our Okta application.

In the OktaShowToken project, create a gradle.properties file and fill in the following properties:

oktaClientId={yourClientId}
oktaClientSecret={yourClientSecret}
oktaBaseUrl=https://{yourOktaDomain}

Open a terminal, go to the OktaShowToken project root, and run ./gradlew bootRun.

Once the application completes launching, navigate to http://localhost:8080.

You’ll go through the Okta login and authentication process. You should see the Okta login screen.

After logging in, you’ll see a page of text that contains your access token. Leave this page open and/or copy this token somewhere where you can use it later.

Use the Access Token to Access the GraphQL Endpoint

First lets store the token value in a temporary shell variable:

TOKEN={accessTokenValue}

Then let’s run the request again setting the authorization header. You’ll need to run the following command from the OktaGraphQL directory.

http POST http://localhost:9000/graphql/ Authorization:"Bearer $TOKEN" < json-requests/post1-all-data.json

You should see these familiar results:

HTTP/1.1 200
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 122
Content-Type: application/json;charset=UTF-8
Date: Fri, 03 Aug 2018 22:22:00 GMT
Expires: 0
Pragma: no-cache
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
{
"data": {
"post": {
"comments": [
{
"id": "1",
"text": "GraphQL is amazing!"
}
],
"id": "1",
"text": "Okta + GraphQL is pretty sweet."
}
}
}
Learn More About Spring Boot, GraphQL, and Secure API Design

And that’s it! GraphQL is obviously a pretty deep subject, and if you’re coming from a traditional REST API background, you’ll need to dig into it a little to shift paradigms and properly implement everything.

In their docs, the GraphQL people make a point of repeatedly stating that GraphQL does not replace your business logic layer, but instead provides a data access query language and type schema that sits between your business logic layer and the outside world. Take a look at their docs on authorization to get a feel for this.

But as you can see, Okta’s Spring Boot Starter makes securing a GraphQL endpoint incredibly simple. If you’re interested in learning more about Spring Boot or GraphQL

Thanks For Visiting, Keep Visiting. If you liked this post, share it with all of your programming buddies!

This post was originally published here