PolyglotDataStudio.GraphQL 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package PolyglotDataStudio.GraphQL --version 1.0.0
                    
NuGet\Install-Package PolyglotDataStudio.GraphQL -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PolyglotDataStudio.GraphQL" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PolyglotDataStudio.GraphQL" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="PolyglotDataStudio.GraphQL" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PolyglotDataStudio.GraphQL --version 1.0.0
                    
#r "nuget: PolyglotDataStudio.GraphQL, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PolyglotDataStudio.GraphQL@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PolyglotDataStudio.GraphQL&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=PolyglotDataStudio.GraphQL&version=1.0.0
                    
Install as a Cake Tool

PolyglotDataStudio.GraphQL

A lightweight, strongly-typed GraphQL schema builder and runtime helpers for .NET.
PolyglotDataStudio.GraphQL provides building blocks (object/input/scalar primitives and root operations) to define GraphQL types and execute queries in a test-friendly, framework-agnostic way. The library is designed to be easy to use from unit tests and integrates cleanly with .NET Standard 2.1 and .NET 10 applications.

Create a GraphQL schema by hand, or use the accompanying CLI tool to generate C# types from an existing GraphQL schema definition file.

Purpose

  • Provide first-class, composable types to declare GraphQL objects, input objects and scalars in C#.
  • Keep schema definition concise and type-safe.
  • Make writing unit tests for GraphQL schemas straightforward (see PolyglotDataStudio.GraphQL.Tests for working examples).
  • Be small, dependency-free and easy to include in libraries or microservices.

Highlights / Features

  • Core entity base types (GraphQLEntityBase, GraphQLObject, GraphQLInputObject, GraphQLRootOperation).
  • Common scalar implementations (GraphQLScalarString, GraphQLScalarInt, GraphQLScalarFloat, GraphQLScalarBool).
  • Helpers for building test schemas and executing queries from unit tests.
  • Targets .NET Standard 2.1 and .NET 10 for broad compatibility.
  • Ultra-high performance, with no runtime reflection, expressions or dynamic code generation

Installation

Install both the CLI tool and the library package.

dotnet tool install PolyglotDataStudio.GraphQL.CLI
dotnet add package PolyglotDataStudio.GraphQL

The CLI tool is used to generate C# types from a GraphQL schema definition file. The library package contains the runtime types and helpers. See the PolyglotDataStudio.GraphQL.CLI README for details on using the CLI tool.

Quick Start

Use the CLI tool to generate C# types from a GraphQL schema file. The output from the tool can be directly included in your code, or packaged into a separate dependent library, at your discretion.

Let's assume your schema has a Type called Hero with fields id and name.

The following code creates a simple query:

	var query = new Query();
	query.Hero.WithFields( h => h.Id, h => h.Name );

	var gql = query.Render( formatted: false );

The resulting GraphQL query string will be:

	query { hero { id name } }

... or with formatting turned on:

	query {
		hero {
			id
			name
		}
	}

The WithFields method accepts multiple field selectors, so you can specify all desired fields in a single call, or if your query requires a complex retrival from a deeply nested structure, you can chain multiple WithFields calls together. Also, you can name your query and apply field aliases as needed.

	var query = new Query().WithName( "GetHero" );
	query.Hero.WithFields( h => h.Id )
			  .WithFields( h => h.Name.WithAlias( "humanName" ) );

	var gql = query.Render( formatted: true );

Which produces the following GraphQL query string:

	query GetHero {
		hero {
			id
			humanName: name
		}
	}

Generating multiple queries can be done by executing additional calls against the same root operation.

	var query = new Query();
	query.Hero.WithAlias( "justId" ).WithFields( h => h.Id );
	query.Hero.WithAlias( "justName" ).WithFields( h => h.Name );

	var gql = query.Render( formatted: true );

Which produces the following GraphQL query string:

	query {
		justId: hero {
			id
		}
		justName: hero {
			name
		}
	}

Parsing response data

To handle response data, an additional layer of types are generated in the CLI to better support JSON deserialization. These are emitted into the Models child namespace, below the namespace nominated in the command-line.

Some important information about the generated models follows:

  • Custom scalars are handled as strings, as the SDL specification does not support specifying an underlying type.
  • It is necessary to manually specify type descriminators and descendent types for interfaces, as this information cannot be determined automatically. For this reason Interfaces are generated as partial.
  • Model classes are always generated with the same class name as their main counterpart, with the addition of a Model suffix.
  • To ensure there are no typename collisions, all model types are generated into a separate Models namespace.

