Repository files navigation

dotnet GraphQL Query generator

Given a GraphQL schema file (or a GraphQL endpoint where we can do a schema introspection), this tool will generate interfaces and classes to enable strongly typed querying from C# to a GraphQL API.

Example GraphQL schema

schema {
query: Query
mutation: Mutation
}
scalar Date
type Query {
actors: [Person]
directors: [Person]
movie(id: Int!): Movie
movies: [Movie]
}
type Movie {
id: Int
name: String
genre: Int
released: Date
actors: [Person]
writers: [Person]
director: Person
rating: Float
}
type Person {
id: Int
dob: Date
actorIn: [Movie]
writerOf: [Movie]
directorOf: [Movie]
died: Date
age: Int
name: String
}
type Mutation {
addPerson(dob: Date!, name: String!): Person
}

Query Generator Command

To generate from a graphql schema file:
dotnet run -- schema.graphql -m Date=DateTime

To generate from a live GraphQL server (note: introspection may not be supported or enabled on your server):
dotnet run -- http://myapi.app/gql -m Date=DateTime -h "Authorization=Bearer eyAfd..."

For all command line options, use --help or -?

Both commands will generate the files GraphQLClient.cs and GeneratedTypes.cs.

GeneratedTypes.cs

Based on the example schema.graphql the GeneratedTypes.cs file will have the following content:

publicinterfaceRootQuery{[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("directors")]List<Person>Directors();[GqlFieldName("directors")]List<TReturn>Directors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("movie")]MovieMovie();[GqlFieldName("movie")]TReturnMovie<TReturn>(intid,Expression<Func<Movie,TReturn>>selection);[GqlFieldName("movies")]List<Movie>Movies();[GqlFieldName("movies")]List<TReturn>Movies<TReturn>(Expression<Func<Movie,TReturn>>selection);}publicinterfaceMovie{[GqlFieldName("id")]intId{get;}[GqlFieldName("name")]stringName{get;}[GqlFieldName("genre")]intGenre{get;}[GqlFieldName("released")]DateTimeReleased{get;}[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("writers")]List<Person>Writers();[GqlFieldName("writers")]List<TReturn>Writers<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("director")]PersonDirector();[GqlFieldName("director")]TReturnDirector<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("rating")]doubleRating{get;}}publicinterfacePerson{[GqlFieldName("id")]intId{get;}[GqlFieldName("dob")]DateTimeDob{get;}[GqlFieldName("actorIn")]List<Movie>ActorIn();[GqlFieldName("actorIn")]List<TReturn>ActorIn<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("writerOf")]List<Movie>WriterOf();[GqlFieldName("writerOf")]List<TReturn>WriterOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("directorOf")]List<Movie>DirectorOf();[GqlFieldName("directorOf")]List<TReturn>DirectorOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("died")]DateTimeDied{get;}[GqlFieldName("age")]intAge{get;}[GqlFieldName("name")]stringName{get;}}publicinterfaceMutation{[GqlFieldName("addPerson")]TReturnAddPerson<TReturn>(DateTimedob,stringname,Expression<Func<Person,TReturn>>selection);}

GraphQLClient.cs

The generated GraphQLClient class instance acts as a session to send GraphQL requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/gql")};varclient=newGraphQLClient(httpClient);

For custom headers like Authorization, configure them in the HttpClient. These will be used during the requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/")};httpClient.DefaultRequestHeaders.Authorization=newAuthenticationHeaderValue("Bearer","eyAf3s...");varclient=newGraphQLClient(newUri("gql",UriKind.Relative),httpClient);

To use the GraphQLClient, copy the following files into your project. These will all be in the output folder:

  1. GraphQLClient.cs - a simple client you can modify or extend
  2. GeneratedResultTypes.cs - generated types from the schema
  3. GeneratedQueryTypes.cs - extensions to allow the linq style querying
  4. BaseGraphQLClient.cs - a base client that GraphQLClient inherits from
  5. GqlFieldNameAttribute.cs - required by the generated code

Ideally move this to a dependency style library and tool in the future.

Request Methods

GraphQLClient exposes 2 methods:

  • Query
    async Task<GqlResult<TQuery>> QueryAsync<TQuery>(Expression<Func<RootQuery, TQuery>> query)
  • Mutation
    async Task<GqlResult<TQuery>> MutateAsync<TQuery>(Expression<Func<Mutation, TQuery>> query)

Query

// queriesvarresult=awaitclient.QueryAsync(q =>new{Movie=q.Movie(2, m =>new{m.Id,m.Name,ReleaseDate=m.Released,Director=m.Director(d =>new{d.Name})}),Actors=q.Actors(a =>new{a.Name,a.Dob})});

This looks similar to the GraphQL. And now result.Data is a strongly type object with the expected types.

If a field in the schema is an object (can have a selection performed on it) it will be exposed in the generated code as a method where you pass in any field arguments first and then the selection.

The GraphQL created by the above will look like this:

{
query {
Movie: movie(id: 2) {
Id: id
Name: name
ReleaseDate: released
Director: director {
Name: name
}
}
Actors: actors {
Name: name
Dob: dob
}
}
}

Mutations

Mutations look very similar to the above query, just as they do in GraphQL. The above schema had one mutation that can be called like so

// mutationsvarmutationResult=awaitclient.MutateAsync(m =>new{NewPerson=m.AddPerson(newDateTime(1801,7,3),"John Johny", p =>new{p.Id})});

m is the Mutation type interface and lets you call any of the mutations generated from the schema. Like a query, you create a new anonymous object and call as many mutations as you wish. Each mutation method has all their arguments and the last one is a selection query on the mutation's return type.

The above has mutationResult strongly typed. E.g. mutationResult.Data.NewPerson will only have an Id field.

Input types

Any input types are generated as actual classes as the are used as arguments. The -m Date=DateTime tells the tool that the scalar type Date should be the DateTime type in C#. You can use this to support any other custom scalar types. E.g. -m Date=DateTime;Point=PointF, just comma separate a GqlScalar=DotnetType list.

About

Generate dotnet interfaces/classes from a GraphQL schema to perform type-safe querying from dotnet

Resources

Stars

78 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

dotnet GraphQL Query generator

