spring-projects / spring-graphql

Spring Integration for GraphQL
https://spring.io/projects/spring-graphql
Apache License 2.0
1.5k stars 297 forks source link

Support fragments in GraphQlTester #964

Closed wickstopher closed 1 month ago

wickstopher commented 2 months ago

I am in the process of converting a codebase from the old GraphQL Java Kickstart library over to spring-graphql.

The test template in the testing framework for that library included a parameter that allowed you to optionally pass in fragment resource paths.

It would be helpful in the maintenance of test requests to support the loading of GraphQL fragments from disk. Currently, as far as I can tell fragments are only supported in the document method, which requires you to juxtapose your fragment with your query in a single string.

Being able to write something along the following lines:

graphQlTester
  .documentName("graphQLDocument")
  .withFragmentNames("fragmentOne", "fragmentTwo")
  .execute()

would be much nicer than having to repeat boilerplate in your test requests.

bclozel commented 2 months ago

Duplicates #923 Please comment on that other issue to provide more feedback and ideas. Thanks!

rstoyanchev commented 2 months ago

The #import syntax suggested in #923 is a much broader feature as it tends to be used in schema files too. We don't necessarily need to go there to support reusable fragments, which is a much more specific goal that makes sense to support.

As mentioned in https://github.com/spring-projects/spring-graphql/issues/923#issuecomment-2014665969, we could also expose fragmentName and fragment methods on GraphQlTester, and is also what is suggested here, so let's use this issue to track the request.

It makes sense to have equivalent methods on GraphQlClient too.

rstoyanchev commented 2 months ago

In the meantime, since "documentName" handling can be customized, you could support a name like "myDocument::myFragment1::myFragment2". I haven't tested this, but a custom DocumentSource to support that could look like this:

public class ConcatenatingDocumentSource implements DocumentSource {

    private final DocumentSource delegate = new ResourceDocumentSource(
            List.of(new ClassPathResource("graphql-test/")), List.of(".graphql"));

    @Override
    public Mono<String> getDocument(String name) {
        return name.contains("::") ?
                Flux.fromArray(name.split("::")).flatMap(this.delegate::getDocument).reduce((s, s2) -> s + s2) :
                this.delegate.getDocument(name);
    }

}

You plug that in via GraphQlTester.Builder#documentSource . The delegate is what is used by default. In the custom implementation we are simply using it to load multiple documents and join them.

wickstopher commented 2 months ago

Thanks, this workaround is exactly what I needed to move forward without having to abandon fragment utilization in my test cases. Much appreciated!