⚠️ DisclaimerAutoGuru no longer use graphql-dotnet in our GraphQL stack.
As such we're no longer actively maintaining it ourselves.
This library provides useful bits for graphql-dotnet based servers to add relay support.
Relay requires that:
- all queryable types in your graph implement a base type
Node
, and - are queryable via query fields of form
node(id: ID!)
andnodes(ids: [ID!]!)
.
We offer two classes to make this easy for you.
Use this as the base for your root query
field you attach to your schema and
It'll add the node
and nodes
fields mentioned above.
Use this as the base for your own types, instead of ObjectGraphType<TSourceType>
and
it'll add two fields, id
and dbId
(where id
is the Relay-spec compliant field required by all Node
types,
and dbId
is your own internal id for that type, that you may need for displaying in your UI).
Although an ID
is great for Relay, it's not great for humans or for use in our internal code.
Furthermore, once you jump on the Relay train, you'll want to replace all your id-referencing field arguments with ID!
That causes a few issues:
- How can I query for data when dev'ing without first getting the global ID?
- Similarly, I want my website's URLs to contain my friendlier id, like /blog/1, how can I call graph with that without first translating that into a global ID?
- How can I migrate to Relay support gradually without all my clients breaking by passing
1
or"1"
? - How can I deserialize a global
ID
in my resolver to a value I understand internally to resolve my data?
To make this easier, we:
- Hookup wiring to support parsing
string
orTId
into aID
, so you can safely pass "1" or1
in place of a real globalID
. - Provide extension methods you can use in your resolver to read global
ID
s into the real id you know and love.
There's also a GlobalIdParser
if you ever need to work with global IDs yourself.
We offer some built-in types for variations of global IDs (e.g. GuidGlobalId
, IntGlobalId
, LongGlobalId
, StringGlobalId
)
so that you can read a complex field argument as a DTO class and use properties like IntGlobalId
.
If you're using AutoMapper to translate between say an InputDto
and another type,
you can have a DTO with a IntGlobalId
property and map that to a type with an int
property.
Similar to above but for NewtonsoftJson. Call JsonSerializerFactory.Create()
to get a serializer that can read/write
these ID-types into the equivalent BCL type to work with. Or use them like you would any other
Newtonsoft.Json converter.
If you're using FluentValidation, you can validate a strongly-typed global ID class's value like so:
RuleFor(x => x.Id).ValidGlobalId()
WIP
Note: Versions 1.x are for GraphQL 2.4.0. Versions 2.x are for GraphQL 3.0.0-preview-x
Install from NuGet:
> dotnet add package GraphQL.RelaySupport
> dotnet add package GraphQL.RelaySupport.AutoMapped
> dotnet add package GraphQL.RelaySupport.FluentValidation
> dotnet add package GraphQL.RelaySupport.NewtonsoftJson
> dotnet add package GraphQL.RelaySupport.Core
In your Startup.cs
:
- Call
services.AddRelaySupport();
- For AutoMapper support, include our profile when registering it,
services.AddAutoMapper(..., typeof(GlobalIdsProfile))
Update your root Query type to inherit from QueryGraphType
.
For each of your relevant graph types:
- Inherit from
NodeGraphType<TSourceType, TId>
, specifyingTId
as the type you use internally, e.g.int
. - Call base constructor, passing an
idSelector
func, e.g.myType => myType.Id
. - Implement the abstract
GetByIdAsync
method, which will receive the real database id of your type.
In your field resolvers:
- If you want an id/s argument, use
context.GetIntIdFromGlobalIdArgument("argName")
or relevant overload. - If you want a complex argument, use standard
context.GetArgument<T>
fromGraphQL
project, but use the strongly-typedID
classes on your propeties where needed.
MIT © AutoGuru