Given a GraphQL schema file (or a GraphQL endpoint where we can do a schema introspection), this tool will generate interfaces and classes to enable strongly typed querying from C# to a GraphQL API.

Example GraphQL schema

schema {
query: Query
mutation: Mutation
}
scalar Date
type Query {
actors: [Person]
directors: [Person]
movie(id: Int!): Movie
movies: [Movie]
}
type Movie {
id: Int
name: String
genre: Int
released: Date
actors: [Person]
writers: [Person]
director: Person
rating: Float
}
type Person {
id: Int
dob: Date
actorIn: [Movie]
writerOf: [Movie]
directorOf: [Movie]
died: Date
age: Int
name: String
}
type Mutation {
addPerson(dob: Date!, name: String!): Person
}

Query Generator Command

To generate from a graphql schema file:
dotnet run -- schema.graphql -m Date=DateTime

To generate from a live GraphQL server (note: introspection may not be supported or enabled on your server):
dotnet run -- http://myapi.app/gql -m Date=DateTime -h "Authorization=Bearer eyAfd..."

For all command line options, use --help or -?

Both commands will generate the files GraphQLClient.cs and GeneratedTypes.cs.

GeneratedTypes.cs

Based on the example schema.graphql the GeneratedTypes.cs file will have the following content:

publicinterfaceRootQuery{[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("directors")]List<Person>Directors();[GqlFieldName("directors")]List<TReturn>Directors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("movie")]MovieMovie();[GqlFieldName("movie")]TReturnMovie<TReturn>(intid,Expression<Func<Movie,TReturn>>selection);[GqlFieldName("movies")]List<Movie>Movies();[GqlFieldName("movies")]List<TReturn>Movies<TReturn>(Expression<Func<Movie,TReturn>>selection);}publicinterfaceMovie{[GqlFieldName("id")]intId{get;}[GqlFieldName("name")]stringName{get;}[GqlFieldName("genre")]intGenre{get;}[GqlFieldName("released")]DateTimeReleased{get;}[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("writers")]List<Person>Writers();[GqlFieldName("writers")]List<TReturn>Writers<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("director")]PersonDirector();[GqlFieldName("director")]TReturnDirector<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("rating")]doubleRating{get;}}publicinterfacePerson{[GqlFieldName("id")]intId{get;}[GqlFieldName("dob")]DateTimeDob{get;}[GqlFieldName("actorIn")]List<Movie>ActorIn();[GqlFieldName("actorIn")]List<TReturn>ActorIn<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("writerOf")]List<Movie>WriterOf();[GqlFieldName("writerOf")]List<TReturn>WriterOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("directorOf")]List<Movie>DirectorOf();[GqlFieldName("directorOf")]List<TReturn>DirectorOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("died")]DateTimeDied{get;}[GqlFieldName("age")]intAge{get;}[GqlFieldName("name")]stringName{get;}}publicinterfaceMutation{[GqlFieldName("addPerson")]TReturnAddPerson<TReturn>(DateTimedob,stringname,Expression<Func<Person,TReturn>>selection);}

GraphQLClient.cs

The generated GraphQLClient class instance acts as a session to send GraphQL requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/gql")};varclient=newGraphQLClient(httpClient);

For custom headers like Authorization, configure them in the HttpClient. These will be used during the requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/")};httpClient.DefaultRequestHeaders.Authorization=newAuthenticationHeaderValue("Bearer","eyAf3s...");varclient=newGraphQLClient(newUri("gql",UriKind.Relative),httpClient);

To use the GraphQLClient, copy the following files into your project. These will all be in the output folder:

  1. GraphQLClient.cs - a simple client you can modify or extend
  2. GeneratedResultTypes.cs - generated types from the schema
  3. GeneratedQueryTypes.cs - extensions to allow the linq style querying
  4. BaseGraphQLClient.cs - a base client that GraphQLClient inherits from
  5. GqlFieldNameAttribute.cs - required by the generated code

Ideally move this to a dependency style library and tool in the future.

Request Methods

GraphQLClient exposes 2 methods:

  • Query
    async Task<GqlResult<TQuery>> QueryAsync<TQuery>(Expression<Func<RootQuery, TQuery>> query)
  • Mutation
    async Task<GqlResult<TQuery>> MutateAsync<TQuery>(Expression<Func<Mutation, TQuery>> query)

Query

// queriesvarresult=awaitclient.QueryAsync(q =>new{Movie=q.Movie(2, m =>new{m.Id,m.Name,ReleaseDate=m.Released,Director=m.Director(d =>new{d.Name})}),Actors=q.Actors(a =>new{a.Name,a.Dob})});

This looks similar to the GraphQL. And now result.Data is a strongly type object with the expected types.

If a field in the schema is an object (can have a selection performed on it) it will be exposed in the generated code as a method where you pass in any field arguments first and then the selection.

The GraphQL created by the above will look like this:

{
query {
Movie: movie(id: 2) {
Id: id
Name: name
ReleaseDate: released
Director: director {
Name: name
}
}
Actors: actors {
Name: name
Dob: dob
}
}
}

Mutations

Mutations look very similar to the above query, just as they do in GraphQL. The above schema had one mutation that can be called like so

// mutationsvarmutationResult=awaitclient.MutateAsync(m =>new{NewPerson=m.AddPerson(newDateTime(1801,7,3),"John Johny", p =>new{p.Id})});

m is the Mutation type interface and lets you call any of the mutations generated from the schema. Like a query, you create a new anonymous object and call as many mutations as you wish. Each mutation method has all their arguments and the last one is a selection query on the mutation's return type.

The above has mutationResult strongly typed. E.g. mutationResult.Data.NewPerson will only have an Id field.

Input types

Any input types are generated as actual classes as the are used as arguments. The -m Date=DateTime tells the tool that the scalar type Date should be the DateTime type in C#. You can use this to support any other custom scalar types. E.g. -m Date=DateTime;Point=PointF, just comma separate a GqlScalar=DotnetType list.

About

Generate dotnet interfaces/classes from a GraphQL schema to perform type-safe querying from dotnet

Resources

Stars

78 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

dotnet GraphQL Query generator

