GraphQlErrorConfig.java

package io.slayyyyer.orders.graphql;

import graphql.ErrorType;
import graphql.GraphQLError;
import graphql.GraphqlErrorBuilder;
import graphql.schema.DataFetchingEnvironment;
import io.slayyyyer.orders.service.ConflictException;
import io.slayyyyer.orders.service.NotFoundException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.graphql.execution.DataFetcherExceptionResolver;
import org.springframework.graphql.execution.DataFetcherExceptionResolverAdapter;

/**
 * GraphQL and REST share the same domain exceptions but not the same error shape: GraphQL
 * gets typed errors with a classification, REST gets problem details. Keeping the mapping
 * explicit stops one transport's conventions leaking into the other.
 */
@Configuration
public class GraphQlErrorConfig {

    @Bean
    public DataFetcherExceptionResolver domainExceptionResolver() {
        return new DataFetcherExceptionResolverAdapter() {
            @Override
            protected GraphQLError resolveToSingleError(Throwable ex, DataFetchingEnvironment env) {
                if (ex instanceof NotFoundException notFound) {
                    return error(env, notFound.getMessage(), ErrorType.DataFetchingException)
                            .extensions(java.util.Map.of(
                                    "code", "NOT_FOUND",
                                    "resource", notFound.resource(),
                                    "id", notFound.id()))
                            .build();
                }
                if (ex instanceof ConflictException conflict) {
                    return error(env, conflict.getMessage(), ErrorType.ExecutionAborted)
                            .extensions(java.util.Map.of("code", "CONFLICT"))
                            .build();
                }
                if (ex instanceof IllegalArgumentException invalid) {
                    return error(env, invalid.getMessage(), ErrorType.ValidationError)
                            .extensions(java.util.Map.of("code", "INVALID_REQUEST"))
                            .build();
                }
                return null;
            }
        };
    }

    private static GraphqlErrorBuilder<?> error(
            DataFetchingEnvironment env, String message, ErrorType type) {
        return GraphqlErrorBuilder.newError(env)
                .message(message)
                .errorType(type);
    }
}