Git Product home page Git Product logo

micronaut-graphql's Introduction

Micronaut GraphQL

Maven Central Build Status Revved up by Develocity

This project includes integration between Micronaut and GraphQL Java.

The Micronaut GraphQL integration can be used together with other GraphQL integration libraries like GraphQL Java Tools and GraphQL SPQR.

Documentation

See the Documentation for more information.

See the Snapshot Documentation for the current development docs.

Examples

Examples can be found in the examples directory.

Snapshots and Releases

Snaphots are automatically published to Sonatype Snapshots using Github Actions.

See the documentation in the Micronaut Docs for how to configure your build to use snapshots.

Releases are published to Maven Central via Github Actions.

Releases are completely automated. To perform a release use the following steps:

micronaut-graphql's People

Contributors

alextu avatar alvarosanchez avatar auke- avatar benmccann avatar dependabot-preview[bot] avatar dependabot[bot] avatar donbeave avatar gklijs avatar goodforgod avatar graemerocher avatar guillermocalvo avatar ilopmar avatar jameskleeh avatar jeremyg484 avatar marceloverdijk avatar micronaut-build avatar msupic avatar n0tl3ss avatar renovate[bot] avatar sdelamo avatar timyates avatar weisheme avatar wetted avatar yawkat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

micronaut-graphql's Issues

GraphiQL doesn't work with Mirconaut 2.0.0-M3

When visiting http://localhost:8080/graphiql in my project I get the error below

14:36:34.592 [nioEventLoopGroup-1-2] ERROR i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred: io.micronaut.context.env.DefaultPropertyPlaceholderResolver.(Lio/micronaut/core/value/PropertyResolver;)V
java.lang.NoSuchMethodError: io.micronaut.context.env.DefaultPropertyPlaceholderResolver.(Lio/micronaut/core/value/PropertyResolver;)V
at io.micronaut.configuration.graphql.GraphiQLController.replaceParameters(GraphiQLController.java:123)
at io.micronaut.configuration.graphql.GraphiQLController.resolvedTemplate(GraphiQLController.java:116)
at io.micronaut.core.async.SupplierUtil$1.initialize(SupplierUtil.java:47)
at io.micronaut.core.async.SupplierUtil$1.get(SupplierUtil.java:42)
at io.micronaut.configuration.graphql.GraphiQLController.get(GraphiQLController.java:88)
at io.micronaut.configuration.graphql.$GraphiQLControllerDefinition$$exec1.invokeInternal(Unknown Source)
at io.micronaut.context.AbstractExecutableMethod.invoke(AbstractExecutableMethod.java:146)
at io.micronaut.context.DefaultBeanContext$4.invoke(DefaultBeanContext.java:457)
at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:255)
at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:117)
at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildResultEmitter$11(RoutingInBoundHandler.java:1322)
at io.reactivex.internal.operators.flowable.FlowableDefer.subscribeActual(FlowableDefer.java:35)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14868)
at io.micronaut.tracing.instrument.util.TracingPublisher.subscribe(TracingPublisher.java:120)
at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:52)
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:68)
at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:52)
at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14868)
at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildExecutableRoute$5(RoutingInBoundHandler.java:1026)
at io.micronaut.web.router.DefaultUriRouteMatch$1.execute(DefaultUriRouteMatch.java:81)
at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:117)
at io.micronaut.http.server.netty.RoutingInBoundHandler.handleRouteMatch(RoutingInBoundHandler.java:687)
at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:549)
at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:144)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)

Userguide link is 404

Hi,
I just clicked on the userguide link in the readme but it is not available

Kind Regards

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Pending Approval

These branches will be created by Renovate only once you click their checkbox below.

  • chore(deps): update actions/checkout action to v4.1.6
  • chore(deps): update github artifact actions to v4 (major) (actions/download-artifact, actions/upload-artifact)
  • ๐Ÿ” Create all pending approval PRs at once ๐Ÿ”

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

github-actions
.github/workflows/central-sync.yml
  • actions/checkout v4
  • gradle/wrapper-validation-action v2
  • actions/setup-java v4
.github/workflows/graalvm-dev.yml
  • actions/checkout v4
  • actions/checkout v4
.github/workflows/graalvm-latest.yml
  • actions/checkout v4
  • actions/checkout v4
.github/workflows/gradle.yml
  • actions/checkout v4
  • graalvm/setup-graalvm v1.2.1
  • gradle/gradle-build-action v3.2.1
  • mikepenz/action-junit-report v4
  • actions/upload-artifact v3.1.3@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
  • haya14busa/action-cond v1
.github/workflows/publish-snapshot.yml
  • actions/checkout v4
  • actions/cache v4
  • actions/setup-java v4
.github/workflows/release.yml
  • actions/checkout v4
  • gradle/wrapper-validation-action v2
  • actions/setup-java v4
  • actions/upload-artifact v3.1.3@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
  • actions/upload-artifact v3.1.3@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
  • actions/download-artifact v3.0.2@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
  • slsa-framework/slsa-github-generator v1.10.0
  • actions/checkout v4.1.1@b4ffde65f46336ab88eb53be808477a3936bae11
  • actions/download-artifact v3.0.2@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
  • softprops/action-gh-release v0.1.15@de2c0eb89ae2a093876385947365aca7b0e5f844
gradle
gradle.properties
settings.gradle
  • io.micronaut.build.shared.settings 6.7.0