Given a GraphQL schema file (or a GraphQL endpoint where we can do a schema introspection), this tool will generate interfaces and classes to enable strongly typed querying from C# to a GraphQL API.

Example GraphQL schema

schema {
query: Query
mutation: Mutation
}
scalar Date
type Query {
actors: [Person]
directors: [Person]
movie(id: Int!): Movie
movies: [Movie]
}
type Movie {
id: Int
name: String
genre: Int
released: Date
actors: [Person]
writers: [Person]
director: Person
rating: Float
}
type Person {
id: Int
dob: Date
actorIn: [Movie]
writerOf: [Movie]
directorOf: [Movie]
died: Date
age: Int
name: String
}
type Mutation {
addPerson(dob: Date!, name: String!): Person
}

Query Generator Command

To generate from a graphql schema file:
dotnet run -- schema.graphql -m Date=DateTime

To generate from a live GraphQL server (note: introspection may not be supported or enabled on your server):
dotnet run -- http://myapi.app/gql -m Date=DateTime -h "Authorization=Bearer eyAfd..."

For all command line options, use --help or -?

Both commands will generate the files GraphQLClient.cs and GeneratedTypes.cs.

GeneratedTypes.cs

Based on the example schema.graphql the GeneratedTypes.cs file will have the following content:

publicinterfaceRootQuery{[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("directors")]List<Person>Directors();[GqlFieldName("directors")]List<TReturn>Directors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("movie")]MovieMovie();[GqlFieldName("movie")]TReturnMovie<TReturn>(intid,Expression<Func<Movie,TReturn>>selection);[GqlFieldName("movies")]List<Movie>Movies();[GqlFieldName("movies")]List<TReturn>Movies<TReturn>(Expression<Func<Movie,TReturn>>selection);}publicinterfaceMovie{[GqlFieldName("id")]intId{get;}[GqlFieldName("name")]stringName{get;}[GqlFieldName("genre")]intGenre{get;}[GqlFieldName("released")]DateTimeReleased{get;}[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("writers")]List<Person>Writers();[GqlFieldName("writers")]List<TReturn>Writers<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("director")]PersonDirector();[GqlFieldName("director")]TReturnDirector<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("rating")]doubleRating{get;}}publicinterfacePerson{[GqlFieldName("id")]intId{get;}[GqlFieldName("dob")]DateTimeDob{get;}[GqlFieldName("actorIn")]List<Movie>ActorIn();[GqlFieldName("actorIn")]List<TReturn>ActorIn<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("writerOf")]List<Movie>WriterOf();[GqlFieldName("writerOf")]List<TReturn>WriterOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("directorOf")]List<Movie>DirectorOf();[GqlFieldName("directorOf")]List<TReturn>DirectorOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("died")]DateTimeDied{get;}[GqlFieldName("age")]intAge{get;}[GqlFieldName("name")]stringName{get;}}publicinterfaceMutation{[GqlFieldName("addPerson")]TReturnAddPerson<TReturn>(DateTimedob,stringname,Expression<Func<Person,TReturn>>selection);}

GraphQLClient.cs

The generated GraphQLClient class instance acts as a session to send GraphQL requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/gql")};varclient=newGraphQLClient(httpClient);

For custom headers like Authorization, configure them in the HttpClient. These will be used during the requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/")};httpClient.DefaultRequestHeaders.Authorization=newAuthenticationHeaderValue("Bearer","eyAf3s...");varclient=newGraphQLClient(newUri("gql",UriKind.Relative),httpClient);

To use the GraphQLClient, copy the following files into your project. These will all be in the output folder:

  1. GraphQLClient.cs - a simple client you can modify or extend
  2. GeneratedResultTypes.cs - generated types from the schema
  3. GeneratedQueryTypes.cs - extensions to allow the linq style querying
  4. BaseGraphQLClient.cs - a base client that GraphQLClient inherits from
  5. GqlFieldNameAttribute.cs - required by the generated code

Ideally move this to a dependency style library and tool in the future.

Request Methods

GraphQLClient exposes 2 methods:

  • Query
    async Task<GqlResult<TQuery>> QueryAsync<TQuery>(Expression<Func<RootQuery, TQuery>> query)
  • Mutation
    async Task<GqlResult<TQuery>> MutateAsync<TQuery>(Expression<Func<Mutation, TQuery>> query)

Query

// queriesvarresult=awaitclient.QueryAsync(q =>new{Movie=q.Movie(2, m =>new{m.Id,m.Name,ReleaseDate=m.Released,Director=m.Director(d =>new{d.Name})}),Actors=q.Actors(a =>new{a.Name,a.Dob})});

This looks similar to the GraphQL. And now result.Data is a strongly type object with the expected types.

If a field in the schema is an object (can have a selection performed on it) it will be exposed in the generated code as a method where you pass in any field arguments first and then the selection.

The GraphQL created by the above will look like this:

{
query {
Movie: movie(id: 2) {
Id: id
Name: name
ReleaseDate: released
Director: director {
Name: name
}
}
Actors: actors {
Name: name
Dob: dob
}
}
}

Mutations

Mutations look very similar to the above query, just as they do in GraphQL. The above schema had one mutation that can be called like so

// mutationsvarmutationResult=awaitclient.MutateAsync(m =>new{NewPerson=m.AddPerson(newDateTime(1801,7,3),"John Johny", p =>new{p.Id})});

m is the Mutation type interface and lets you call any of the mutations generated from the schema. Like a query, you create a new anonymous object and call as many mutations as you wish. Each mutation method has all their arguments and the last one is a selection query on the mutation's return type.

The above has mutationResult strongly typed. E.g. mutationResult.Data.NewPerson will only have an Id field.

Input types

Any input types are generated as actual classes as the are used as arguments. The -m Date=DateTime tells the tool that the scalar type Date should be the DateTime type in C#. You can use this to support any other custom scalar types. E.g. -m Date=DateTime;Point=PointF, just comma separate a GqlScalar=DotnetType list.

About

Generate dotnet interfaces/classes from a GraphQL schema to perform type-safe querying from dotnet

Resources

Stars

78 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

dotnet GraphQL Query generator

Given a GraphQL schema file (or a GraphQL endpoint where we can do a schema introspection), this tool will generate interfaces and classes to enable strongly typed querying from C# to a GraphQL API.

