Movatterモバイル変換


[0]ホーム

URL:


Hot Chocolatev12

Extending Types

Type extensions allow us to add, remove or replace fields on existing types, without necessarily needing access to these types.

Because of these capabilities, they also allow for better organization of our types. We could for example have classes that encapsulate part of our domain and extend ourQuery type with these functionalities.

Type extensions are especially useful if we want to modify third-party types, such as types that live in a separate assembly and are therefore not directly modifiable by us.

Warning

Type extensions do not produce theextend type syntax that GraphQL offers, since it would unnecessarily complicate the resulting schema. Instead, Hot Chocolate's type extensions are directly merged with the original type definition to create a single type at runtime.

Object Types

Consider we have the following entity that we want to extend with functionality.

C#
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public int AuthorId { get; set; }
}

Adding fields

We can easily add new fields to our existingBook type.

C#
[ExtendObjectType(typeof(Book))]
public class BookExtensions
{
public IEnumerable<string> GetGenres([Parent] Book book)
{
// Omitted code for brevity
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddGraphQLServer()
.AddTypeExtension<BookExtensions>();
}
}

One of the most common use-cases for this would be adding new resolvers to one of our root types.

C#
[ExtendObjectType(typeof(Query))]
public class QueryBookResolvers
{
public IEnumerable<Book> GetBooks()
{
// Omitted code for brevity
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddGraphQLServer()
.AddTypeExtension<QueryBookResolvers>();
}
}

Removing fields

We can also ignore fields of the type we are extending.

C#
[ExtendObjectType(typeof(Book),
IgnoreProperties = new[] { nameof(Book.AuthorId) })]
public class BookExtensions
{
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddGraphQLServer()
.AddTypeExtension<BookExtensions>();
}
}

Replacing fields

We might have anId field, which we want to replace with a field that resolves the actual type theId is pointing to.

In this example we replace theauthorId field with anauthor field.

C#
[ExtendObjectType(typeof(Book))]
public class BookExtensions
{
[BindMember(nameof(Book.AuthorId))]
public Author GetAuthor([Parent] Book book)
{
// Omitted code for brevity
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddGraphQLServer()
.AddTypeExtension<BookExtensions>();
}
}

Extending by name

If we can not reference a type, we can still extend it by specifying its name.

C#
[ExtendObjectType("Foo")]
public class FooExtensions
{
// Omitted code for brevity
}

When extending root types, we can make use of the constants inOperationTypeNames. We can for example useOperationTypeNames.Query instead of writing"Query" everywhere.

Extending base types

We can also extend multiple types at once, but still dedicate specific resolvers to specific types.

C#
// this extends every type that inherits from object (essentially every type)
[ExtendObjectType(typeof(object))]
public class ObjectExtensions
{
// this field is added to every object type
public string NewField()
{
// Omitted code for brevity
}
// this field is only added to the Book type
public Author GetAuthor([Parent] Book book)
{
// Omitted code for brevity
}
// this field is only added to the Author type
public IEnumerable<Book> GetBooks([Parent] Author author)
{
// Omitted code for brevity
}
}

We can also modify all object types that are connected by a base type, like an interface.

C#
[InterfaceType]
public interface IPost
{
string Title { get; set; }
}
// this extends every type that implements the IPost interface,
// not the interface type itself
[ExtendObjectType(typeof(IPost))]
public class PostExtensions
{
public string NewField([Parent] IPost post)
{
// Omitted code for brevity
}
}

Note: TheIPost is annotated with[InterfaceType] to include it in the GraphQL schema, but that isn't necessary for the type extension to work.We can use any base type, likeobject or anabstract base class, as an extension point without necessarily exposing the base type in our GraphQL schema.

Last updated on2025-06-16 byGlen
About this article
Help us improving our content
  1. Edit on GitHub
  2. Discuss on Slack

[8]ページ先頭

©2009-2025 Movatter.jp