spring boot Graphql CustomContext 생성하기

GraphQL의 요청을 핸들링하는 GraphQLServletContextBuilder를 implements하여 grpahQL요청에 대해 커스텀Context를 반환하도록 만들 수 있다.

예를들어 요청의 헤더에 접근하여 Context에 특정 헤더값을 저장하는 식으로의 custom이 가능하다. 이번 예시에서는 헤더에 api-key가 포함되어있고 이 key를 분리하여 context도 저장하고있는 context를 만들어보려고 한다.


1. CustomContext 정의

GraphQLServletContext를 implements하여 총6개의 메서드들을 정의해주면 된다.

@Getter
@RequiredArgsConstructor
public class CustomGraphQLContext implements GraphQLServletContext {

    private final String apiKey;
    private final GraphQLServletContext context;

    @Override
    public List<Part> getFileParts() {
        return context.getFileParts();
    }

    @Override
    public Map<String, List<Part>> getParts() {
        return context.getParts();
    }

    @Override
    public HttpServletRequest getHttpServletRequest() {
        return context.getHttpServletRequest();
    }

    @Override
    public HttpServletResponse getHttpServletResponse() {
        return context.getHttpServletResponse();
    }

    @Override
    public Optional<Subject> getSubject() {
        return context.getSubject();
    }

    @Override
    public DataLoaderRegistry getDataLoaderRegistry() {
        return context.getDataLoaderRegistry();
    }
}

기본적인 ServletContext의 정보를 갖고있을 context 변수와 예시로 헤더값에 포함된 api-key를 저장할 필드를 포함한 커스텀context를 정의 해주면 된다.


2. GraphQLServeltContextBuilder

실제로 GraphQLServletContext를 생성하는 Builder도 구현해주어야 우리가 생성한 CustomContext로 Context가 생성이 된다.

@Component
@RequiredArgsConstructor
public class CustomGraphQLContextBuilder implements GraphQLServletContextBuilder {

    @Override
    public GraphQLContext build(HttpServletRequest httpServletRequest,
                                HttpServletResponse httpServletResponse) {

        String apiKey = httpServletRequest.getHeader("api-key");

        DefaultGraphQLServeltContext context = DefaultGraphQLServletContext.createServletContext()
                .with(httpServletRequest)
                .with(httpServletResponse)
                .build();

        return new CustomGraphQLContext(apiKey, context);
    }

    @Override
    public GraphQLContext build(Session session, HandshakeRequest handshakeRequest) {
        throw new IllegalStateException("Unsupported");
    }

    @Override
    public GraphQLContext build() {
        throw new IllegalStateException("Unsupported");
    }
}

build() 메서드 3개를 Override해 정의 해주어야 하는데, session방식은 사용하지 않기 때문에 Exception처리 해주었고 build의 매개변수인 httpServletRequest의 getHeader를 통해 api-key의 값을 꺼내고 만들어둔 CustomGraphQLContext에 apiKey를 포함하여 return하면 실제 QueryResolver를 처리하는 Context는 우리가 만든 CustomContext가 처리하게 된다.

그래서 이전에 설명한 Environment의 getContext() 메서드를 통해서 특정 필드에 접근도 가능하다.

@Component
@Slf4j
public class WetayoQuery implements GraphQLQueryResolver {
    //... 각종 Service들과 Constructor

    public List<RouteStationGraphQLDto> getStations(Double x, Double y, Double distance, DataFetchingEnvironment e) {
        CustomGraphQLContext context = e.getContext();
        log.info(context.getApiKey());  //헤더의 api-key  값 출력

        if(!context.getApiKey().equals("123456789")) throw new UnAuthorizedAccessExeption("유효하지 않은 api key");

        //비즈니스 로직

        return routeStationDtos;
    }
}

위와 같이 Controller의 메서드에서 context의 필드에도 접근,조회가 가능하게 된다. 하지만 위의 방법은 단일 책임 원칙에 위배되고 AOP스럽지도 못하기 때문에 썩 그렇게 좋은 코드는 아니고 예시로만 봐주면 될 것 같다.

Related Posts

표준 입출력

표준 입출력

GoLang의 표준 입출력은 다른 언어와 같이 터미널이 기본이며, 파일등으로 수정이 가능하고 fmt패키지에서 제공을 한다. 입출력은 BitStream형태로 되어있다. 1. 표준 출력 1) 함수 함수 기능 Print() 입력값들을 출력 Println() 마지막에 개행문자를 포함한 입력값들을 출력 Printf() c의 printf와 같이 특정 포맷에 맞게 출력 2) 포맷 서식 포맷형태 설명 %d 정...

Read More
인터페이스

인터페이스

  • Java
  • 2021년 12월 8일

1. 인터페이스란? 자바의 다형성을 극대화하여 개발코드 수정을 줄이고 유지보수를 용이하게 하기 위함 다형성? 동일한 메시지를 수신했을 때 객체의 타입에 따라 다르게 응답할 수 있는 능력 1) 추상클래스와 인터페이스 차이 추상메서드를 가짐으로써 다형성을 극대화하면서 어떤 역할을 구현하는 방법(객체들이 따라야 하는 책임의 집합을 서술한 것)이라는 공통...

Read More
Graph

Graph

연결되어 있는 객체 간의 관계를 표현할 수 있는 자료구조로 Tree도 그래프의 일종인데 그래프 중에서도 사이클이 허용되지 않는 그래프이다. 1. 개념 정점(vertex) / 노드(node) : 위치 간선(edge) / 링크(link) : 위치간의 관계 인접 정점 : 간선에 의해 직접 연결된 노드 차수 : 하나의 노드에 인접한 노드의 수 경로 길이 : 경로를...

Read More