Example GraphQL schema

schema {
query: Query
mutation: Mutation
}
scalar Date
type Query {
actors: [Person]
directors: [Person]
movie(id: Int!): Movie
movies: [Movie]
}
type Movie {
id: Int
name: String
genre: Int
released: Date
actors: [Person]
writers: [Person]
director: Person
rating: Float
}
type Person {
id: Int
dob: Date
actorIn: [Movie]
writerOf: [Movie]
directorOf: [Movie]
died: Date
age: Int
name: String
}
type Mutation {
addPerson(dob: Date!, name: String!): Person
}

Query Generator Command

To generate from a graphql schema file:
dotnet run -- schema.graphql -m Date=DateTime

To generate from a live GraphQL server (note: introspection may not be supported or enabled on your server):
dotnet run -- http://myapi.app/gql -m Date=DateTime -h "Authorization=Bearer eyAfd..."

For all command line options, use --help or -?

Both commands will generate the files GraphQLClient.cs and GeneratedTypes.cs.

GeneratedTypes.cs

Based on the example schema.graphql the GeneratedTypes.cs file will have the following content:

publicinterfaceRootQuery{[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("directors")]List<Person>Directors();[GqlFieldName("directors")]List<TReturn>Directors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("movie")]MovieMovie();[GqlFieldName("movie")]TReturnMovie<TReturn>(intid,Expression<Func<Movie,TReturn>>selection);[GqlFieldName("movies")]List<Movie>Movies();[GqlFieldName("movies")]List<TReturn>Movies<TReturn>(Expression<Func<Movie,TReturn>>selection);}publicinterfaceMovie{[GqlFieldName("id")]intId{get;}[GqlFieldName("name")]stringName{get;}[GqlFieldName("genre")]intGenre{get;}[GqlFieldName("released")]DateTimeReleased{get;}[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("writers")]List<Person>Writers();[GqlFieldName("writers")]List<TReturn>Writers<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("director")]PersonDirector();[GqlFieldName("director")]TReturnDirector<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("rating")]doubleRating{get;}}publicinterfacePerson{[GqlFieldName("id")]intId{get;}[GqlFieldName("dob")]DateTimeDob{get;}[GqlFieldName("actorIn")]List<Movie>ActorIn();[GqlFieldName("actorIn")]List<TReturn>ActorIn<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("writerOf")]List<Movie>WriterOf();[GqlFieldName("writerOf")]List<TReturn>WriterOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("directorOf")]List<Movie>DirectorOf();[GqlFieldName("directorOf")]List<TReturn>DirectorOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("died")]DateTimeDied{get;}[GqlFieldName("age")]intAge{get;}[GqlFieldName("name")]stringName{get;}}publicinterfaceMutation{[GqlFieldName("addPerson")]TReturnAddPerson<TReturn>(DateTimedob,stringname,Expression<Func<Person,TReturn>>selection);}

GraphQLClient.cs

The generated GraphQLClient class instance acts as a session to send GraphQL requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/gql")};varclient=newGraphQLClient(httpClient);

For custom headers like Authorization, configure them in the HttpClient. These will be used during the requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/")};httpClient.DefaultRequestHeaders.Authorization=newAuthenticationHeaderValue("Bearer","eyAf3s...");varclient=newGraphQLClient(newUri("gql",UriKind.Relative),httpClient);

To use the GraphQLClient, copy the following files into your project. These will all be in the output folder:

  1. GraphQLClient.cs - a simple client you can modify or extend
  2. GeneratedResultTypes.cs - generated types from the schema
  3. GeneratedQueryTypes.cs - extensions to allow the linq style querying
  4. BaseGraphQLClient.cs - a base client that GraphQLClient inherits from
  5. GqlFieldNameAttribute.cs - required by the generated code

Ideally move this to a dependency style library and tool in the future.

Request Methods

GraphQLClient exposes 2 methods:

  • Query
    async Task<GqlResult<TQuery>> QueryAsync<TQuery>(Expression<Func<RootQuery, TQuery>> query)
  • Mutation
    async Task<GqlResult<TQuery>> MutateAsync<TQuery>(Expression<Func<Mutation, TQuery>> query)

Query

// queriesvarresult=awaitclient.QueryAsync(q =>new{Movie=q.Movie(2, m =>new{m.Id,m.Name,ReleaseDate=m.Released,Director=m.Director(d =>new{d.Name})}),Actors=q.Actors(a =>new{a.Name,a.Dob})});

This looks similar to the GraphQL. And now result.Data is a strongly type object with the expected types.

If a field in the schema is an object (can have a selection performed on it) it will be exposed in the generated code as a method where you pass in any field arguments first and then the selection.

The GraphQL created by the above will look like this:

{
query {
Movie: movie(id: 2) {
Id: id
Name: name
ReleaseDate: released
Director: director {
Name: name
}
}
Actors: actors {
Name: name
Dob: dob
}
}
}

Mutations

Mutations look very similar to the above query, just as they do in GraphQL. The above schema had one mutation that can be called like so

// mutationsvarmutationResult=awaitclient.MutateAsync(m =>new{NewPerson=m.AddPerson(newDateTime(1801,7,3),"John Johny", p =>new{p.Id})});

m is the Mutation type interface and lets you call any of the mutations generated from the schema. Like a query, you create a new anonymous object and call as many mutations as you wish. Each mutation method has all their arguments and the last one is a selection query on the mutation's return type.

The above has mutationResult strongly typed. E.g. mutationResult.Data.NewPerson will only have an Id field.

Input types

Any input types are generated as actual classes as the are used as arguments. The -m Date=DateTime tells the tool that the scalar type Date should be the DateTime type in C#. You can use this to support any other custom scalar types. E.g. -m Date=DateTime;Point=PointF, just comma separate a GqlScalar=DotnetType list.

About

Generate dotnet interfaces/classes from a GraphQL schema to perform type-safe querying from dotnet

Resources

Stars

78 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

dotnet GraphQL Query generator

Given a GraphQL schema file (or a GraphQL endpoint where we can do a schema introspection), this tool will generate interfaces and classes to enable strongly typed querying from C# to a GraphQL API.