build.gradle
buildSrc/settings.gradle
buildSrc/build.gradle
buildSrc/src/main/groovy/io.micronaut.build.internal.graphql-base.gradle
buildSrc/src/main/groovy/io.micronaut.build.internal.graphql-module.gradle
buildSrc/src/main/groovy/io.micronaut.build.internal.graphql.test-suite-graal.gradle
buildSrc/src/main/groovy/io.micronaut.build.internal.graphql.test-suite-serialization.gradle
buildSrc/src/main/groovy/micronaut-graphql.docs-examples-conventions.gradle
buildSrc/src/main/groovy/micronaut-graphql.example-conventions.gradle
docs-examples/hello-world-groovy/build.gradle
docs-examples/hello-world-java/build.gradle
docs-examples/hello-world-kotlin/build.gradle
gradle/libs.versions.toml
  • org.graalvm.nativeimage:svm 24.0.0
  • io.micronaut:micronaut-core-bom 4.4.1
  • io.micronaut.kotlin:micronaut-kotlin-bom 4.3.0
  • io.micronaut.security:micronaut-security-bom 4.7.0
  • io.micronaut.serde:micronaut-serde-bom 2.9.0
  • io.micronaut.reactor:micronaut-reactor-bom 3.3.0
  • com.graphql-java:graphql-java 21.5
  • com.graphql-java:graphql-java-extended-scalars 2023-01-24T02-11-56-babda5f
  • com.graphql-java-kickstart:graphql-java-tools 13.1.1
  • io.leangen.graphql:spqr 0.12.4
  • org.jetbrains.kotlin:kotlin-gradle-plugin 1.9.23
  • org.jetbrains.kotlin:kotlin-allopen 1.9.23
  • gradle.plugin.com.github.johnrengelman:shadow 8.0.0
  • io.micronaut.gradle:micronaut-gradle-plugin 4.3.6
gradle/license.gradle
graphql/build.gradle
graphql-bom/build.gradle
test-suite-graal/build.gradle
test-suite-jackson/build.gradle.kts
test-suite-serde/build.gradle.kts
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.7

  • Check this box to trigger a request for Renovate to run again on this repository

Upgrade bundled GraphiQL to version 2

Feature description

It would be nice to upgrade GraphiQL to last release (actually 2.0.0) to use the new features coming from collaboration with Playground team, such as tabs and plugin system

@Blocking annonation doesn't work in datafetcher

I am experimenting with a "hello world" graphql example and I observe that if I put a @Blocking annotation on the datafetcher method, I still see that the Micronaut is executing the method within the netty's eventloop.

@Blocking
@Override
	public String get(DataFetchingEnvironment env) implements DataFetcher<String> {
              return "foo"
}

and this is how I am doing runtime wiring

RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring()																							 .type("Query", typeWiring -> typeWiring																									 .dataFetcher("fooQuery", myDataFetcher))																							 .build();

I would expect to see that the method is being executed in some worker thread pool and not the netty's event loop.

I also tried @ExecuteOn approach but that didn't work either :(

GraphQL Dependency conflict

Thanks for reporting an issue, please review the task list below before submitting the
issue. Your issue report will be closed if the issue is incomplete and the below tasks not completed.

NOTE: If you are unsure about something and the issue is more of a question a better place to ask questions is on Stack Overflow (https://stackoverflow.com/tags/micronaut) or Gitter (https://gitter.im/micronautfw/). DO NOT use the issue tracker to ask questions.

Task List

  • Steps to reproduce provided
  • Stacktrace (if present) provided
  • Example that reproduces the problem uploaded to Github
  • Full description of the issue provided (see below)

Steps to Reproduce

  1. Use micronaut-graphql version 2.2.0
  2. Add the dependency :
       <dependency>
            <groupId>io.leangen.graphql</groupId>
            <artifactId>spqr</artifactId>
            <version>0.11.1</version>
        </dependency>
  1. Write a factory :
@Factory
public class GraphQLFactory {

    @Inject
    protected BeanContext beanContext;

    @Bean
    @Singleton
    public GraphQL graphQL() {
        GraphQLSchemaGenerator schemaGenerator = new GraphQLSchemaGenerator(); // 1

        Collection graphQLServices = beanContext.getBeansOfType(Object.class, Qualifiers.byStereotype(GraphQLService.class));

        if (graphQLServices.isEmpty()) {
            return new GraphQL.Builder(GraphQLSchema.newSchema().build())
                    .build();
        } else { // 4
            for (Object graphQLService : graphQLServices) {
                Class graphQLServiceClass = graphQLService.getClass();
                if (graphQLServiceClass.getSimpleName().contains("$Intercepted"))
                    graphQLServiceClass = graphQLServiceClass.getSuperclass();

                schemaGenerator.withOperationsFromSingleton(graphQLService, graphQLServiceClass);
            }
        }

        return new GraphQL.Builder(schemaGenerator.generate()).build();
    }
}

Expected Behaviour

The process should start and accept graphql queries.

Actual Behaviour

Failing with
Message: java.lang.NoSuchMethodError: graphql.schema.GraphQLType.getName()Ljava/lang/String;
Path Taken: new GraphQLController([GraphQLInvocation graphQLInvocation],GraphQLExecutionResultHandler graphQLExecutionResultHandler,GraphQLJsonSerializer graphQLJsonSerializer) --> new DefaultGraphQLInvocation([GraphQL graphQL],GraphQLExecutionInputCustomizer graphQLExecutionInputCustomizer,Provider dataLoaderRegistry)

Environment Information

  • Operating System: Linux
  • Micronaut Version: 2.3.4
  • JDK Version: 8

Example Application

Graal Support

First of all, thanks for added GraphQL support to the Micronaut Framework.

May I know is there any plan to support Graal for the fabulous micronaut-graphql packages? As I didn't find any graphql graal tests at https://github.com/micronaut-graal-tests.

Currently, I managed to make it works with Graal by import the source code to the following location of the project:
https://github.com/limcheekin/micronaut-person/tree/graal-data-jpa-2.0.x/src/main/java/io/micronaut/configuration/graphql
with the following minimal changes:

  • Added @Introspected to the GraphQLRequestBody and GraphQLResponseBody class
  • Removed the ws package which caused runtime errors in AWS Lambda and the app don't need such functionality
  • Removed GraphiQLController class which caused build errors and not needed in production

Oh yeah, forgot to mentioned that it works with one side effect, the response come with data property nested inside specification property, for example:

{
    "specification": {
        "data": {
           .....
        }
    }
}

Hopefully the library is support Graal by simply adding the dependency to build.gradle file in the near future. ๐Ÿ‘

Suport for multiple GraphQL Endpoints

Feature description

We have the use case that we expose internal and external GraphQL APIs. The feature would allow us to expose multiple endpoints on the same micronaut instance.

One way would. be to have the ability to register multiple graphql.GraphQL Beans (e.g: Named Beans) and configure a different endpoint path for each in the config.

Add support for GraphQL multipart request

Trying to make GraphQL multipart request work as per this specification https://github.com/jaydenseric/graphql-multipart-request-spec , but receiving error when I send a multipart request. Is Multipart request supported now in Micronaut/GraphQL extension ?

Error:
/string - Failed to convert argument [string] for value [null] due to: Cannot deserialize instance of java.lang.String out of START_OBJECT token
at [Source: UNKNOWN; line: -1, column: -1]] using codec: io.micronaut.jackson.codec.JsonMediaTypeCodec@439d545c

