How to Build a simple GraphQL server with Spring-Boot

How to Build a simple GraphQL server with Spring-Boot

In this article, we will build a simple GraphQL server with 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. GraphQL is strongly typed protocol and all data operations are validated against a GraphQL schema.

In this article, we will build a simple GraphQL server with Spring Boot.

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.

Thank you for reading!

How to Build a GraphQL API with Java and Spring Boot

How to Build a GraphQL API with Java and Spring Boot

In this tutorial, I’ll show you how to use Java and Spring Boot to build a GraphQL API. How to GraphQL in Java. Create a GraphQL API with Java and Spring Boot. Run Your Java GraphQL API. Test Your Java GraphQL API with JUnit 5. Secure Your Java GraphQL API. Further Reading on GraphQL and Java.

REST APIs are hard to design so they serve multiple clients well. As each client has their own needs in terms of data searching, filtering and which fields they want, a traditional REST API will provide a single version of an entity and the client has the responsibility of navigating through multiple endpoints and correlate the data on their side to build the data they want.

GraphQL was developed by Facebook to overcome the shortcomings they found with REST APIs. It’s a query language for APIs and a runtime for fulfilling those queries with your existing data. By providing a complete and understandable description of the data in your API, clients can leverage that and have the power to ask for exactly what they need. By exposing the schema, it makes it easier to evolve APIs over time. Clients can still navigate the schema the way they need even if you add more fields and relations to it.

In this tutorial, I’ll show you how to use Java and Spring Boot to build a GraphQL API. I’ll also show how to test your GraphQL API using Java’s most popular testing library: JUnit 5.

Create a GraphQL API with Java and Spring Boot

Let’s start with an initialized app by going to Spring Initializr and defining your app data as follows:

  • Project: Maven Project
  • Language: Java
  • Spring Boot: 2.2.2
  • Project Metadata:
    • Group: com.oktadeveloper
    • Artifact: graphqldemo
  • Dependencies:
    • Add Spring Web
    • Add Spring Data JPA
    • Add H2 Database

You may also follow this link, it will take you to a pre-configured Spring Initializr page.

Expand the downloaded package and add GraphQL SPQR as a dependency to your pom.xml:

<dependency>
    <groupId>io.leangen.graphql</groupId>
    <artifactId>graphql-spqr-spring-boot-starter</artifactId>
    <version>0.0.4</version>
</dependency>

Then create a Food entity class:

package com.oktadeveloper.graphqldemo;

import io.leangen.graphql.annotations.GraphQLQuery;

import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Entity;

@Entity
public class Food {

    @Id @GeneratedValue
    @GraphQLQuery(name = "id", description = "A food's id")
    private Long id;

    @GraphQLQuery(name = "name", description = "A food's name")
    private String name;

    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;
    }

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

}

Notice that you are already using GraphQL SPQR (GraphQL Schema Publisher & Query Resolver, pronounced like speaker) annotations (i.e. @GraphQLQuery) on the entity. This is how it will know to expose those entities in the API.

Create the respective repository:

package com.oktadeveloper.graphqldemo;

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

@Repository
interface FoodRepository extends JpaRepository<Food, Long> {
}

In GraphQL you can either define a query which will only load data, or define a mutation which will also change the underlying data that feeds the API. For this sample app, you will define the basic read, save and delete functionality for food entities. For that, create a service class:

package com.oktadeveloper.graphqldemo;

import io.leangen.graphql.annotations.GraphQLArgument;
import io.leangen.graphql.annotations.GraphQLContext;
import io.leangen.graphql.annotations.GraphQLMutation;
import io.leangen.graphql.annotations.GraphQLQuery;
import io.leangen.graphql.spqr.spring.annotations.GraphQLApi;
import org.springframework.stereotype.Service;

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

@Service
@GraphQLApi
public class FoodService {

    private final FoodRepository foodRepository;

    public FoodService(FoodRepository foodRepository) {
        this.foodRepository = foodRepository;
    }

    @GraphQLQuery(name = "foods") // READ ALL
    public List<Food> getFoods() {
        return foodRepository.findAll();
    }

    @GraphQLQuery(name = "food") // READ BY ID
    public Optional<Food> getFoodById(@GraphQLArgument(name = "id") Long id) {
        return foodRepository.findById(id);
    }

