Study/Java

Spring Boot GraphQL 사용해보기

Bluesky_ 2022. 9. 2. 04:34
반응형

GraphQL 소개

GraphQL은 페이스북에서 만든 API를 위한 쿼리 언어이다.

SQL과 유사하게 사용하는 웹 요청용 쿼리를 정의한 규약이고 많이 사용하는 REST API와 다른 형식의 요청이라고 생각하면 된다.

REST API의 경우 요청 주소에 따라 응답 결과를 얻게 되지만 GraphQL은 단일 요청 주소로 질의한 쿼리 별 대한 응답 결과를 얻는 차이가 있다.

GraphQL 홈페이지

GraphQL for Java/Kotlin

GraphQL은 다양한 언어에 대한 라이브러리를 제공하고 있다.

Code using GraphQL

이 중 Java에서 사용하기 위한 라이브러리 항목은 다음을 참고한다.

Code using GraphQL Java/Kotlin

Spring for GraphQL

이 중 graphql-java에서 spring에서 사용하기 위해 제공하던 graphql-java-spring 라이브러리가 spring project로 이전되어 spring-graphql로 변경되었다.

graphql-java-spring

spring-graphql

이 라이브러리를 기반으로 Spring Boot 2.7.0부터 graphql에 대한 autoconfigure를 제공하기 시작하였고 이제 spring-boot-starter-graphql을 사용하면 된다.
(이전에 별도 라이브러리를 선택하여 사용하던 경우 이제 Spring이 graphql-java를 기반으로 제공하기 시작하였으므로 변경을 고려하면 될 것 같다.)

Spring for GraphQL

dependency 설정

Spring Boot에서 사용하려면 다음과 같이 설정한다.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-graphql</artifactId>
</dependency>

Spring Boot를 사용하면 위 starter 참조 시 GraphQL 사용이 기본 활성화된다.

properties 설정

GraphQL 관련하여 Spring Boot는 2개의 properties를 설정할 수 있게 제공한다.

  • GraphQlProperties
  • GraphQlCorsProperties

GraphQlProperties에서는 기본적인 graphql 사용 설정을 한다.

default 설정은 다음과 같다.

spring.graphql.path=/graphql
spring.graphql.graphiql.path=/graphiql
spring.graphql.graphiql.enabled=false
spring.graphql.schema.locations=classpath:graphql/**/
spring.graphql.schema.file-extensions=.graphqls,.gqls
spring.graphql.schema.introspection.enabled=true
spring.graphql.schema.printer.enabled=false
spring.graphql.websocket.connection-init-timeout=60s
spring.graphql.websocket.path=
spring.graphql.rsocket.mapping=

GraphQlCorsProperties에서 Cors 관련 설정을 한다.

default 설정은 다음과 같다.

spring.graphql.cors.allow-credentials=
spring.graphql.cors.allowed-headers=
spring.graphql.cors.allowed-methods=
spring.graphql.cors.allowed-origin-patterns
spring.graphql.cors.allowed-origins=
spring.graphql.cors.exposed-headers=
spring.graphql.cors.max-age=1800s

만약 기존 web 관련 cors 설정과 연동하고자 원한다면 따로 처리를 해야 할 것 같다.

여기까지 설정을 하면 이제 사용할 수 있게 된다.

개발 중엔 위에 열거한 설정 중 아래 두 가지 설정을 활성화하는 걸 추천한다.

spring.graphql.graphiql.enabled=true
spring.graphql.schema.printer.enabled=true

graphiql 활성화하기

graphiql은 GraphQL을 사용하면서 만들어야 할 query를 쉽게 만들어서 테스트할 수 있는 편집기이다.

graphiql github

graphql

해당 편집기를 통해 GraphQL query를 편하게 작성해서 사용할 수 있다.

graphiql live demo

test

spring-boot-starter-graphql를 사용하는 경우 spring.graphql.graphiql.enabled=true 설정을 하면 /graphiql 주소가 활성화되어 graphiql 편집기를 사용할 수 있게 된다.

schema 활성화하기

작성한 GraphQL schema를 호출을 통해 확인할 수 있다.

schema를 단일 파일로 관리하지 않는 경우 전체 schema 확인 시 유용하다.

spring.graphql.schema.printer.enabled=true 설정을 하면 /graphql/schema 주소가 활성화되어 schema를 확인할 수 있다.

사용해보기

REST API와 차이점

rest API의 경우 해당 resource에 대해 주소가 정해져 있고 GET, POST, PUT, DELETE와 같이 호출하여 해당 resource에 대한 CRUD 처리를 한다.

GraphQL의 경우 고정된 주소에 POST 호출로 쿼리를 사용한다.

spring-boot-starter-graphql 을 사용하는 경우 기본 설정된 주소는 /graphql 이다.

