GraphQL for Java with Spring Boot made easy.
APACHE-2.0 License
Bot releases are visible (Hide)
Published by github-actions[bot] about 3 years ago
Published by srinivasankavitha about 3 years ago
Published by github-actions[bot] about 3 years ago
Published by github-actions[bot] about 3 years ago
As part of an effort to migrate the DGS Client Components that should belong to the DGS Codegen project, we are removing from the graphql-dgs-client
module all components in the com.netflix.graphql.dgs.client.codegen
package. If you depend on them you will have to use the DGS Codegen plugin, such plugin will add a new module automatically with the artifacts. This change will allow us to evolve the both projects independently. In other words, we will not need to release a new version of the DGS Framework if we need changes to the DGS Codegen components.
@connection
directive for generating SDL types for cursor-based pagination. (#487) @srinivasankavithaAs a new feature we are releasing the new graphql-dgs-pagination
module. It adds support for generating schema types for cursor-based pagination based on the relay spec.
The benefit is to avoid having the user define related Connection and Edge types in the schema for every type that needs to be paginated. The following example below shows the schema the user needs to define:
type Query {
something: MovieConnection
}
type Movie @connection {
movieID: ID
title: String
}
Note the @connection
directive against the type Movie
. This will generate a MovieConnection
and MovieEdge
as follows:
type MovieConnection {
edges: [MovieEdge]
pageInfo: PageInfo
}
type MovieEdge {
node: Movie
cursor: String
}
type PageInfo {
hasPreviousPage: Boolean!
hasNextPage: Boolean!
startCursor: String
endCursor: String
}
PageInfo
is generated only once, if necessary.
You can now use Kotlin Coroutines to define datafetchers. For example, let's say we have a field called range
that will compute the sum between two numbers. You could define your datafetcher as follows:
@DgsQuery
suspend fun range(@InputArgument from: Int, to: Int): Int = coroutineScope {
var sum = 0
withContext(executor.asCoroutineDispatcher()) {
repeat(from.rangeTo(to).count()) {
sum++
// Forcing a blocking call to demonstrate running with a thread pool
Thread.sleep(50)
}
sum
}
}
Using a coroutine is very similar to returning CompletableFuture
. In fact, coroutines are internally resolved as CompletableFuture
.
A coroutine (similar to returning CompletableFuture
) marks a datafetcher as potentially async.
However, coroutine datafetchers are dispatched using the unconfined dispatcher, which in practice means they won't automatically get any parallel behavior. This means, that multiple datafetchers defined as coroutines will still not run in parallel.
To get parallel execution, the developer is in charge of setting up the correct context. A great way to do this is using an Executor
.
Also remember that any thread-bound context, such as request data stored on thread-local, will not be available when executing on a different thread. An executor has to be set up explicitly for this.
Again, this is exactly the same when using CompletableFuture
for parallel datafetcheres.
Published by github-actions[bot] over 3 years ago
Published by github-actions[bot] over 3 years ago
Published by github-actions[bot] over 3 years ago
We are preparing to move the following components to the DGS Codegen project.
These artifacts are mainly used in the context of codegen. With the move we will hope to decouple
the codegen project from the DGS Framework releases. For now you can still use them but soon they will be deprecated
and after that removed:
For now things stay the same but, this will eventually affect you if you are using the graphql-dgs-client
.
We will deprecate the components and provide you with additional instructions in the next release.
Published by github-actions[bot] over 3 years ago
Published by github-actions[bot] over 3 years ago
You can now return a Mono
or Flux
from a Data Fetcher. The framework will now transform a Mono or Flux object to a CompletableFuture automatically such that graphql-java can process its execution. Since graphql-java is already executing async this doesn't add any extra blocking.
The gql.resolver
, gql.dataLoader
, and gql.error
timers will now express the following tags:
gql.operation
: QUERY, MUTATION, SUBSCRIPTION are the possible values. These represent the GraphQL operation that is executed.
gql.operation.name
: GraphQL operation name if any. There is only one operation name per execution. If the GraphQL query does not have an operation name, anonymous is used instead. Since the cardinality of the value is high it will be limited. More on how you can configure such limit below.
gql.query.sig.hash
: Query Signature Hash of the query that was executed. Absent in case the query failed to pass GraphQL validation. Since the cardinality of the value is high it will be limited. More on how you can configure such limit below.
Note, in addition we are changing the name of the qgl.queryComplexity
tag to gql.query.complexity
to better express that the complexity is a part of the query and be inline with gql.query.sig.hash
tag.
The Query Signature, is defined as the tuple of the GraphQL AST Signature of the GraphQL Document and the Query Signature Hash. The signature of a query is defined as follows:
A canonical AST which removes excess operations, removes any field aliases,
hides literal values and sorts the result into a canonical query
Ref graphql-java
The Query Signature Hash is the Hex 256 SHA string produced by encoding the Query Signature. While we can't tag a metric by the Query Signature due its length, we can use the Query Signature Hash as now expressed by the gql.query.sig.hash
tag.
management.metrics.dgs-graphql.query-signature.enabled
: If true
it will enable the calculation of GQL Query Signature. This will enable the tagging of gql
metrics with the gql.query.sig.hash
. A QuerySignatureRepositor
component will also be available for container injection. It will be able to resolve a Document
and InstrumentationExecutionParameters
tuple to the QuerySignature
. This can be useful if you want to leverage such object to add additional information to your Logs, Tracing Spans, etc.
management.metrics.dgs-graphql.query-signature.caching.enabled
: By default the calculation of the signature will be cached. You can turn this off
by setting this property to false
. Note that this will not turn the calculation of the signature off, it will just disable the cache. If you want to turn it off use management.metrics.dgs-graphql.query-signature.enabled
.
management.metrics.dgs-graphql.tags.limiter.limit
: Defaults to100
, sets the cardinality limit for the values of the gql.query.sig.hash
and gql.operation.name
tags. This limits the number of different values expressed in such tag, protecting the backing metric service form a cardinality explosion. The cardinality limit is per tag.
DGS Entity Fetchers can now return null instead of creating an empty object that represents an entity. Previously, this would result in a DGSEntityNotFoundException
with the following result, which was not compliant with federation spec:
{
"errors": [
{
"message": "com.netflix.graphql.dgs.exceptions.MissingDgsEntityFetcherException: Missing @DgsEntityFetcher for type Movie",
"locations": [],
"path": [
"_entities"
],
"extensions": {
"errorType": "INTERNAL"
}
}
],
data: null
The implementation is now returning the expected null entities array, for valid use cases where null data is expected :
{
"data": {
"_entities": [
null
]
}
}
We are also improving the handling of exceptions such that it allows us to return partial results. The exceptions errors are now populated for each entity as part of the error data in the result, along with an empty entities array as data. Previously, partial results were not being returned in case of exceptions. We can now get partial results along with the errors:
{
"errors": [
{
"message": "java.lang.RuntimeException: Test entity exception",
"locations": [],
"path": [
"_entities"
],
"extensions": {
"errorType": "INTERNAL"
}
}
],
"data": {
"_entities": [
{
"__typename": "Movie",
"movieId": 1133,
"fakeReviews": {
"pageInfo": {
"hasPreviousPage": false
}
}
},
null,
]
}
}
Published by github-actions[bot] over 3 years ago
MetricsInstrumentationState.tags
method. (#390) @berngp