Example GraphQL schema

schema {
query: Query
mutation: Mutation
}
scalar Date
type Query {
actors: [Person]
directors: [Person]
movie(id: Int!): Movie
movies: [Movie]
}
type Movie {
id: Int
name: String
genre: Int
released: Date
actors: [Person]
writers: [Person]
director: Person
rating: Float
}
type Person {
id: Int
dob: Date
actorIn: [Movie]
writerOf: [Movie]
directorOf: [Movie]
died: Date
age: Int
name: String
}
type Mutation {
addPerson(dob: Date!, name: String!): Person
}

Query Generator Command

To generate from a graphql schema file:
dotnet run -- schema.graphql -m Date=DateTime

To generate from a live GraphQL server (note: introspection may not be supported or enabled on your server):
dotnet run -- http://myapi.app/gql -m Date=DateTime -h "Authorization=Bearer eyAfd..."

For all command line options, use --help or -?

Both commands will generate the files GraphQLClient.cs and GeneratedTypes.cs.

GeneratedTypes.cs

Based on the example schema.graphql the GeneratedTypes.cs file will have the following content:

publicinterfaceRootQuery{[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("directors")]List<Person>Directors();[GqlFieldName("directors")]List<TReturn>Directors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("movie")]MovieMovie();[GqlFieldName("movie")]TReturnMovie<TReturn>(intid,Expression<Func<Movie,TReturn>>selection);[GqlFieldName("movies")]List<Movie>Movies();[GqlFieldName("movies")]List<TReturn>Movies<TReturn>(Expression<Func<Movie,TReturn>>selection);}publicinterfaceMovie{[GqlFieldName("id")]intId{get;}[GqlFieldName("name")]stringName{get;}[GqlFieldName("genre")]intGenre{get;}[GqlFieldName("released")]DateTimeReleased{get;}[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("writers")]List<Person>Writers();[GqlFieldName("writers")]List<TReturn>Writers<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("director")]PersonDirector();[GqlFieldName("director")]TReturnDirector<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("rating")]doubleRating{get;}}publicinterfacePerson{[GqlFieldName("id")]intId{get;}[GqlFieldName("dob")]DateTimeDob{get;}[GqlFieldName("actorIn")]List<Movie>ActorIn();[GqlFieldName("actorIn")]List<TReturn>ActorIn<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("writerOf")]List<Movie>WriterOf();[GqlFieldName("writerOf")]List<TReturn>WriterOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("directorOf")]List<Movie>DirectorOf();[GqlFieldName("directorOf")]List<TReturn>DirectorOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("died")]DateTimeDied{get;}[GqlFieldName("age")]intAge{get;}[GqlFieldName("name")]stringName{get;}}publicinterfaceMutation{[GqlFieldName("addPerson")]TReturnAddPerson<TReturn>(DateTimedob,stringname,Expression<Func<Person,TReturn>>selection);}

GraphQLClient.cs

The generated GraphQLClient class instance acts as a session to send GraphQL requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/gql")};varclient=newGraphQLClient(httpClient);

For custom headers like Authorization, configure them in the HttpClient. These will be used during the requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/")};httpClient.DefaultRequestHeaders.Authorization=newAuthenticationHeaderValue("Bearer","eyAf3s...");varclient=newGraphQLClient(newUri("gql",UriKind.Relative),httpClient);

To use the GraphQLClient, copy the following files into your project. These will all be in the output folder:

  1. GraphQLClient.cs - a simple client you can modify or extend
  2. GeneratedResultTypes.cs - generated types from the schema
  3. GeneratedQueryTypes.cs - extensions to allow the linq style querying
  4. BaseGraphQLClient.cs - a base client that GraphQLClient inherits from
  5. GqlFieldNameAttribute.cs - required by the generated code

Ideally move this to a dependency style library and tool in the future.

Request Methods

GraphQLClient exposes 2 methods:

  • Query
    async Task<GqlResult<TQuery>> QueryAsync<TQuery>(Expression<Func<RootQuery, TQuery>> query)
  • Mutation
    async Task<GqlResult<TQuery>> MutateAsync<TQuery>(Expression<Func<Mutation, TQuery>> query)

Query

// queriesvarresult=awaitclient.QueryAsync(q =>new{Movie=q.Movie(2, m =>new{m.Id,m.Name,ReleaseDate=m.Released,Director=m.Director(d =>new{d.Name})}),Actors=q.Actors(a =>new{a.Name,a.Dob})});

This looks similar to the GraphQL. And now result.Data is a strongly type object with the expected types.

If a field in the schema is an object (can have a selection performed on it) it will be exposed in the generated code as a method where you pass in any field arguments first and then the selection.

The GraphQL created by the above will look like this:

{
query {
Movie: movie(id: 2) {
Id: id
Name: name
ReleaseDate: released
Director: director {
Name: name
}
}
Actors: actors {
Name: name
Dob: dob
}
}
}

Mutations

Mutations look very similar to the above query, just as they do in GraphQL. The above schema had one mutation that can be called like so

// mutationsvarmutationResult=awaitclient.MutateAsync(m =>new{NewPerson=m.AddPerson(newDateTime(1801,7,3),"John Johny", p =>new{p.Id})});

m is the Mutation type interface and lets you call any of the mutations generated from the schema. Like a query, you create a new anonymous object and call as many mutations as you wish. Each mutation method has all their arguments and the last one is a selection query on the mutation's return type.

The above has mutationResult strongly typed. E.g. mutationResult.Data.NewPerson will only have an Id field.

Input types

Any input types are generated as actual classes as the are used as arguments. The -m Date=DateTime tells the tool that the scalar type Date should be the DateTime type in C#. You can use this to support any other custom scalar types. E.g. -m Date=DateTime;Point=PointF, just comma separate a GqlScalar=DotnetType list.

About

Generate dotnet interfaces/classes from a GraphQL schema to perform type-safe querying from dotnet

Resources

Stars

78 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

dotnet GraphQL Query generator

Given a GraphQL schema file (or a GraphQL endpoint where we can do a schema introspection), this tool will generate interfaces and classes to enable strongly typed querying from C# to a GraphQL API.

