What is the difference between Code-First and Pure Code-First or Annotation-Based in Hot Chocolate and what are the pros and cons of each of these coding approaches in GraphQL schema perspective and internally in Hot Chocolate?
What is the difference between Code-First and Pure Code-First or Annotation-Based in Hot Chocolate and what are the pros and cons of each of these coding approaches in GraphQL schema perspective and internally in Hot Chocolate?
Pure Code First was renamed to Annotation Based. So these two are the same.
It depends on architecture and taste what you will end up using. You are not bound to code first or annotation based, you can also mix and match.
HotChocolate infers all properties and their types by default. Meaning, when you return a User it will automatically create a type for it with all properties that the user has.
If you would like to change the configuration of the type you can either us annotations or create a ObjectType`
Under the hood all approaches (even schema first) have the same representation. They all are translated into the code-first approach.
In the code first approach you use type inheritance and a fluent API to configure the types
public class User
{
public string Id {get; set}
}
public class UserType : ObjectType<User>
{
protected override void Configure(IObjectTypeDescriptor<User> descriptor)
{
descriptor.Field(x => x.Id).Type<IdType>();
descriptor.Field<Resolvers>(x => x.GetAddressAsync(default, default));
}
public class Resolvers
{
public Task<Address> GetAddressAsync(
[Parent]User user,
[Service]AddressRepo repo) => repo.GetAddressByUserAsync(user.Id);
}
}
In the annotation based approach, you can use annotations to customise the types:
public class User
{
[GraphQLType(typeof(IdType))]
public string Id {get; set}
}
[ExtendObjectType(nameof(User))]
public class UserAddressExtensions
{
public Task<Address> GetAddressAsync(
[Parent]User user,
[Service]AddressRepo repo) => repo.GetAddressByUserAsync(user.Id);
}
Even though both approaches are equally powerful and have the same features, there are certain benefits of using one over the other.
If you do not have access to the Domain models, or do not want to add attributes to them, you may find the code first approach easier to use. Same goes for the case when you want to opt out of the type inference and specify what fields you want to expose in the schema.
The Annotation Based approach usually safes a ton of boiler plate code that you would need if you do code first. If you find yourself exposing more properties on the api than properties you hide, you may find the annotation based approach more elegant. Usually you have a lot less and cleaner code if you use annotations
What we see very often is a combination of both approaches. Where everything that is in the GraphQL domain, uses annotations and to configure the domain models, code first types are used.
Though with the new attributes that are released in 11.2 you do not even need the code first types anymore. You can also change, ignore or replace fields with attributes and type extensions. You can also define Unions and interfaces with [UnionType] or [InterfaceType]
https://chillicream.com/docs/hotchocolate/defining-a-schema/extending-types/
Annotation-Based or Pure Code-First: In this approach, we don't bother about GraphQL schema types, we will just write clean C# code that automatically translates to GraphQL types.
Code-first: In this approach, we use Schema types, Schema types allow us to keep the GraphQL type configuration separate from our .NET types. This can be the right approach when we do not want any Hot Chocolate attributes on our business objects.