Правильный способ возврата ошибок в GraphQL-SPQR

На данный момент я бросаю RuntimeException, чтобы вернуть ошибки проверки GraphQL. Он работает на удивление хорошо, за исключением того, что он выдает ужасные ошибки с большими трассировками стека в моих журналах.

Здесь вы можете видеть, что я проверяю отправленную новую мутацию регистрации пользователя, чтобы убедиться, что пароли совпадают, а адрес электронной почты еще не используется.

Как правильно сделать это в GraphQL SPQR Spring Boot Starter.

@GraphQLMutation (name="register")
public User register(@GraphQLArgument(name="firstname") String firstname, @GraphQLArgument(name="lastname") String lastname, @GraphQLArgument(name="email") String email, @GraphQLArgument(name="msisdn") String msisdn, @GraphQLArgument(name="password") String password, @GraphQLArgument (name="confirmPassword") String confirmPassword) {
    if (userRepo.findByEmail(email) != null) {
        throw new RuntimeException("User already exists");
    }

    if (!password.equals(confirmPassword)) {
        throw new RuntimeException("Passwords do not match");
    }

    User newUser = new User();
    //...
    return userRepo.save(newUser);
}

person sparkyspider    schedule 26.07.2019    source источник
comment
Я не знаю, есть ли обычный способ делегировать проверку с помощью аннотаций или чего-то подобного, но для проверки ввода я бы выбрал IllegalArgumentException вместо RuntimeException, вы также можете использовать предварительные условия Google для этих проверок   -  person Elgayed    schedule 26.07.2019
comment
Вы хотите уменьшить размер трассировки стека? Это то, что вы планировали. Если да, вы можете переопределить DataFetcherExceptionHandler и создать собственный обработчик и подключиться к GraphQL.   -  person user06062019    schedule 26.07.2019


Ответы (1)


Мне неясно, о чем вы спрашиваете ... но я предполагаю, что вы хотите настроить, что регистрируется.

Для начала я бы предложил специальный тип исключения, например ValidationException, который вы можете перехватывать и обрабатывать по-разному.

Что касается ведения журнала, это, вероятно, происходит в grapqh-java, поскольку SPQR сам по себе ничего не регистрирует. По умолчанию graphql-java использует SimpleDataFetcherExceptionHandler который регистрирует исключения, обнаруженные во время разрешения поля.

Теперь у вас есть несколько вариантов: вы можете зарегистрировать ResolverInterceptor в SPQR, который улавливает исключения проверки и регистрирует то, что вы хотите, и возвращает DataFetcherResult с сообщением об ошибке для пользователя. Поскольку исключения проверки не всплывают до graphql-java, DataFetcherExceptionHandler в этом сценарии делать нечего.

Это выглядело бы примерно так:

public class ValidationInterceptor implements ResolverInterceptor {

    @Override
    public Object aroundInvoke(InvocationContext context, Continuation continuation) throws Exception {
        try {
            return continuation.proceed(context);
        } catch (ValidationException e) {
            log.warning(e);
            return DataFetcherResult.newResult()
                    .error(GraphqlErrorBuilder
                            .newError(context.getResolutionEnvironment().dataFetchingEnvironment)
                            .message(e.getMessage()) //the message for the user
                            .build());
        }
    }
}

См. ответ здесь для получения инструкций по регистрации пользовательского перехватчика. с помощью Spring Boot.

Другой вариант - заменить DataFetcherExceptionHandler graphql-java. Для этого вы должны сами построить GraphQL объект и зарегистрировать его как bean-компонент.

@Bean
public GraphQL graphQL(GraphQLSchema schema) {
    GraphQL.Builder builder = GraphQL.newGraphQL(schema)
            .queryExecutionStrategy(new AsyncExecutionStrategy(customExceptionHandler))
            .mutationExecutionStrategy(new AsyncSerialExecutionStrategy(customExceptionHandler));
    return builder.build();
}

Я также не удивлюсь, если где-нибудь есть функция Spring, которую можно использовать для обработки исключений в управляемых bean-компонентах.

person kaqqao    schedule 31.07.2019
comment
В моем перехватчике преобразователя я вместо этого получаю исключение InvocationTargetException, которое обертывает исключение, которое я хочу перехватить, что дает? - person William; 02.11.2019
comment
@Unidan Это нормально для исключений во время рефлексивного вызова, но SPQR должен их разворачивать. На какой у вас версии? - person kaqqao; 02.11.2019
comment
Я на 0.10.0. Перехватчик FWIW находится в Kotlin, но все преобразователи и их базовые модели данных находятся на Java. - person William; 03.11.2019
comment
@Unidan Боюсь, что это ошибка (только что проверил сам). Исправлю в следующем выпуске. - person kaqqao; 03.11.2019
comment
Хорошо, спасибо за быстрый ответ. Абсолютно люблю библиотеку, даже если документации почти нет: D! - person William; 03.11.2019
comment
Если вы используете Spring AOP для TransactionManagement, вы можете не получить ValidationException, но InvocationTargetException, поскольку исключение не разворачивается с помощью graphql-spqr - person Janning; 17.03.2020