---- Logs ----

21:52:10.675 [nioEventLoopGroup-1-8] DEBUG i.m.h.s.netty.RoutingInBoundHandler - Matching route POST - /graphql
21:52:10.675 [nioEventLoopGroup-1-8] DEBUG i.m.h.s.netty.RoutingInBoundHandler - Matched route POST - /graphql to controller class io.micronaut.configuration.graphql.GraphQLController
21:52:10.676 [nioEventLoopGroup-1-8] DEBUG i.m.context.DefaultBeanContext - Resolved existing bean [io.micronaut.http.server.netty.FormDataHttpContentSubscriberFactory@5eeaaf88] for type [interface io.micronaut.http.server.netty.HttpContentSubscriberFactory] and qualifier [Content-Type: multipart/form-data;boundary=------------------------e67f840163e3fadc]
21:52:10.678 [nioEventLoopGroup-1-8] DEBUG i.m.c.beans.DefaultBeanIntrospector - No BeanIntrospection found for bean type: class java.lang.String
21:52:10.678 [nioEventLoopGroup-1-8] DEBUG io.micronaut.core.reflect.ClassUtils - Cannot instantiate type [class java.lang.String] without reflection. Attempting reflective instantiation
21:52:10.678 [nioEventLoopGroup-1-8] DEBUG i.m.context.DefaultBeanContext - Resolved existing bean [io.micronaut.jackson.bind.JacksonBeanPropertyBinder@69626e28] for type [interface io.micronaut.core.bind.BeanPropertyBinder] and qualifier [null]
21:52:10.678 [nioEventLoopGroup-1-8] DEBUG i.m.context.DefaultBeanContext - Registering singleton bean io.micronaut.http.server.exceptions.ConversionErrorHandler@246a6496 for type [<ConversionErrorException,Object> io.micronaut.http.server.exceptions.ExceptionHandler] using bean key <ConversionErrorException,Object> io.micronaut.http.server.exceptions.ConversionErrorHandler
21:52:10.678 [nioEventLoopGroup-1-8] DEBUG i.m.context.DefaultBeanContext - Registering singleton bean io.micronaut.http.server.exceptions.ConversionErrorHandler@246a6496 for type [<ConversionErrorException,Object> io.micronaut.http.server.exceptions.ExceptionHandler] using bean key <ConversionErrorException,Object> io.micronaut.http.server.exceptions.ConversionErrorHandler
21:52:10.679 [nioEventLoopGroup-1-8] DEBUG i.m.context.DefaultBeanContext - Registering singleton bean io.micronaut.http.server.exceptions.ConversionErrorHandler@246a6496 for type [<ConversionErrorException,Object> io.micronaut.http.server.exceptions.ExceptionHandler] using bean key <ConversionErrorException,Object> io.micronaut.http.server.exceptions.ConversionErrorHandler
21:52:10.679 [nioEventLoopGroup-1-8] DEBUG i.m.context.DefaultBeanContext - Resolved existing bean [io.micronaut.http.server.exceptions.ConversionErrorHandler@246a6496] for type [interface io.micronaut.http.server.exceptions.ExceptionHandler] and qualifier [<ConversionErrorException,Object>]
21:52:10.679 [nioEventLoopGroup-1-8] DEBUG i.m.h.s.netty.RoutingInBoundHandler - Encoding emitted response object [ /string - Failed to convert argument [string] for value [null] due to: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
 at [Source: UNKNOWN; line: -1, column: -1]] using codec: io.micronaut.jackson.codec.JsonMediaTypeCodec@439d545c

GraphQLController not supported on AWS Lambda+Proxy API Gateway

graphql/src/main/java/io/micronaut/configuration/graphql/GraphQLController.java

There is problem with below code :
@Post(consumes = ALL, produces = APPLICATION_JSON, single = true)

consumes all translated to / which does not match with request over AWS.

Suggesting below to get it worked with LambdaProxyHandler
consumes = {MediaType.APPLICATION_JSON,MediaType.APPLICATION_GRAPHQL}

Move every example GraphQL project to a Micronaut Guide

@timyates I would like you to move every example project to a Micronaut Guide.

Those examples don't participate in the documentation and they would be more discoverable by users in guides.

chat

  • Example deletion PR
  • Guide PR

jwt-security

  • Example deletion PR
  • Guide PR

todo-java-tools

  • Example deletion PR
  • Guide PR

todo

  • Example deletion PR
  • Guide PR

todo-spqr

  • Example deletion PR
  • Guide PR

Secured Annotation is not fired on @GraphQLQuery and @GraphQLMutation

Thanks for reporting an issue, please review the task list below before submitting the
issue. Your issue report will be closed if the issue is incomplete and the below tasks not completed.