Simple expample

Using the previous Hero example, the code to generate a query and parse the response with the default modes is as follows:

var query = new Query();
query.Hero.WithFields( h => h.Id, h => h.Name );

var gql = query.Render( formatted: true );

// use your own infrastructure for actually executing the query
var responseJson = await myGqlExecutor.ExecuteQuery( gql );
query.SetResultJson( resultJson );

Models.Hero myHero1 = query.GetResult();

// alternative 1
var myHero2 = query.GetResult<Models.Hero>();

// alternative 2
var myHero2 = query.GetResult<MySpecialType>();
  • SetResultJson() accepts a raw json string or a JsonElement
  • Don't set field aliases or model properties will not map correctly
  • You are free to use any model type you wish, defaults are provided automatically
  • GetResult<T>() provides an additional argument to override the serializer options if you wish

More complex expample

For a more complex example we are going to make multiple operations in a single request. To deserialize the response we will need to custom-make a type that combines the results from both queries. While possible, this is not always desirable.

As an alternative, provide the GetResult() method with a string parameter to indicate which operation (or alias) we want the response for, and use the default or a custom model to represent part of the respose.

When querying the same type multiple times, it is important to set field aliases to distinguish the responses.

var query = new Query();
query.Hero.WithAlias( "justId" ).WithFields( h => h.Id );
query.Hero.WithAlias( "justName" ).WithFields( h => h.Name );

var gql = query.Render( formatted: true );

// use your own infrastructure for actually executing the query
var responseJson = await myGqlExecutor.ExecuteQuery( gql );
query.SetResultJson( resultJson );

// alternative 1
var myHeroId = query.GetResult<Models.Hero>( "justId" );
var myHeroName = query.GetResult<Models.Hero>( "justName" );

Example use of interfaces and poymorphism during deserialization

Let's assume your schema defines the following elements:

enum AccountType {
	USER
	ROLE
}  

interface Account {
	displayName: String
	name: String!
	accountType: AccountType!
}

type User implements Account {
	displayName: String
	name: String!
	accountType: AccountType!
	email: String
	phone: String
}

type Role implements Account {
	displayName: String
	name: String!
	accountType: AccountType!
	isAdministrator: Boolean
}

The generated C# models will be created as follows:

public enum AccountType { ROLE, USER }
public partial interface AccountModel {
	string? DisplayName { get; }
	string? Name { get; }
	AccountType? AccountType { get; }
}
public class UserModel : AccountModel {
	public string? DisplayName { get; set; }
	public string? Name { get; set; }
	public AccountType? AccountType { get; set; }
	public string? Email { get; set; }
	public string? Phone { get; set; }
}
public class RoleModel : AccountModel {
	public string? DisplayName { get; set; }
	public string? Name { get; set; }
	public AccountType? AccountType { get; set; }
	public bool? IsAdministrator { get; set; }
}
  • Model members always support nullability to accommodate partial responses.
  • Polymorphism support is built in, insofar as concrete types exist for all interfaces in your schema. When a request is made for a property that returns an interface, the framework will include the __typename field automatically, to use as a type discriminator, which will select the correct concrete type to use in deserialization, assuming one is available.

To support the manual deserialization of polymorphic types, one might create an additional partial class as follows:

[JsonPolymorphic( IgnoreUnrecognizedTypeDiscriminators = true, TypeDiscriminatorPropertyName = "accountType", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor )]
[JsonDerivedType( typeof( UserModel ), "USER" )]
[JsonDerivedType( typeof( RoleModel ), "ROLE" )]
public partial interface AccountModel { }

This allows the deserializer to correctly instantiate the appropriate derived type based on the accountType field in the response data.

While it would be possible to specify some of the JsonDerivedType attributes in the generated code, it is not possible to know which field could be used as the type discriminator, or which values would identify the type to use, so this must be done manually.

Contributing

Contributions are welcome. Please:

  • Open issues for bugs or feature requests.
  • Submit pull requests against the develop branch.
  • Follow repository coding conventions and add/update unit tests for new behavior.
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on PolyglotDataStudio.GraphQL:

Package Downloads
PINGWorks.SitecoreExperienceEdge.ContentSDK

PING Works' .NET SDK for working with Sitecore's Experience Edge Content API.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 136 4/16/2026
1.1.2 245 3/30/2026
1.1.1 108 2/18/2026
1.1.0 108 2/11/2026
1.0.0 105 2/4/2026