【问题标题】:How to execute Java calls to GraphQL in a Spring Boot + GraphQL Java Tools' context?如何在 Spring Boot + GraphQL Java 工具的上下文中执行对 GraphQL 的 Java 调用?
【发布时间】:2020-01-30 23:46:32
【问题描述】:

在 Spring Boot 应用程序中,我们已经拥有一个功能齐全的 GraphQL 端点,通过 GraphQL Java 工具提供.graphqls 文件(我们包含了graphql-spring-boot-starter 依赖项)并通过我们的基础Query 类处理数据解析实现GraphQLQueryResolver 和后续的GraphQLResolver

出于业务需求,我们必须重新创建标准 REST API 端点,所以我想知道为什么不直接调用 GraphQL(而不必再次“手动”重新实现数据解析)? 由于它在同一个后端应用程序中,无需进行 HTTP 或 servlet (ForwardRequest) 调用,只需调用 Java 中的一些 API。 问题是我不知道该怎么做。

我阅读了这个示例,但它使用的是基本的 GraphQL Java(不是工具): https://www.graphql-java.com/documentation/v9/execution/

我知道这应该是可能的,因为我们可以在测试中这样做: https://github.com/graphql-java-kickstart/graphql-spring-boot/blob/master/example-graphql-tools/src/test/java/com/graphql/sample/boot/GraphQLToolsSampleApplicationTest.java

但是如何在常规代码中做到这一点?没有GraphQLTemplate 这样的东西。

我还尝试在以下位置搜索示例:

但没有找到与我们的需求相关的内容。

在文档中找不到更多内容:

我错过了什么?理想情况下,我希望像这样注入一些GraphQLSomething

@RestController
@RequestMapping(path = "api")
public class CompanyController {

    @Autowired
    private GraphQLSomething graphQLSomething;

    @GetMapping("company/{id}")
    public ResponseEntity<?> societe(@PathVariable @NotNull Integer id) {
        GraphQLSomethingResult result = GraphQLSomething.query("company(id: $id) { id name andsoone }", "{ \"id\": 123456 }").execute(); // not really sure of the GraphQL syntax here, but it'll need some tests...
        return result.getDataOrElse();
    }

}

【问题讨论】:

    标签: java spring-boot graphql graphql-java graphql-java-tools


    【解决方案1】:

    终于找到了我想做的事情:

    import java.util.Map;
    import java.util.Optional;
    
    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Positive;
    
    import org.springframework.beans.factory.annotation.Autowired;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.google.common.collect.ImmutableMap;
    
    import graphql.ExecutionResult;
    import graphql.servlet.core.GraphQLQueryInvoker;
    import graphql.servlet.core.internal.GraphQLRequest;
    import graphql.servlet.input.GraphQLInvocationInputFactory;
    import graphql.servlet.input.GraphQLSingleInvocationInput;
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    @Validated
    @RestController
    @RequestMapping(path = "api")
    public class CompanyController {
    
        @Autowired
        private GraphQLInvocationInputFactory invocationInputFactory;
    
        @Autowired
        private GraphQLQueryInvoker queryInvoker;
    
        @GetMapping("company/{id}")
        public ResponseEntity<?> societe(@PathVariable @NotNull Integer id) {
            String query = "query ($id: Int!) { company(id: $id) { id name andsoon } }";
            /*
             * ImmutableMap is a Guava class; you can build the map (e.g. a HashMap) on your
             * own, or simply Map.to(..) in Java 9, or even @PathVariable Map<String,
             * Object> variables as the method's parameter instead (but you'll miss the
             * validation).
             */
            Map<String, Object> variables = ImmutableMap.of("id", id);
    
            GraphQLRequest request = new GraphQLRequest(query, variables, null);
            GraphQLSingleInvocationInput invocationInput = invocationInputFactory.create(request);
            ExecutionResult result = queryInvoker.query(invocationInput);
    
            /*
             * Of course result.getData() can be null here - see also result.isDataPresent()
             * - but data/error handling's left to you
             */
            Optional<Object> company = Optional.ofNullable(result.getData().get("company"));
            return ResponseEntity.of(company);
        }
    
    }
    

    【讨论】:

    • 您能否提供为上述解决方案添加的所有依赖项?
    • 添加了缺失的导入
    • 注入GraphQLInvocationInputFactory时出现org.springframework.beans.factory.BeanCurrentlyInCreationException
    • 如果你在 graphl 解析器中使用它,GraphQLInvocationInputFactory 必须使用@Lazy。
    • 事实上,我并没有在 GraphQL 解析器中使用它,因为那不是目的(这违背了 GraphQL 的目的)......也许可以检查我的另一个问题:stackoverflow.com/questions/64041119/…跨度>
    【解决方案2】:

    仅供参考,要获取上述代码的依赖项,您需要:

        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-spring-boot-autoconfigure</artifactId>
            <version>5.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java-servlet</artifactId>
            <version>6.1.3</version>
        </dependency>
    

    【讨论】:

    • 我在原帖里说过:we included the graphql-spring-boot-starter dependency
    • 我试图完整地记录依赖关系。
    猜你喜欢
    • 2020-05-16
    • 2019-12-16
    • 2017-10-31
    • 2019-05-15
    • 2018-08-06
    • 2021-06-01
    • 2018-09-04
    • 2021-05-13
    • 2020-11-25
    相关资源
    最近更新 更多