Example GraphQL schema

schema {
query: Query
mutation: Mutation
}
scalar Date
type Query {
actors: [Person]
directors: [Person]
movie(id: Int!): Movie
movies: [Movie]
}
type Movie {
id: Int
name: String
genre: Int
released: Date
actors: [Person]
writers: [Person]
director: Person
rating: Float
}
type Person {
id: Int
dob: Date
actorIn: [Movie]
writerOf: [Movie]
directorOf: [Movie]
died: Date
age: Int
name: String
}
type Mutation {
addPerson(dob: Date!, name: String!): Person
}

Query Generator Command

To generate from a graphql schema file:
dotnet run -- schema.graphql -m Date=DateTime

To generate from a live GraphQL server (note: introspection may not be supported or enabled on your server):
dotnet run -- http://myapi.app/gql -m Date=DateTime -h "Authorization=Bearer eyAfd..."

For all command line options, use --help or -?

Both commands will generate the files GraphQLClient.cs and GeneratedTypes.cs.

GeneratedTypes.cs

Based on the example schema.graphql the GeneratedTypes.cs file will have the following content:

publicinterfaceRootQuery{[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("directors")]List<Person>Directors();[GqlFieldName("directors")]List<TReturn>Directors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("movie")]MovieMovie();[GqlFieldName("movie")]TReturnMovie<TReturn>(intid,Expression<Func<Movie,TReturn>>selection);[GqlFieldName("movies")]List<Movie>Movies();[GqlFieldName("movies")]List<TReturn>Movies<TReturn>(Expression<Func<Movie,TReturn>>selection);}publicinterfaceMovie{[GqlFieldName("id")]intId{get;}[GqlFieldName("name")]stringName{get;}[GqlFieldName("genre")]intGenre{get;}[GqlFieldName("released")]DateTimeReleased{get;}[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("writers")]List<Person>Writers();[GqlFieldName("writers")]List<TReturn>Writers<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("director")]PersonDirector();[GqlFieldName("director")]TReturnDirector<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("rating")]doubleRating{get;}}publicinterfacePerson{[GqlFieldName("id")]intId{get;}[GqlFieldName("dob")]DateTimeDob{get;}[GqlFieldName("actorIn")]List<Movie>ActorIn();[GqlFieldName("actorIn")]List<TReturn>ActorIn<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("writerOf")]List<Movie>WriterOf();[GqlFieldName("writerOf")]List<TReturn>WriterOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("directorOf")]List<Movie>DirectorOf();[GqlFieldName("directorOf")]List<TReturn>DirectorOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("died")]DateTimeDied{get;}[GqlFieldName("age")]intAge{get;}[GqlFieldName("name")]stringName{get;}}publicinterfaceMutation{[GqlFieldName("addPerson")]TReturnAddPerson<TReturn>(DateTimedob,stringname,Expression<Func<Person,TReturn>>selection);}

GraphQLClient.cs

The generated GraphQLClient class instance acts as a session to send GraphQL requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/gql")};varclient=newGraphQLClient(httpClient);

For custom headers like Authorization, configure them in the HttpClient. These will be used during the requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/")};httpClient.DefaultRequestHeaders.Authorization=newAuthenticationHeaderValue("Bearer","eyAf3s...");varclient=newGraphQLClient(newUri("gql",UriKind.Relative),httpClient);

To use the GraphQLClient, copy the following files into your project. These will all be in the output folder:

  1. GraphQLClient.cs - a simple client you can modify or extend
  2. GeneratedResultTypes.cs - generated types from the schema
  3. GeneratedQueryTypes.cs - extensions to allow the linq style querying
  4. BaseGraphQLClient.cs - a base client that GraphQLClient inherits from
  5. GqlFieldNameAttribute.cs - required by the generated code

Ideally move this to a dependency style library and tool in the future.

Request Methods

GraphQLClient exposes 2 methods:

  • Query
    async Task<GqlResult<TQuery>> QueryAsync<TQuery>(Expression<Func<RootQuery, TQuery>> query)
  • Mutation
    async Task<GqlResult<TQuery>> MutateAsync<TQuery>(Expression<Func<Mutation, TQuery>> query)

Query

// queriesvarresult=awaitclient.QueryAsync(q =>new{Movie=q.Movie(2, m =>new{m.Id,m.Name,ReleaseDate=m.Released,Director=m.Director(d =>new{d.Name})}),Actors=q.Actors(a =>new{a.Name,a.Dob})});

This looks similar to the GraphQL. And now result.Data is a strongly type object with the expected types.

If a field in the schema is an object (can have a selection performed on it) it will be exposed in the generated code as a method where you pass in any field arguments first and then the selection.

The GraphQL created by the above will look like this:

{
query {
Movie: movie(id: 2) {
Id: id
Name: name
ReleaseDate: released
Director: director {
Name: name
}
}
Actors: actors {
Name: name
Dob: dob
}
}
}

Mutations

Mutations look very similar to the above query, just as they do in GraphQL. The above schema had one mutation that can be called like so

// mutationsvarmutationResult=awaitclient.MutateAsync(m =>new{NewPerson=m.AddPerson(newDateTime(1801,7,3),"John Johny", p =>new{p.Id})});

m is the Mutation type interface and lets you call any of the mutations generated from the schema. Like a query, you create a new anonymous object and call as many mutations as you wish. Each mutation method has all their arguments and the last one is a selection query on the mutation's return type.

The above has mutationResult strongly typed. E.g. mutationResult.Data.NewPerson will only have an Id field.

Input types

Any input types are generated as actual classes as the are used as arguments. The -m Date=DateTime tells the tool that the scalar type Date should be the DateTime type in C#. You can use this to support any other custom scalar types. E.g. -m Date=DateTime;Point=PointF, just comma separate a GqlScalar=DotnetType list.

About

Generate dotnet interfaces/classes from a GraphQL schema to perform type-safe querying from dotnet

Resources

Stars

78 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

dotnet GraphQL Query generator

Given a GraphQL schema file (or a GraphQL endpoint where we can do a schema introspection), this tool will generate interfaces and classes to enable strongly typed querying from C# to a GraphQL API.

Example GraphQL schema