이 주소에 POST 요청을 하며 R (Read) 요청의 경우 Query 로 요청을 하고 그 외의 CUD (Create, Update, Delete) 요청의 경우 Mutation으로 요청을 한다.

대략 아래와 같은 형태로 요청한다.

// Query 요청의 경우
fetch("/graphql", {
    "method": "POST",
    "headers": {
        "Content-Type": "application/json"
    },
    body : JSON.stringify({ query : "{ userBlogList { blogId, userId } }" })
})
.then(response => response.json());

// Mutation 요청의 경우
fetch("/graphql", {
    "method": "POST",
    "headers": {
        "Content-Type": "application/json"
    },
    body : JSON.stringify({ query : "mutation { createBlog { blogId, userId } }" })
})
.then(response => response.json());

GraphQL을 사용하려면 위 요청을 받아 처리할 수 있도록 아래 두 가지 사항에 대한 처리를 해야 한다.

  1. Controller 설정
  2. Schema 설정

REST API는 Controller만 설정하면 되지만 GraphQL을 요청을 쿼리로 하기 때문에 쿼리에 대한 Schema 설정이 추가로 더 필요하다.

@SchemaMapping, @QueryMapping, @MutationMapping 설정하기

@SchemaMapping, @QueryMapping, @MutationMapping 은 Controller에서 graphql을 사용하기 위해 사용하는 annotation이다.

대략 다음과 같이 사용한다.

@Controller
public class TestController {

    private String testAString = "testAString";

    @QueryMapping
    public String testA() {
        return testAString;
    }

    @MutationMapping
    public String testAUpdate(@Argument String changeValue) {
        testAString = changeValue;
        return testAString;
    }
}

@QueryMapping@MutationMapping@SchemaMapping을 축약해서 사용하기 위해 제공되는 anntation으로 풀어쓰면 다음과 같다.

// 이 annotation은
@QueryMapping
public String someMethod() {
    return "TEST";
}

// 이 annotaton을 쓴 것과 같음
@SchemaMapping(typeName = "Query")
public String someMethod() {
    return "TEST";
}

@MutationMapping
public String someMethodUpdate(@Argument String changeValue) {
    targetString = changeValue
    return targetString;
}

@SchemaMapping(typeName = "Mutation")
public String someMethodUpdate(@Argument String changeValue) {
    targetString = changeValue
    return targetString;
}

기존 REST API의 Controller 설정에선 @RequestMapping, @GetMapping, @PostMapping annotation을 사용하였는데 그에 상응하는 annotation들이라고 생각하면 될 것 같다.

Schema 설정하기

GraphQL을 사용하려면 위에 설정한 Controller의 ScheamMapping에 대해 Schema를 설정해야 한다.

spring-boot-starter-graphql를 사용하는 경우 default로 설정된 Schema 파일 위치는 classpath:graphql/**/ 으로 /src/main/resources/graphql/ 위치에 자유로운 이름으로 *.graphqls 또는 *.gqls 파일을 만들면 된다.

위 controller의 testA 호출의 경우 대략 다음과 같은 Schema를 설정하면 된다.

type Query {
    testA: String
}

호출해보기

위에 만들어진 testA를 호출하려면 다음과 같이 하면 된다.

javascript fetch 호출의 예인데 graphiql 을 사용하면 좀더 편하게 호출해볼 수 있다.

fetch("/graphql", {
    "method": "POST",
    "headers": {
        "Content-Type": "application/json"
    },
    body : JSON.stringify({ query : "{ testA }" })
})
.then(response => response.json());

Object에 대해 호출해보기

여기까지 따라 해 보았다면 기본적인 controller생성과 schema 설정, 그리고 호출하는 것까지 해본 것이다.

단순한 문자열 반환의 경우 이렇게 단순하지만 만약 Object를 반환하는 경우나 매개변수가 있는 경우라면 schema의 설정이 좀 더 복잡해진다.

예를 들면 다음가 같다.

type Query {
    getAObject(id: ID): AObject
}

type AObject {
    id: ID
    name: String
    description: String!
    amount: Int
}

위와 같이 schema가 정의되어 있으면 아래와 같이 호출한다.

fetch("/graphql", {
    "method": "POST",
    "headers": {
        "Content-Type": "application/json"
    },
    body : JSON.stringify({ query : "{ getAObject(123) { id, name } }" })
})
.then(response => response.json());

호출할 대상에 대해 argument와 응답할 Object의 field를 지정하고 있다.

마무리

대략적으로 GraphQL을 사용을 해보았다.

기존 사용하던 REST API와 비교해서 어떤 게 더 좋은지 판단하는 것은 각 사용자의 몫일 것 같다.

굳이 한쪽만 사용할 필요 없이 원하는 곳에 REST API / GraphQL을 병행 사용하면 되지 않을까 싶다.

반응형