NOTE: If you are unsure about something and the issue is more of a question a better place to ask questions is on Stack Overflow (https://stackoverflow.com/tags/micronaut) or Gitter (https://gitter.im/micronautfw/). DO NOT use the issue tracker to ask questions.

Task List

  • Steps to reproduce provided
  • Stacktrace (if present) provided
  • Example that reproduces the problem uploaded to Github
  • Full description of the issue provided (see below)

Steps to Reproduce

  1. Launch the app : https://github.com/fabienmifsud/micronaut-crud
  2. Execute a graphQL query :
    POST : http://localhost:8080/graphql
query readClients {
  clients{
    id,
    name,
    email,
    dateOfBirth
  }
}

With Basic Authent standardUser/standardUser
3. The query response is a 403 forbidden because all @secured annotations are not triggered (only the path /graphql is triggered when debugging SecuredAnnotationRule class)

Expected Behaviour

The secured & RolesAllowed annotations on ClientService should be interpreted.

Actual Behaviour

The secured & RolesAllowed annotations on ClientService are not interpreted and since graphql use the same url for all the queries, it is not possible to secured specificaly some queries or mutations.

Environment Information

  • Operating System: Linux
  • Micronaut Version: 2.3.4
  • JDK Version: OpenJDK 8

Example Application

GraphQL fields are always null

Expected Behavior

When doing a simple query like

query {
  allBooks {
    name
  }
}

I would expect the name attribute to not be null.

Actual Behaviour

The query results in

{
  "data": {
    "allBooks": [
      {
        "name": null
      },
      {
        "name": null
      },
      {
        "name": null
      }
    ]
  }
}

Steps To Reproduce

please see the github repo.

Environment Information

No response

Example Application

https://github.com/patrickdronk/mn-graphql-graalvm-lambda

Version

3.3.0

Security Example configuration is old

Issue description

see: https://github.com/micronaut-projects/micronaut-graphql/blob/master/examples/jwt-security/src/main/resources/application.yml

I think this

micronaut:
  security:
    enabled: true
    authentication: cookie
    token:
      jwt:
        enabled: true
        bearer:
          enabled: false
        cookie:
          enabled: true
      refresh:
        cookie:
          enabled: false
    intercept-url-map:
      - pattern: /**
        http-method: GET
        access:
          - isAnonymous()
      - pattern: /**
        http-method: POST
        access:
          - isAnonymous()
graphql:
  graphiql.enabled: true

can be :

micronaut:
  security:
    authentication: cookie
    token:
      refresh:
        cookie:
          enabled: false
    intercept-url-map:
      - pattern: /**
        http-method: GET
        access:
          - isAnonymous()
      - pattern: /**
        http-method: POST
        access:
          - isAnonymous()
graphql:
  graphiql.enabled: true

Rename all `graphql-ws` related classes

Issue description

Currently all graphql-ws classes are related to an implementation of subscription-transport-ws , but there's a new protocol called graphql-ws. That name conflicts with the current naming of the old implementation and a new one would have to use a "workaround naming". To avoid such a chaos, it should be considered renaming the old classes and package. Something like ApolloGraphQLWs would be a good name. The disadvantage of this renaming would that a lot of codebase would have to refactor imports and config options, so this is definitely a breaking change.

This issue related to #301. If this decision is made then I would probably implement the new protocol when I have some time.

GraphQLWsController is heavy on logs

This ticket is related to

LOG.info("Opened websocket connection with id {}", session.getId());

On every page refresh onClose and onOpen is logged at info level. I could just filter info from logback.xml, but onError is logging at the same level. This makes distinguishing between 'normal' and 'exceptional' flow difficult. Generally speaking, my problem is solved as long as the onOpen()', 'onClose() are different from onError.

Having said that, I believe log levels for onOpen() and onClose() should be trace or at most debug level. onError should be considered debug or at most info.

The {graphqlPath} in index.html for graphiql does not take context-path into account

Steps to Reproduce

  1. Install Micronaut and micronaut-graphql
  2. Use any of the examples in this project
  3. Set micronaut.server.context-path to /some/random/path in application.yml
  4. Add settings to enable graphiql (defaults will do)
  5. Go to the graphiql index page

Expected Behaviour

The index.html should post to /some/random/path/graphql

Actual Behaviour

The page will post to /graphql

Environment Information

  • Micronaut Version: 2.3.1
  • JDK Version: 11.0.7
  • micronaut-graphql Version 2.2.0

Proposed solution

Add HttpServerConfiguration to GraphiQLController and add the contextPath to the parameters Map. Add this variable to the index.html:
return fetch('${contextPath}${graphqlPath}', {...}

GraphQL access to underlying HttpRequest

Our setup within company involves using SSL certificates for connecting to any intranet / internet website. The certificate has user information, and it is what we use to Authenticate.

In my DataFetchers I will like to know the identity of the requesting user. I had hard time trying to figure it out. I eventually did - but kinda think there must be a better way to do it.

What I did -

  1. Added HttpServerFilter, and used HttpRequest and NettyHttpRequest to get underlying SSL context to retrieve certificate.
  2. Parsed cert to get user information.
  3. Called custom Authentication / Authorization service to retrieve valid user roles. (this has to be custom as it goes to central db and is a separate microservice)
  4. Populated UserDetails and added it back to HttpRequest as an attribute.

i resorted to adding Filter because, I was not able to get my implementation of AuthenticationProvider (as mentioned in the guide but for BasicAuth) called. Most likely my lack of knowledge - but will like to know if there is a better way to implement SSLAuthenticationProvider.

By default, I don't have access to HttpRequest in DataFetchers. After going through code and debugging finally resorted to overriding / @Replaces annotation and replaced one of the framework bean (which I don't like)
I Replaced DefaultGraphQLInvocation and made a small change in it to set httpRequest in the context :

ExecutionInput.newExecutionInput()
.query(..).operationName(..).variables.(..)
.context(httpRequest).build();

And then in my Datafetcher, I could get it from DataFetchingEnvironment. I just think, there must be a simple and better solution to this which I haven't been able to figure out.

Appreciate your help.
Thanks

Graphiql configuration not loaded in 1.0.0

For such configuration:

graphql:
  enabled: true
  graphiql:
    enabled: true
    path: /api/public/graphiql
    template-path: classpath:graphiql-index.html

graphiql configuration is not loaded here. The graphiQLConfiguration object still has defaults in its properties, instead of values loaded from config. The only reason the controller works is because of this header, which uses appropriate properties from the config.

To make it working I need to repeat the same configuration this way:

graphql:
  enabled: true
  graphiql: # thats the feed for @Controller annotation
    enabled: true
    path: /api/public/graphiql
    template-path: classpath:graphiql-index.html
  graphiQLConfiguration: # this is a workaround to load the proper config into graphiQLConfiguration object
    graphiql: 
      enabled: true
      path: /api/public/graphiql
      template-path: classpath:graphiql-index.html

It looks the GraphQLConfiguration is wrong.

Add support for GraphQL v20

Feature description

GraphQL recently released version 20, which include many new features and improvements, including support for java records

GraphQL FAIL_ON_EMPTY_BEANS

Task List

  • Steps to reproduce provided
  • Stacktrace (if present) provided
  • Example that reproduces the problem uploaded to Github
  • Full description of the issue provided (see below)

Expected Behaviour

Is this issue related to configuration?

Actual Behaviour

14:06:15.726 [pool-2-thread-2] ERROR i.m.s.DefaultTaskExceptionHandler - Error invoking scheduled task Error instantiating bean of type [io.micronaut.configuration.graphql.ws.GraphQLWsKeepAlive]: Error serializing object to JSON: No serializer found for class io.micronaut.configuration.graphql.ws.GraphQLWsResponse and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type [io.micronaut.configuration.graphql.ws.GraphQLWsKeepAlive]: Error serializing object to JSON: No serializer found for class io.micronaut.configuration.graphql.ws.GraphQLWsResponse and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
	at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1918)
	at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:2638)
	at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2624)
	at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2296)
	at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2270)
	at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:716)
	at io.micronaut.scheduling.processor.ScheduledMethodProcessor.lambda$process$5(ScheduledMethodProcessor.java:123)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.lang.Thread.run(Thread.java:834)
	at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:517)
	at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
Caused by: java.lang.RuntimeException: Error serializing object to JSON: No serializer found for class io.micronaut.configuration.graphql.ws.GraphQLWsResponse and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
	at io.micronaut.configuration.graphql.JacksonGraphQLJsonSerializer.serialize(JacksonGraphQLJsonSerializer.java:51)
	at io.micronaut.configuration.graphql.ws.GraphQLWsKeepAlive.<init>(GraphQLWsKeepAlive.java:55)
	at io.micronaut.configuration.graphql.ws.$GraphQLWsKeepAliveDefinition.build(Unknown Source)
	at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1889)
	... 14 common frames omitted
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class io.micronaut.configuration.graphql.ws.GraphQLWsResponse and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
	at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277)
	at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
	at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71)
	at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
	at com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4407)
	at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3661)
	at io.micronaut.configuration.graphql.JacksonGraphQLJsonSerializer.serialize(JacksonGraphQLJsonSerializer.java:49)
	... 17 common frames omitted

Environment Information

  • Operating System: MacOSX 10.15
  • Micronaut Version: 2.0.3
  • JDK Version: 11

build.gradle

plugins {
    id "com.diffplug.eclipse.apt" version "3.22.0"
    id "groovy"
    id "com.github.johnrengelman.shadow" version "6.0.0"
    id "application"
    id "org.sonarqube" version "3.0"
}

version "0.1"
group "io.example"

repositories {
    mavenCentral()
    jcenter()
}

configurations {
    // for dependencies that are needed for development only
    developmentOnly
}

dependencies {
    compileOnly("org.projectlombok:lombok:$lombokVersion")
    annotationProcessor("org.projectlombok:lombok:$lombokVersion")
    annotationProcessor(platform("io.micronaut:micronaut-bom:$micronautVersion"))
    annotationProcessor("io.micronaut:micronaut-inject-java")
    annotationProcessor("io.micronaut:micronaut-validation")
    annotationProcessor("io.micronaut:micronaut-graal")
    compileOnly(platform("io.micronaut:micronaut-bom:$micronautVersion"))
    compileOnly("org.graalvm.nativeimage:svm")
    implementation(platform("io.micronaut:micronaut-bom:$micronautVersion"))
    implementation("io.micronaut:micronaut-inject")
    implementation("io.micronaut:micronaut-validation")
    implementation("io.micronaut:micronaut-runtime")
    implementation("javax.annotation:javax.annotation-api")
    implementation("io.micronaut:micronaut-http-server-netty")
    implementation("io.micronaut:micronaut-http-client")
    implementation("io.micronaut.flyway:micronaut-flyway")
    implementation("io.micronaut.sql:micronaut-jdbc-hikari")
    implementation("io.micronaut.beanvalidation:micronaut-hibernate-validator")
    implementation("io.micronaut.sql:micronaut-hibernate-jpa")
    implementation("io.micronaut.graphql:micronaut-graphql")
    implementation("io.micronaut.cache:micronaut-cache-caffeine")
    runtimeOnly("ch.qos.logback:logback-classic")
    runtimeOnly("org.postgresql:postgresql")
    implementation("com.graphql-java-kickstart:graphql-java-tools:$graphqlJavaToolsVersion")

    testCompileOnly("org.projectlombok:lombok:$lombokVersion")
    testAnnotationProcessor("org.projectlombok:lombok:$lombokVersion")
    testImplementation(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion"))
    testImplementation("io.micronaut:micronaut-inject-groovy")
    testImplementation("org.spockframework:spock-core") {
        exclude group: "org.codehaus.groovy", module: "groovy-all"
    }
    testImplementation("io.micronaut.test:micronaut-test-spock")

    testImplementation(platform("org.testcontainers:testcontainers-bom:1.14.3"))
    testRuntimeOnly("org.testcontainers:postgresql")

    implementation('com.github.javafaker:javafaker:1.0.2')
}

test.classpath += configurations.developmentOnly

mainClassName = "io.passiontech.Application"

// use JUnit 5 platform
test {
    useJUnitPlatform()
}

java {
    sourceCompatibility = JavaVersion.toVersion('11')
    targetCompatibility = JavaVersion.toVersion('11')
}

tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
    options.compilerArgs.addAll([
        '-parameters',
        // enables incremental compilation
        '-Amicronaut.processing.incremental=true',
        '-Amicronaut.processing.annotations=io.passiontech.*',
        "-Amicronaut.processing.group=$project.group",
        "-Amicronaut.processing.module=$project.name",
    ])
}

shadowJar {
    mergeServiceFiles()
}

tasks.withType(JavaExec) {
    classpath += configurations.developmentOnly
    jvmArgs('-XX:TieredStopAtLevel=1', '-Dcom.sun.management.jmxremote')
    if (gradle.startParameter.continuous) {
        systemProperties(
            'micronaut.io.watch.restart':'true',
            'micronaut.io.watch.enabled':'true',
            "micronaut.io.watch.paths":"src/main"
        )
    }
}

Does not work with io.micronaut.graphql:micronaut-graphql:1.2.0

When running with micronaut-graphql:1.2.0 a runtime exception is thrown

Message: No bean of type [org.dataloader.DataLoaderRegistry] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Path Taken: new GraphQLController([GraphQLInvocation graphQLInvocation],GraphQLExecutionResultHandler graphQLExecutionResultHandler,GraphQLJsonSerializer graphQLJsonSerializer) --> new DefaultGraphQLInvocation(GraphQL graphQL,GraphQLExecutionInputCustomizer graphQLExecutionInputCustomizer,[Provider dataLoaderRegistry])
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [dataLoaderRegistry] of class: io.micronaut.configuration.graphql.DefaultGraphQLInvocation

Message: No bean of type [org.dataloader.DataLoaderRegistry] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Path Taken: new GraphQLController([GraphQLInvocation graphQLInvocation],GraphQLExecutionResultHandler graphQLExecutionResultHandler,GraphQLJsonSerializer graphQLJsonSerializer) --> new DefaultGraphQLInvocation(GraphQL graphQL,GraphQLExecutionInputCustomizer graphQLExecutionInputCustomizer,[Provider dataLoaderRegistry])
	at io.micronaut.context.AbstractBeanDefinition.resolveBeanWithGenericsFromConstructorArgument(AbstractBeanDefinition.java:1701)
	at io.micronaut.context.AbstractBeanDefinition.getBeanProviderForConstructorArgument(AbstractBeanDefinition.java:1064)
	at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:967)
	at io.micronaut.configuration.graphql.$DefaultGraphQLInvocationDefinition.build(Unknown Source)
	at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1494)
	at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2174)
	at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1852)
	at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1832)
	at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:997)
	at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:982)
	at io.micronaut.configuration.graphql.$GraphQLControllerDefinition.build(Unknown Source)
	at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1494)
	at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2174)
	at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1852)
	at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1832)
	at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:577)
	at io.micronaut.context.DefaultBeanContext$BeanExecutionHandle.getTarget(DefaultBeanContext.java:2693)
	at io.micronaut.context.DefaultBeanContext$BeanExecutionHandle.invoke(DefaultBeanContext.java:2714)
	at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:295)
	at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:122)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildResultEmitter$15(RoutingInBoundHandler.java:1330)
	at io.reactivex.internal.operators.flowable.FlowableDefer.subscribeActual(FlowableDefer.java:35)
	at io.reactivex.Flowable.subscribe(Flowable.java:14805)
	at io.reactivex.Flowable.subscribe(Flowable.java:14752)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
	at io.reactivex.Flowable.subscribe(Flowable.java:14805)
	at io.reactivex.internal.operators.flowable.FlowableMap.subscribeActual(FlowableMap.java:37)
	at io.reactivex.Flowable.subscribe(Flowable.java:14805)
	at io.reactivex.Flowable.subscribe(Flowable.java:14752)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
	at io.reactivex.Flowable.subscribe(Flowable.java:14805)
	at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
	at io.reactivex.Flowable.subscribe(Flowable.java:14805)
	at io.reactivex.Flowable.subscribe(Flowable.java:14752)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
	at io.reactivex.Flowable.subscribe(Flowable.java:14805)
	at io.reactivex.Flowable.subscribe(Flowable.java:14755)
	at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:52)
	at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52)
	at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:52)
	at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
	at io.reactivex.Flowable.subscribe(Flowable.java:14805)
	at io.reactivex.Flowable.subscribe(Flowable.java:14752)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:68)
	at io.reactivex.Flowable.subscribe(Flowable.java:14805)
	at io.reactivex.Flowable.subscribe(Flowable.java:14752)
	at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
	at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run(ExecutorScheduler.java:288)
	at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run(ExecutorScheduler.java:253)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:748)
Caused by: io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [org.dataloader.DataLoaderRegistry] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
	at io.micronaut.context.DefaultBeanContext.getBeanProvider(DefaultBeanContext.java:1102)
	at io.micronaut.context.AbstractBeanDefinition.lambda$getBeanProviderForConstructorArgument$9(AbstractBeanDefinition.java:1065)
	at io.micronaut.context.AbstractBeanDefinition.resolveBeanWithGenericsFromConstructorArgument(AbstractBeanDefinition.java:1697)
	... 54 common frames omitted

Dependencies in build.gradle

dependencies {
    annotationProcessor "io.micronaut:micronaut-inject-java"
    annotationProcessor "io.micronaut:micronaut-validation"
    compile 'io.micronaut.graphql:micronaut-graphql:1.2.0'
    compile("io.micronaut:micronaut-http-client")
    compile("io.micronaut:micronaut-http-server-netty")
    compile("io.micronaut:micronaut-inject")
    compile("io.micronaut:micronaut-validation")
    compile("io.micronaut:micronaut-runtime")
    compileOnly("io.micronaut:micronaut-inject-java")
    runtime("ch.qos.logback:logback-classic:1.2.3")
}

Fails to parse valid Apollo subscription messages which contain extensions field

Describe the bug

Apollo sends an extensions: {} field with subscription queries like so:

{
  "id": "1",
  "type": "start",
  "payload": {
    "variables": {
      "_v0_symbol": "btcusd"
    },
    "extensions": {},
    "operationName": null,
    "query": "subscription ($_v0_symbol: String) {  ticker(symbol: $_v0_symbol) {    average    createdAtTimestamp  }}"
  }
}

Unless extensions is removed or changed to undefined then the java graphql server refuses to parse the valid message. In Micronaut v1 it threw a JSON parse exeption, in Micronaut v2 it doesn't throw but a response is not sent unless extensions is undefined or not present.

To Reproduce

Send a query with extensions: {} for example:

{
  "id": "1",
  "type": "start",
  "payload": {
    "variables": {
      "marketId": "BTCUSD"
    },
    "extensions": {},
    "operationName": "TickerForTradeSubscription",
    "query": "subscription TickerForTradeSubscription($marketId: String!) {\n  ticker(symbol: $marketId) {\n    symbol\n    open\n    low\n    high\n    baseVolume\n    bestBid\n    bestAsk\n    last\n    lastTradeSize\n    createdAtTimestamp\n    __typename\n  }\n}\n"
  }
}

Environment Information

  • Operating System: MacOS & Docker
  • Micronaut Version: v2
  • JDK Version: 11

Update GraphiQL default version

Feature description

the currently used default version of graphiql (0.13.2) dates back to 2019

using recent versions (eg v1.0.0 added a request header editor) does not work as CDN URLs changed and also react needs to be updated.

i customized my local setup using the below template and application.yml
evtl somebody is willing to put this into a new micronaut-graphql release

graphql:
  graphiql:
    version: 1.8.5
    template-path: classpath:graphiql/index-custom.html

graphiql/index-custom.html:

<!--
 based on cdn example https://github.com/graphql/graphiql/blob/main/examples/graphiql-cdn/index.html

 with adaptions from micronaut's graphiql client
 https://github.com/micronaut-projects/micronaut-graphql/blob/master/graphql/src/main/resources/graphiql/index.html

 and also pass headers to the fetcher
  https://github.com/graphql/graphiql/issues/59#issuecomment-914079822

 *  Copyright (c) 2021 GraphQL Contributors
 *  All rights reserved.
 *
 *  This source code is licensed under the license found in the
 *  LICENSE file in the root directory of this source tree.
-->
<!DOCTYPE html>
<html>
<head>
    <title>${pageTitle}</title>
    <style>
      body {
        height: 100%;
        margin: 0;
        width: 100%;
        overflow: hidden;
      }

      #graphiql {
        height: 100vh;
      }
    </style>

    <!--
      This GraphiQL example depends on Promise and fetch, which are available in
      modern browsers, but can be "polyfilled" for older browsers.
      GraphiQL itself depends on React DOM.
      If you do not want to rely on a CDN, you can host these files locally or
      include them directly in your favored resource bunder.
    -->
    <script
            crossorigin
            src="https://unpkg.com/react@16/umd/react.development.js"
    ></script>
    <script
            crossorigin
            src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"
    ></script>

    <!--
      These two files can be found in the npm module, however you may wish to
      copy them directly into your environment, or perhaps include them in your
      favored resource bundler.
     -->
    <link rel="stylesheet" href="https://unpkg.com/graphiql@${graphiqlVersion}/graphiql.min.css" />
</head>

<body>
<div id="graphiql">Loading...</div>
<script
        src="https://unpkg.com/graphiql@${graphiqlVersion}/graphiql.min.js"
        type="application/javascript"
></script>

<script>

    // Parse the search string to get url parameters.
    var search = window.location.search;
    var parameters = {};
    search.substr(1).split('&').forEach(function (entry) {
        var eq = entry.indexOf('=');
        if (eq >= 0) {
            parameters[decodeURIComponent(entry.slice(0, eq))] =
                decodeURIComponent(entry.slice(eq + 1));
        }
    });

    // If variables was provided, try to format it.
    if (parameters.variables) {
        try {
            parameters.variables =
                JSON.stringify(JSON.parse(parameters.variables), null, 2);
        } catch (e) {
            // Do nothing, we want to display the invalid JSON as a string, rather
            // than present an error.
        }
    }

    // When the query and variables string is edited, update the URL bar so
    // that it can be easily shared.
    function onEditQuery(newQuery) {
        parameters.query = newQuery;
        updateURL();
    }

    function onEditVariables(newVariables) {
        parameters.variables = newVariables;
        updateURL();
    }

    function onEditOperationName(newOperationName) {
        parameters.operationName = newOperationName;
        updateURL();
    }

    function updateURL() {
        var newSearch = '?' + Object.keys(parameters).filter(function (key) {
            return Boolean(parameters[key]);
        }).map(function (key) {
            return encodeURIComponent(key) + '=' +
                encodeURIComponent(parameters[key]);
        }).join('&');
        history.replaceState(null, null, newSearch);
    }

    // return path to service from current URL where GraphiQL was invoked
    function pathToService() {
        let graphiqlPath = '${graphiqlPath}'
        let graphiqlPathLength = graphiqlPath.length
        let removePathLength = window.location.pathname.endsWith('/') && !graphiqlPath.endsWith('/')
            ? graphiqlPathLength + 1
            : graphiqlPathLength;

        return window.location.pathname.substr(0, window.location.pathname.length - removePathLength);
    }

      function graphQLFetcher(graphQLParams, opts) {
        const { headers = {} } = opts;
        return fetch(
          pathToService() + '${graphqlPath}',
          {
            method: 'post',
            headers: {
              Accept: 'application/json',
              'Content-Type': 'application/json',
              ...headers,
            },
            body: JSON.stringify(graphQLParams),
            credentials: 'include',
          },
        ).then(function (response) {
          return response.json().catch(function () {
            return response.text();
          });
        });
      }

    let fetcher = graphQLFetcher;
    if('${graphqlWsPath}' !== ''){
      let wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
      let fullWsPath = wsProtocol + '//' + window.location.hostname + ':' + window.location.port + pathToService() +'${graphqlWsPath}';
      let subscriptionsClient = new window.SubscriptionsTransportWs.SubscriptionClient(fullWsPath, { reconnect: true });
      fetcher = window.GraphiQLSubscriptionsFetcher.graphQLFetcher(subscriptionsClient, graphQLFetcher);
    }

      ReactDOM.render(
        React.createElement(GraphiQL, {
          fetcher: fetcher,
          query: parameters.query,
          defaultVariableEditorOpen: true,
          variables: parameters.variables,
            operationName: parameters.operationName,
            onEditQuery: onEditQuery,
            onEditVariables: onEditVariables,
            defaultVariableEditorOpen: true,
            onEditOperationName: onEditOperationName
        }),
        document.getElementById('graphiql'),
      );
    </script>
</body>
</html>

Returning a Publisher from a data fetcher for a Query / Mutation

My data fetchers make use of a reactive http client. I need to return a publisher from the data fetcher to avoid blocking the main event loop with a blockingSingle or similar.

I noticed the example show returning a publisher for a subscription. However, when I return a publisher from a mutation via a data fetcher, I get essentially a blank result. I have also set breakpoints and have found that the reactive stream is not being executed on return. It appears the publisher is being returned without being evaluated.

I did see how a publisher can be returned for subscription using the SubscriptionExecutionStrategy. However, that use case does not support a simple query or mutation which would emit a single result, not a stream.

It does look like SubscriptionExecutionStrategy can be adapted to allow this, I am just not sure how.

Any thoughts or suggestions would be appreciated.

Access User/Roles in GraphQL

Feature description

I'd like to limit usage of certain GraphQL queries or mutations to certain roles and also access user- and role related information (eg via SecuirtyService bean) within functions exposed via GraphQL.

Currently this seems to be impossible or at least undocumented (i did not find a section/example in the docs)

There is an open (and for > 1 year unanswered) issue for supporting the @Secured annotation. (this blogpost seems to (partly) solve this problem)

There is also another ticket outlining how to access request information.
I used this approach to extract authentication information (duplicating logic of a custom AuthenticationFetcher) from the request and inject it into mutation parameters within a DataFetcherFactoryProvider via mapParameterToValue.

A nicer way would be to have a possibility to inject SecurityService but it seems request scope beans currently do not really work in the context of GraphQL

Is there any way to add cookie to the response?

Hello!

It looks like the current version of plugin doesn't support returning custom cookies from GraphQL response, current controller will only return json string: https://github.com/micronaut-projects/micronaut-graphql/blob/b3e084d2c42b8d41455bf717bda9b577a2e1d27f/graphql/src/main/java/io/micronaut/configuration/graphql/GraphQLController.java. Maybe I didn't understand wrong, but in case if I need to add some cookies or add some additional headers to the response, I need to modify controller and instead of returning Publisher<String> change it to returning something like MutableHttpResponse<?>. In this case I can use GraphQL context object as a transport for passing cookies to the controller, am I right? Or there is another way to do it?

Thank you!

Micronaut GraphQL as native-image does not work properly

Expected Behavior

The graphlql response:

{
  "data": {
    "products": [
      {
        "id": "1",
        "extId": "Ext34",
        "kind": "Kind2"
      }
    ]
  }
}

Actual Behaviour

The graphlql response:

{
  "errors": [
    {
      "message": "The field at path '/products[0]/id' was declared as a non null type, but the code involved in retrieving data has wrongly returned a null value.  The graphql specification requires that the parent field be set to null, or if that is non nullable that it bubble up null to its parent and so on. The non-nullable type is 'ID' within parent type 'Product'",
      "path": [
        "products",
        0,
        "id"
      ],
      "extensions": {
        "classification": "NullValueInNonNullableField"
      }
    },
    {
      "message": "The field at path '/products[0]/extId' was declared as a non null type, but the code involved in retrieving data has wrongly returned a null value.  The graphql specification requires that the parent field be set to null, or if that is non nullable that it bubble up null to its parent and so on. The non-nullable type is 'String' within parent type 'Product'",
      "path": [
        "products",
        0,
        "extId"
      ],
      "extensions": {
        "classification": "NullValueInNonNullableField"
      }
    },
    {
      "message": "The field at path '/products[0]/kind' was declared as a non null type, but the code involved in retrieving data has wrongly returned a null value.  The graphql specification requires that the parent field be set to null, or if that is non nullable that it bubble up null to its parent and so on. The non-nullable type is 'String' within parent type 'Product'",
      "path": [
        "products",
        0,
        "kind"
      ],
      "extensions": {
        "classification": "NullValueInNonNullableField"
      }
    }
  ],
  "data": {
    "products": [
      null
    ]
  }
}

Steps To Reproduce

Build the micronaut native-image application:

./gradlew nativeCompile

Run the micronaut native-image application:

./build/native/nativeCompile/graphql-native-bug

Open the url http://localhost:8080/graphiql

Execute the graphql query:

{
  products {
    id
    extId
    kind
  }
}

See the graphql response.

Though the micronaut openjdk application works properly.
The actual result of the micronaut openjdk application is presented at Expected Behaviour section above.

Environment Information

  • OS Ubuntu 20.04
  • graalvm-ce-java17-22.1.0

Example Application

https://github.com/eratolekov/micronaut-graphql-native-bug

Version

3.6.2

Upgrade to Micronaut 2.0 rollback?

This project was upgraded to Micronaut 2.0 back in May.

Then a month later @graemerocher pushed this commit to aa61709 to downgrade the project back to Micronaut 1.3.x. Graeme, do you remember why did you revert the micronaut version?

At this moment master and 1.3.x branch target 1.3.1.BUILD-SNAPSHOT version but the latter has only been updated with PRs related to update the common build files.

This is what I would like to do:

  • Branch 1.3.x uses the old build system. I'll leave it as it is for legacy purposes but we won't add more code there.
  • Set version 1.4.0.BUILD-SNAPSHOT in master branch.
  • Release 1.4.0. Use this version in Micronaut 2.0.x BOM.
  • Create 1.4.x branch off of master.
  • Upgrade master to Micronaut 2 and release 2.0.0.RC1.
  • Then, for Micronaut 2.1 include a future 2.0.0 version of this module in the BOM.

@graemerocher @marceloverdijk thoughts or comments about the plan?

Support for pass HTTP Headers in Graphiql

Feature description

Currently, we can only pass query variables in /graphiql, however, at times we need to pass header parameters like x-api-key or other custom headers to some apis which is tough to test out using graphiql and we've to resort to restful clients like postman to test those apis.
If this can be enabled in graphiql (similar to this: https://developers.cloudflare.com/analytics/graphql-api/getting-started/authentication/graphql-client-headers) that would be great feature here.

Add example of using DataLoader

Thank you so much for providing this project! I'm trying to set my project up following the todo-java-tools example. I noticed that example and none of the others demonstrate using a DataLoader and I'm having a hard time figuring it out. (I do see some support was added). I'd love it if this were something that could be added to the example

Thanks again!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.