schema {
query: Query
mutation: Mutation
}
scalar Date
type Query {
actors: [Person]
directors: [Person]
movie(id: Int!): Movie
movies: [Movie]
}
type Movie {
id: Int
name: String
genre: Int
released: Date
actors: [Person]
writers: [Person]
director: Person
rating: Float
}
type Person {
id: Int
dob: Date
actorIn: [Movie]
writerOf: [Movie]
directorOf: [Movie]
died: Date
age: Int
name: String
}
type Mutation {
addPerson(dob: Date!, name: String!): Person
}

Query Generator Command

To generate from a graphql schema file:
dotnet run -- schema.graphql -m Date=DateTime

To generate from a live GraphQL server (note: introspection may not be supported or enabled on your server):
dotnet run -- http://myapi.app/gql -m Date=DateTime -h "Authorization=Bearer eyAfd..."

For all command line options, use --help or -?

Both commands will generate the files GraphQLClient.cs and GeneratedTypes.cs.

GeneratedTypes.cs

Based on the example schema.graphql the GeneratedTypes.cs file will have the following content:

publicinterfaceRootQuery{[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("directors")]List<Person>Directors();[GqlFieldName("directors")]List<TReturn>Directors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("movie")]MovieMovie();[GqlFieldName("movie")]TReturnMovie<TReturn>(intid,Expression<Func<Movie,TReturn>>selection);[GqlFieldName("movies")]List<Movie>Movies();[GqlFieldName("movies")]List<TReturn>Movies<TReturn>(Expression<Func<Movie,TReturn>>selection);}publicinterfaceMovie{[GqlFieldName("id")]intId{get;}[GqlFieldName("name")]stringName{get;}[GqlFieldName("genre")]intGenre{get;}[GqlFieldName("released")]DateTimeReleased{get;}[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("writers")]List<Person>Writers();[GqlFieldName("writers")]List<TReturn>Writers<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("director")]PersonDirector();[GqlFieldName("director")]TReturnDirector<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("rating")]doubleRating{get;}}publicinterfacePerson{[GqlFieldName("id")]intId{get;}[GqlFieldName("dob")]DateTimeDob{get;}[GqlFieldName("actorIn")]List<Movie>ActorIn();[GqlFieldName("actorIn")]List<TReturn>ActorIn<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("writerOf")]List<Movie>WriterOf();[GqlFieldName("writerOf")]List<TReturn>WriterOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("directorOf")]List<Movie>DirectorOf();[GqlFieldName("directorOf")]List<TReturn>DirectorOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("died")]DateTimeDied{get;}[GqlFieldName("age")]intAge{get;}[GqlFieldName("name")]stringName{get;}}publicinterfaceMutation{[GqlFieldName("addPerson")]TReturnAddPerson<TReturn>(DateTimedob,stringname,Expression<Func<Person,TReturn>>selection);}

GraphQLClient.cs

The generated GraphQLClient class instance acts as a session to send GraphQL requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/gql")};varclient=newGraphQLClient(httpClient);

For custom headers like Authorization, configure them in the HttpClient. These will be used during the requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/")};httpClient.DefaultRequestHeaders.Authorization=newAuthenticationHeaderValue("Bearer","eyAf3s...");varclient=newGraphQLClient(newUri("gql",UriKind.Relative),httpClient);

To use the GraphQLClient, copy the following files into your project. These will all be in the output folder:

  1. GraphQLClient.cs - a simple client you can modify or extend
  2. GeneratedResultTypes.cs - generated types from the schema
  3. GeneratedQueryTypes.cs - extensions to allow the linq style querying
  4. BaseGraphQLClient.cs - a base client that GraphQLClient inherits from
  5. GqlFieldNameAttribute.cs - required by the generated code

Ideally move this to a dependency style library and tool in the future.

Request Methods

GraphQLClient exposes 2 methods:

  • Query
    async Task<GqlResult<TQuery>> QueryAsync<TQuery>(Expression<Func<RootQuery, TQuery>> query)
  • Mutation
    async Task<GqlResult<TQuery>> MutateAsync<TQuery>(Expression<Func<Mutation, TQuery>> query)

Query

// queriesvarresult=awaitclient.QueryAsync(q =>new{Movie=q.Movie(2, m =>new{m.Id,m.Name,ReleaseDate=m.Released,Director=m.Director(d =>new{d.Name})}),Actors=q.Actors(a =>new{a.Name,a.Dob})});

This looks similar to the GraphQL. And now result.Data is a strongly type object with the expected types.

If a field in the schema is an object (can have a selection performed on it) it will be exposed in the generated code as a method where you pass in any field arguments first and then the selection.

The GraphQL created by the above will look like this:

{
query {
Movie: movie(id: 2) {
Id: id
Name: name
ReleaseDate: released
Director: director {
Name: name
}
}
Actors: actors {
Name: name
Dob: dob
}
}
}

Mutations

Mutations look very similar to the above query, just as they do in GraphQL. The above schema had one mutation that can be called like so

// mutationsvarmutationResult=awaitclient.MutateAsync(m =>new{NewPerson=m.AddPerson(newDateTime(1801,7,3),"John Johny", p =>new{p.Id})});

m is the Mutation type interface and lets you call any of the mutations generated from the schema. Like a query, you create a new anonymous object and call as many mutations as you wish. Each mutation method has all their arguments and the last one is a selection query on the mutation's return type.

The above has mutationResult strongly typed. E.g. mutationResult.Data.NewPerson will only have an Id field.

Input types

Any input types are generated as actual classes as the are used as arguments. The -m Date=DateTime tells the tool that the scalar type Date should be the DateTime type in C#. You can use this to support any other custom scalar types. E.g. -m Date=DateTime;Point=PointF, just comma separate a GqlScalar=DotnetType list.

About

Generate dotnet interfaces/classes from a GraphQL schema to perform type-safe querying from dotnet

Resources

Stars

78 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

dotnet GraphQL Query generator

Given a GraphQL schema file (or a GraphQL endpoint where we can do a schema introspection), this tool will generate interfaces and classes to enable strongly typed querying from C# to a GraphQL API.

Example GraphQL schema

