To create a new schema we need to supply a base context type. This base type is used as the base for top-level query fields. DemoContext is our base query context for the schema.
// Using EntityGraphQL.AspNet extension method to add the schema auto-populated from the base query type. Schema has types and fields built from DemoContext. See optional arguments for customizing the behavior. services.AddGraphQLSchemaDemoContext>(options => options.ConfigureSchema = (schema) => // configure schema here >; >); // Create a blank schema with the base query type. Schema has no types or fields yet. services.AddGraphQLSchemaDemoContext>(options => options.AutoBuildSchemaFromContext = false; options.ConfigureSchema = (schema) => // configure schema here >; >);
If you need to create a schema outside of ASP.NET.
// Create a schema auto-populated from the base query type. Schema has types and fields built from DemoContext. See optional arguments for customizing the behavior. var schema = new SchemaBuilder.FromObjectDemoContext>(); // Create a blank schema with the base query type. Schema has no types or fields yet. var schema = new SchemaProviderDemoContext>();
Now we need to add some types to our schema which we will use as return types for fields. The most common GraphQL types you will deal with are
For more information of GraphQL types visit the GraphQL docs.
To register a type in the schema:
schema.AddTypePerson>("Person", "Hold data about a person object");
This will add the Person type as a schema object type named Person . It does not have fields yet.
We now need to add some fields to both the root query object and our new Person Object Type.
schema.UpdateTypePerson>(personType => personType.AddField( "firstName", // name in GraphQL schema person => person.FirstName, // expression to resolve the field on the .NET type "A person's first name" // description of the field ); >);
The resolve expression can be any expression you can build.
schema.UpdateTypePerson>(personType => personType.AddField( "fullName", person => $"person.FirstName> person.LastName>", "A person's full name" ); >);
Now let's add a root query field so we can query people.
schema.Query() // returns the root GraphQL query type .AddField( "people", ctx => ctx.People, // ctx is the core context used when creating the schema above "List of people" );
We now have a very simple GraphQL schema ready to use. It has a single root query field ( people ) and a single type Person with 2 fields ( firstName & fullName ).
EntityGraphQL has methods to speed up the creation of your schema. This is helpful to get up and running but be aware if you are exposing this API externally it can be easy to make breaking API changes. For example using the methods above if you end up changing the underlying .NET types you will have compilation errors which alert you of breaking API changes and you can address them. Using the methods below will automatically pick up the underlying changes of the .NET types.
// Automatically add all types and fields from the base context var schema = SchemaBuilder.FromObjectDemoContext>();
Optional arguments for the schema builder:
public ListAllowedException> AllowedExceptions get; set; > = new ListAllowedException> new AllowedException(typeof(EntityGraphQLArgumentException)), new AllowedException(typeof(EntityGraphQLException)), new AllowedException(typeof(EntityGraphQLFieldException)), new AllowedException(typeof(EntityGraphQLAccessException)), new AllowedException(typeof(EntityGraphQLValidationException)), >;
schema query: Query > Type Query people: [Person] person(id: ID!): Person > Type Person firstName: String . >
"Database", "Model", "ChangeTracker", "ContextId"
// Add Sort to all list fields OnFieldCreated = (field) => if (field.ReturnType.IsList && field.ReturnType.SchemaType.GqlType == GqlTypes.QueryObject && !field.FromType.IsInterface) field.UseSort(); > >
AddAllFields() on the schema type will automatically add all the fields on that .NET type.
schema.AddTypePerson>("Person", "All about the project") .AddAllFields();
schema.AddTypePerson>("Person", "All about the project") .AddAllFields(new SchemaBuilderOptions AutoCreateNewComplexTypes = false, // do not add custom dotnet types found as property/field types to the schema. Only add scalar type fields >);
EntityGraphQL provides method to help you modify a schema as well.
schema.UpdateTypePerson>(personType => personType.RemoveField("firstName"); personType.ReplaceField( "lastName", p => p.LastName.ToUpper(), // new expression to resolve the lastName field "New description" ); >); schema.RemoveTypeTType>(); schema.RemoveType("TypeName"); // Remove a type and all fields that return that type schema.RemoveTypeAndAllFieldsType>();
See more details for each schema item in the following sections:
GraphQL supports arguments on query fields. We saw this already with the SchemaBuilder.FromObject() helper method. It created a field with an id argument to select a single item by id. Of course you can create fields with your own arguments to expand the functionality of you GraphQL APi.
GraphQLs mutations allow you to make modifications to your data.
We learnt previously that the GraphQL spec defines the following built in scalar types.
Enum types are just like you'd expect. It let's API consumers know that a field can be only 1 of a set of values.
We've seen passing scalar values, like enums, numbers or strings, as arguments into a field. Input types allow us to define complex types that can be used as an argument. This is particularly valuable in the case of mutations, where you might want to pass in a whole object to be created.
GraphQL supports Interfaces allowing you to define a abstract base type that multiple other types might implement.
Union Types are very similar to interfaces, but they don't get to specify any common fields between the types.
GraphQL defines type modifiers specifically for declaring that a field is a list or cannot be null. In a schema these are [T] and !. For example, a GraphQL schema might have the following.
Directives provide a way to dynamically change the structure and shape of our queries using variables. An example from the GraphQL website:
EntityGraphQL lets you add fields that resolve (fetch) data from sources other than the core query context you created your schema with. This is powerful as it let's you create a single API that brings together multiple data sources into an object graph.
GraphQL subscriptions outline an agreed way for services to define events & clients to subscribe to events with the familiar GraphQL queries.