    @GraphQLMutation(name = "saveFood") // CREATE
    public Food saveFood(@GraphQLArgument(name = "food") Food food) {
        return foodRepository.save(food);
    }

    @GraphQLMutation(name = "deleteFood") // DELETE
    public void deleteFood(@GraphQLArgument(name = "id") Long id) {
        foodRepository.deleteById(id);
    }

    @GraphQLQuery(name = "isGood") // Calculated property of Food
    public boolean isGood(@GraphQLContext Food food) {
        return !Arrays.asList("Avocado", "Spam").contains(food.getName());
    }

}

Notice that you are also able to define calculated properties to entities. In the above class, you declared the method isGood() as a property that can be queried for each food. You will see ahead that you can read it just like you read the food’s id and name fields.

To initialize the app with sample data, add an ApplicationRunner bean definition in GraphqldemoApplication:

@Bean
ApplicationRunner init(FoodService foodService) {
    return args -> {
        Stream.of("Pizza", "Spam", "Eggs", "Avocado").forEach(name -> {
            Food food = new Food();
            food.setName(name);
            foodService.saveFood(food);
        });
        foodService.getFoods().forEach(System.out::println);
    };
}

Also, add the following line to application.properties to enable the web UI to test the GraphQL API:

graphql.spqr.gui.enabled=true

Run Your Java GraphQL API

Run the project with ./mvnw spring-boot:run. Head over to http://localhost:8080/gui and you should see a web UI to test your GraphQL API. Run a sample query by typing on the left-side panel:

{
  foods {
    id
    name
    isGood
  }
}

Click the play button and you should see a result similar to this:

{
  "data": {
    "foods": [
      {
        "id": 1,
        "name": "Pizza",
        "isGood": true
      },
      {
        "id": 2,
        "name": "Spam",
        "isGood": false
      },
      {
        "id": 3,
        "name": "Eggs",
        "isGood": true
      },
      {
        "id": 4,
        "name": "Avocado",
        "isGood": false
      }
    ]
  }
}

You can also find a specific food by ID using a query like the following:

{ food(id: 1) { name } }

And seeing that result:

{
  "data": {
    "food": {
      "name": "Pizza"
    }
  }
}

Notice that you are able to manipulate the response. On that last query, you asked only for the name of the food and the API didn’t return the id nor the isGood property.

Create a new food by running the saveFood() mutation:

mutation {
  saveFood(food: { name: "Pasta" }) {
    id
    isGood
  }
}

And you will see a result like:

{
  "data": {
    "saveFood": {
      "id": 5,
      "isGood": true
    }
  }
}

If you query all the foods again you should see the newly added “Pasta” there.

Test Your Java GraphQL API with JUnit 5

You can write tests for your API with JUnit 5 and Spring Mock MVC. To do this, you can call your API via HTTP, wrap the query in a JSON object with a single property called "query", and the response should be similar to what you were seeing in the web UI. For example, the following class tests that you can retrieve all registered foods:

package com.oktadeveloper.graphqldemo;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class GraphqldemoApplicationTests {

    @Autowired
    MockMvc mockMvc;

    @Test
    void listFoods() throws Exception {
        String expectedResponse = "{\"data\":{\"foods\":[" +
                "{\"id\":1,\"name\":\"Pizza\",\"isGood\":true}," +
                "{\"id\":2,\"name\":\"Spam\",\"isGood\":false}," +
                "{\"id\":3,\"name\":\"Eggs\",\"isGood\":true}," +
                "{\"id\":4,\"name\":\"Avocado\",\"isGood\":false}" +
                "]}}";

        mockMvc.perform(MockMvcRequestBuilders.post("/graphql")
                .content("{\"query\":\"{ foods { id name isGood } }\"}")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().json(expectedResponse))
                .andReturn();
    }

}

You can replace src/test/java/com/.../GraphqldemoApplicationTests.java with the code above and run ./mvnw test to see it in action.

[INFO] Results:
[INFO] 
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

For a client to use your GraphQL API, it just needs to call it as a standard HTTP API: send a POST request with the query or mutation and parse the result as JSON.

Secure Your Java GraphQL API

So far, your API is open to whoever has its endpoint URI. Let’s change that by adding proper security.