schema {
query: Query
mutation: Mutation
}
scalar Date
type Query {
actors: [Person]
directors: [Person]
movie(id: Int!): Movie
movies: [Movie]
}
type Movie {
id: Int
name: String
genre: Int
released: Date
actors: [Person]
writers: [Person]
director: Person
rating: Float
}
type Person {
id: Int
dob: Date
actorIn: [Movie]
writerOf: [Movie]
directorOf: [Movie]
died: Date
age: Int
name: String
}
type Mutation {
addPerson(dob: Date!, name: String!): Person
}

Query Generator Command

To generate from a graphql schema file:
dotnet run -- schema.graphql -m Date=DateTime

To generate from a live GraphQL server (note: introspection may not be supported or enabled on your server):
dotnet run -- http://myapi.app/gql -m Date=DateTime -h "Authorization=Bearer eyAfd..."

For all command line options, use --help or -?

Both commands will generate the files GraphQLClient.cs and GeneratedTypes.cs.

GeneratedTypes.cs

Based on the example schema.graphql the GeneratedTypes.cs file will have the following content:

publicinterfaceRootQuery{[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("directors")]List<Person>Directors();[GqlFieldName("directors")]List<TReturn>Directors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("movie")]MovieMovie();[GqlFieldName("movie")]TReturnMovie<TReturn>(intid,Expression<Func<Movie,TReturn>>selection);[GqlFieldName("movies")]List<Movie>Movies();[GqlFieldName("movies")]List<TReturn>Movies<TReturn>(Expression<Func<Movie,TReturn>>selection);}publicinterfaceMovie{[GqlFieldName("id")]intId{get;}[GqlFieldName("name")]stringName{get;}[GqlFieldName("genre")]intGenre{get;}[GqlFieldName("released")]DateTimeReleased{get;}[GqlFieldName("actors")]List<Person>Actors();[GqlFieldName("actors")]List<TReturn>Actors<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("writers")]List<Person>Writers();[GqlFieldName("writers")]List<TReturn>Writers<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("director")]PersonDirector();[GqlFieldName("director")]TReturnDirector<TReturn>(Expression<Func<Person,TReturn>>selection);[GqlFieldName("rating")]doubleRating{get;}}publicinterfacePerson{[GqlFieldName("id")]intId{get;}[GqlFieldName("dob")]DateTimeDob{get;}[GqlFieldName("actorIn")]List<Movie>ActorIn();[GqlFieldName("actorIn")]List<TReturn>ActorIn<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("writerOf")]List<Movie>WriterOf();[GqlFieldName("writerOf")]List<TReturn>WriterOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("directorOf")]List<Movie>DirectorOf();[GqlFieldName("directorOf")]List<TReturn>DirectorOf<TReturn>(Expression<Func<Movie,TReturn>>selection);[GqlFieldName("died")]DateTimeDied{get;}[GqlFieldName("age")]intAge{get;}[GqlFieldName("name")]stringName{get;}}publicinterfaceMutation{[GqlFieldName("addPerson")]TReturnAddPerson<TReturn>(DateTimedob,stringname,Expression<Func<Person,TReturn>>selection);}

GraphQLClient.cs

The generated GraphQLClient class instance acts as a session to send GraphQL requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/gql")};varclient=newGraphQLClient(httpClient);

For custom headers like Authorization, configure them in the HttpClient. These will be used during the requests.

varhttpClient=newHttpClient{BaseAddress=newUri("http://myapi.app/")};httpClient.DefaultRequestHeaders.Authorization=newAuthenticationHeaderValue("Bearer","eyAf3s...");varclient=newGraphQLClient(newUri("gql",UriKind.Relative),httpClient);

To use the GraphQLClient, copy the following files into your project. These will all be in the output folder:

  1. GraphQLClient.cs - a simple client you can modify or extend
  2. GeneratedResultTypes.cs - generated types from the schema
  3. GeneratedQueryTypes.cs - extensions to allow the linq style querying
  4. BaseGraphQLClient.cs - a base client that GraphQLClient inherits from
  5. GqlFieldNameAttribute.cs - required by the generated code

Ideally move this to a dependency style library and tool in the future.

Request Methods

GraphQLClient exposes 2 methods:

  • Query
    async Task<GqlResult<TQuery>> QueryAsync<TQuery>(Expression<Func<RootQuery, TQuery>> query)
  • Mutation
    async Task<GqlResult<TQuery>> MutateAsync<TQuery>(Expression<Func<Mutation, TQuery>> query)

Query

// queriesvarresult=awaitclient.QueryAsync(q =>new{Movie=q.Movie(2, m =>new{m.Id,m.Name,ReleaseDate=m.Released,Director=m.Director(d =>new{d.Name})}),Actors=q.Actors(a =>new{a.Name,a.Dob})});

This looks similar to the GraphQL. And now result.Data is a strongly type object with the expected types.

If a field in the schema is an object (can have a selection performed on it) it will be exposed in the generated code as a method where you pass in any field arguments first and then the selection.

The GraphQL created by the above will look like this:

{
query {
Movie: movie(id: 2) {
Id: id
Name: name
ReleaseDate: released
Director: director {
Name: name
}
}
Actors: actors {
Name: name
Dob: dob
}
}
}

Mutations

Mutations look very similar to the above query, just as they do in GraphQL. The above schema had one mutation that can be called like so

// mutationsvarmutationResult=awaitclient.MutateAsync(m =>new{NewPerson=m.AddPerson(newDateTime(1801,7,3),"John Johny", p =>new{p.Id})});

m is the Mutation type interface and lets you call any of the mutations generated from the schema. Like a query, you create a new anonymous object and call as many mutations as you wish. Each mutation method has all their arguments and the last one is a selection query on the mutation's return type.

The above has mutationResult strongly typed. E.g. mutationResult.Data.NewPerson will only have an Id field.

Input types

Any input types are generated as actual classes as the are used as arguments. The -m Date=DateTime tells the tool that the scalar type Date should be the DateTime type in C#. You can use this to support any other custom scalar types. E.g. -m Date=DateTime;Point=PointF, just comma separate a GqlScalar=DotnetType list.

About

Generate dotnet interfaces/classes from a GraphQL schema to perform type-safe querying from dotnet

Resources

Stars

78 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages