spring boot Graphql CustomContext 생성하기
- Projects
- 2021년 4월 7일
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스럽지도 못하기 때문에 썩 그렇게 좋은 코드는 아니고 예시로만 봐주면 될 것 같다.