Okta offers a very handy Maven plugin to set up your app’s security quickly and easily. First, add Okta as a dependency in pom.xml. While you’re at it, add Spring Security’s testing library.

<dependency>
    <groupId>com.okta.spring</groupId>
    <artifactId>okta-spring-boot-starter</artifactId>
    <version>1.3.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

Then run the Okta Maven plugin from your app’s folder:

./mvnw com.okta:okta-maven-plugin:setup

Answer a few questions (name, email, and company), and it will generate a new Okta account, register a new OIDC application, and add the correct properties into your application.properties file.

If you start your app again, you’ll notice that you can’t run GraphQL queries anymore. That’s because you’re not authenticated.

To authenticate and see your access token (required to use the API), create a very simple controller that displays the access token. Add the following class to your project:

package com.oktadeveloper.graphqldemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;

@RestController
class MyAccessTokenController {

    @Autowired
    private OAuth2AuthorizedClientService clientService;

    @RequestMapping("/my-access-token")
    String home(Principal user) {
        OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) user;
        String authorizedClientRegistrationId = token.getAuthorizedClientRegistrationId();
        String name = user.getName();
        OAuth2AuthorizedClient client = clientService.loadAuthorizedClient(authorizedClientRegistrationId, name);
        return "token: " + client.getAccessToken().getTokenValue();
    }

}

Start your app again and go to http://localhost:8080/my-access-token. If you are not authenticated, it will present you with a login form. After authenticating, you will see your token displayed on the web page. Copy the token value as you will use it next.

If you want to use the web UI (http://localhost:8080/gui), click on HTTP HEADERS at the bottom left and add the following, replacing <your_access_token> with the actual value of your access token that you got in the previous step:

{ "Authorization": "Bearer <your_access_token>" }

If you are calling the API directly through HTTP, simply add the Authorization header with value Bearer <your_access_token>. You can click the Copy CURL button in the top right of the web UI to see an example.

curl 'http://localhost:8080/graphql' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Connection: keep-alive' -H 'DNT: 1' -H 'Origin: http://localhost:8080' -H 'Authorization: Bearer <your_access_token>' --data-binary '{"query":"{\n  foods {\n    id\n    name\n  }\n}"}' --compressed

Or you can use HTTPie:

http POST http://localhost:8080/graphql query='{foods{id,name}}' 'Authorization: <your_access_token>'

Now you have a fully secured GraphQL API!

If you try running your tests (./mvnw test), you will notice they are failing because the API will now answer with 403 Forbidden instead of 200 OK:

$ ./mvnw test
...
[INFO] Results:
[INFO]
[ERROR] Failures:
[ERROR]   GraphqldemoApplicationTests.listFoods:34 Status expected:<200> but was:<403>
[INFO]
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
...

That happens because your tests are not security-aware. To fix that, you need to add the method call .with(SecurityMockMvcRequestPostProcessors.jwt()) to each of your mockMvc.perform() chains, for example:

mockMvc.perform(MockMvcRequestBuilders.post("/graphql")
        .with(SecurityMockMvcRequestPostProcessors.jwt()) // <- ADD THIS LINE
        .content("{\"query\":\"{ foods { id name isGood } }\"}")
        .contentType(MediaType.APPLICATION_JSON)
        .accept(MediaType.APPLICATION_JSON))
        .andExpect(status().isOk())
        .andExpect(content().json(expectedResponse))
        .andReturn();

Both MockMvcRequestBuilders.post() and SecurityMockMvcRequestPostProcessors.jwt() can be static imports, so you can make this code a bit easier to read. Add the imports:

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;

Then remove the class names from the test:

mockMvc.perform(post("/graphql")
        .with(jwt())
        ...

The jwt() method instructs the test to inject a JWT authentication and act accordingly as if a user is authenticated.

Below is a full test class that verifies the GraphQL API you wrote works as expected::

package com.oktadeveloper.graphqldemo;

import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class GraphqldemoApplicationTests {

    @Autowired
    MockMvc mockMvc;

    @Test
    @Order(0)
    void listFoods() throws Exception {

        String expectedResponse = "{\"data\":{\"foods\":[" +
                "{\"id\":1,\"name\":\"Pizza\",\"isGood\":true}," +
                "{\"id\":2,\"name\":\"Spam\",\"isGood\":false}," +
                "{\"id\":3,\"name\":\"Eggs\",\"isGood\":true}," +
                "{\"id\":4,\"name\":\"Avocado\",\"isGood\":false}" +
                "]}}";

        mockMvc.perform(post("/graphql")
                .with(jwt())
                .content("{\"query\":\"{ foods { id name isGood } }\"}")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().json(expectedResponse))
                .andReturn();
    }

    @Test
    @Order(1)
    void addAndRemoveFood() throws Exception {
        String expectedResponseBefore = "{\"data\":{\"foods\":[" +
                "{\"id\":1,\"name\":\"Pizza\"}," +
                "{\"id\":2,\"name\":\"Spam\"}," +
                "{\"id\":3,\"name\":\"Eggs\"}," +
                "{\"id\":4,\"name\":\"Avocado\"}" +
                "]}}";
        String expectedResponseAfter = "{\"data\":{\"foods\":[" +
                "{\"id\":1,\"name\":\"Pizza\"}," +
                "{\"id\":2,\"name\":\"Spam\"}," +
                "{\"id\":3,\"name\":\"Eggs\"}," +
                "{\"id\":4,\"name\":\"Avocado\"}," +
                "{\"id\":5,\"name\":\"Pasta\"}" +
                "]}}";

        // List foods, expect 'New Food' to not be there
        mockMvc.perform(post("/graphql")
                .with(jwt())
                .content("{\"query\":\"{ foods { id name } }\"}")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().json(expectedResponseBefore))
                .andReturn();

        // Add 'New Food'
        mockMvc.perform(post("/graphql")
                .with(jwt())
                .content("{\"query\":\"mutation { saveFood(food: { name: \\\"Pasta\\\" }) { id name } }\"}")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().json("{\"data\":{\"saveFood\":{\"id\":5,\"name\":\"Pasta\"}}}"))
                .andReturn();

        // List foods, expect 'New Food' to be there
        mockMvc.perform(post("/graphql")
                .with(jwt())
                .content("{\"query\":\"{ foods { id name } }\"}")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().json(expectedResponseAfter))
                .andReturn();

        // Remove 'New Food'
        mockMvc.perform(post("/graphql")
                .with(jwt())
                .content("{\"query\":\"mutation { deleteFood(id: 5) }\"}")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andReturn();

        // List foods, expect 'New Food' to not be there
        mockMvc.perform(post("/graphql")
                .with(jwt())
                .content("{\"query\":\"{ foods { id name } }\"}")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().json(expectedResponseBefore))
                .andReturn();
    }

}

Spring Boot Tutorials - Spring Boot Full Course

Spring Boot Tutorials - Spring Boot Full Course

Spring Boot Tutorials | Full Course - What is Spring? Spring Boot is an open source Java-based framework used to create a Micro Service. Spring Boot contains a comprehensive infrastructure support for developing a micro service and enables you to develop enterprise-ready applications that you can “just run”.

  1. What is Spring ? – 00:05
  2. Dependency Injection? – 05:34
  3. Spring Tool Suite | Spring Boot IDE – 13:40
  4. Spring, Autowire, Dependency Injection – 22:17
  5. Web App using Spring Boot – 40:39
  6. Application Properties File – 55:33
  7. Accepting Client Data – 01:00:11
  8. ModelAndView – 01:08:51
  9. Model Object – 01:16:12
  10. JPA | MVC | H2 Example – 01:20:29
  11. JPA | MVC | H2 Example Part 2 – 01:35:29
  12. Data JPA | MVC | H2 | Query Methods Example – 01:45:12
  13. Data JPA | MVC | H2 | REST Example – 01:54:43
  14. Data JPA | MVC | H2 | REST Example – 02:02:22
  15. Postman | Data JPA | MVC | H2 | REST Example – 02:06:55
  16. Content Negotiation | Data JPA | MVC | H2 | REST – 02:11:29
  17. Spring Boot | MVC | REST Post Example – 2:19:36
  18. Spring Boot | MVC | REST PUT DELETE Example – 02:27:35
  19. Spring Boot Data REST Example – 02:36:30

Spring Boot Tutorials | Full Course:- https://github.com/navinreddy20/Spring-Boot

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