EntityGraphQL

A GraphQL library for .NET

MIT License

Stars
378
Committers
28

Bot releases are visible (Hide)

EntityGraphQL - 5.2.1 Latest Release

Published by lukemurray 6 months ago

Fixes

  • #355 - make error variable values more distinctive
  • EntityGraphQL is now more specific in which methods it tries to optimize the pattern of a list to single. E.g. If a field has an expression like ctx => ctx.People.FirstOrDefault(filter) EntityGraphQL treats that as a ListToSingle field and will build a full expression similar to ctx => ctx.People.Where(filter).Select(x => new {...}).FirstOrDefault() to avoid over fetching when using EntityFramework. Previously EntityGraphQL would try to break up and rebuild expressions.methods it didn't know how to. It now correctly only tries this optimization on First, FirstOrDefault, Single, SingleOrDefault, Last & LastOrDefault from Queryable & Enumerable
EntityGraphQL - 5.2.0

Published by lukemurray 7 months ago

Changes

  • #347 - The handler for the subscriptions end point added by UseGraphQLWebSockets no longer returns 400 if the request is not a web socket request. Allowing the request to get passed to the next handlers. This allows you to have the same endpoint for queries/mutations and subscriptions.
  • #318 - Support Unicode characters in the string of the filter language
  • Add a net8.0 target output for the base EntityGraphQL library.
  • Make more properties public in nodes like GraphQLCollectionToSingleField to better support customisation in custom directives
  • Added field.Resolve<TService, ...>() to replace ResolveWithService<>(). Recommended to use Resolve(). Release 5.3 will mark ResolveWithService as deprecated and release 6.0 will remove them.
  • Add field.ResolveBulk<TService, TKey, TResult>() to allow you to use services to bulk load data to avoid multiple calls to a service resolve expression that may call an external service in a list result. Example
  • Add schema.AddEnum<TEnum>(typeName, description) to the schema building API
  • Add net8.0 as a target for EntityGraphQL.AspNet project
var schema = SchemaBuilder.FromObject<MyContext>();
schema.UpdateType<Project>(type =>
{
    type.ReplaceField("createdBy", "Get user that created it")
      // normal service to fetch the User object for creator of the Project type
      .ResolveWithService<UserService>((proj, users) => users.GetUserById(proj.CreatedById))
      // Bulk service used to fetch many User objects
      .ResolveBulk<UserService, int, User>(proj => proj.CreatedById, (ids, srv) => srv.GetAllUsers(ids));
});

If you have a query like

{
  # ResolveBulk
  projects {
    # project fields
    name
    id
    # service field - resolved with ResolveBulk expression for all Projects loaded
    createdBy {
      name
    }
  }

  # ResolveWithService
  project(id: 78) {
    # project fields
    name
    id
    # service field - resolved with ResolveWithService expression for the single project loaded
    createdBy {
      name
    }
  }
}

Instead of calling users.GetUserById() for each project to resolve createdBy { name }, EntityGraphQL will build a list of keys using the proj => proj.CreatedById expression from the list of projects and then call the (ids, srv) => srv.GetAllUsers(ids) expression once for the whole list of projects in the results. See updated documentation for further details.

Fixes

  • #350 - Index accessors properties (which are methods to dotnet) on types are ignored when using SchemaBuilder. Previously they would fail.
  • #333 - Fixes to method and service calls on interfaces/unions
  • #344 - Support paging field extensions with field.ResolveBulk<TService, TKey, TResult>()
  • Fix error when using a service at a query root field that uses First() as friends (List to single pattern). E.g. (ctx, service) => ctx.SomeList.First(i => i.Thing == service.Other)
  • #318 - Fix issue comparing int style fields against float style fields in the filter expression
  • Better error message when comparing different enum types in the filter language
  • Include descriptions for scalars and directives in introspection and schema output
  • Fix issue using the default SchemaBuilderOptions with a mutation method that has a list argument. The argument input type was not being correctly added to the schema. Not an issue if you were already adding the type manually
  • #336 - Fix conversion of non-nullable/nullable types
  • #342 - Fix argument incorrectly being renamed when using [GraphQLField]
EntityGraphQL - 5.1.1

Published by lukemurray 9 months ago

Fixes

Fix #337 - Description attribute accidentally updating name instead of description

EntityGraphQL - 4.3.1

Published by lukemurray 11 months ago

Fixes

  • Fix issue using the OneOf directive with ArgumentHelper.Required<T>() in a query field argument.
EntityGraphQL - 5.1.0

Published by lukemurray 11 months ago

Changes

  • Upgrade to the latest standard Antlr4 - the parser/tool used for the filter expression strings. Fixing precedence of operators

Fixes

  • #319 - Only convert strings to Guid or DateTime when required
  • If you add a field connecting back to the Query Context that ends in a method to go from a list to a single result the graph object projection will now correctly be inserted before the last call. Example
var schema = SchemaBuilder.FromObject<MyContext>();
schema.AddType<ExternalData>("ExternalData").AddAllFields();

schema.UpdateType<ExternalData>(ed =>
{
    // connect back to the MyContext types
    ed.AddField("movie", "Get movie")
      // here FirstOrDefault() goes from list -> single
      .ResolveWithService<MyContext>((ed, db) => db.Movies.Where(m => m.Id == ed.Id).FirstOrDefault());
});

schema.Query().AddField("externalData", "Get Data")
    .ResolveWithService<ExternalDataService>((p, srv) => srv.GetData());

In the above case if you select

{
  externalData {
    movie { director { name } }
  }
}

The movie field will have the selection inserted allowing EF to resolve fields without lazy loading turned on. Without this the m.Director.Name would also be null as no relation was included. e.g.

db.Movies.Where(m => m.Id == ed.Id)
.Select(m => new [
  director = new {
    name = m.Director.Name
  }
])
.FirstOrDefault();
EntityGraphQL - 5.0.1

Published by lukemurray about 1 year ago

Fixes

  • Fix #314 - Some clean up of the Antlr4 grammer for the filter expressions
EntityGraphQL - 5.0.0

Published by lukemurray about 1 year ago

Make sure to check out the changes 5.0.0-beta1

Breaking Changes

  • Generated schema type name for field sort inputs now include the name of the schema type the field is on to avoid conflicts

Changes

  • IField.AddExtension now returns the IField
  • UseSort() field extension now can take a list of default sort fields e.g.
  • Broadcaster (inbuilt IObservable<TType> you can use for subscriptions) now has a OnUnsubscribe callback
schema.ReplaceField("people",
    ctx => ctx.People,
    "Return a list of people. Optional sorted")
    .UseSort(
        new Sort<Person>((person) => person.Height, SortDirection.ASC),
        new Sort<Person>((person) => person.LastName, SortDirection.ASC)
    );
  • SchemaBuilderOptions now has a OnFieldCreated callback to make changes to fields as SchemaBuilder is building the schema.
  • .contains(string), .startsWith(string), .endsWith(string) & .toLower() / .toUpper() string methods now available in the filter argument expression.

Fixes

  • Fix naming of fields extracted from service calls when those field use convert
EntityGraphQL - 5.0.0-beta1

Published by lukemurray over 1 year ago

Breaking Changes

  • EntityGraphQL.AspNet now targets net6.0 and net7.0, dropping tagets netcoreapp3.1 or net5.0. You can still use the base EntityGraphQL library with older targets.
  • Interface IExposableException has been removed. Use SchemaBuilderSchemaOptions.AllowedExceptions or the new AllowedExceptionAttribute to define which exceptions are rendered into the results
  • #254 - Previously passing null for the ClaimsPrincipal in ExecuteRequest() would skip any authorization checks. All authorization checks are now done regardless of the ClaimsPrincipal value. Meaning null will fail if there is fields requiring authorization.
  • IDirectiveProcessor interface has changed. See upgrade docs for changes
  • SchemaBuilderMethodOptions removed, see updated properties on SchemaBuilderOptions and upgrade docs. This was because you can also now add methods as query fields with GraphQLFieldAttribute
  • SchemaBuilderOptions.AutoCreateInputTypes now defaults to true. Meaning in SchemaBuilder when adding mutations etc any complex types will be added to the schema if they are not there already.
  • The rules for reflection on method parameters have been changed to make them clearer. See the upgrade to 5.0 docs and the mutation docs that cover examples.
  • GraphQLValidator is no longer magically added to your method fields (mutations/subscriptions). If you wish to use it please register it in your services. There is a new helper method in EntityGraphQL.AspNet AddGraphQLValidator(). This means you can implement and register your own implementation.
  • SchemaProvider.ExecuteRequest & SchemaProvider.ExecuteRequestAsync have been renamed to ExecuteRequestWithContext & ExecuteRequestWithContextAsync. The schema context instance provided will be used for all context references within that query.
  • #309 - Introduced new SchemaProvider.ExecuteRequest & SchemaProvider.ExecuteRequestAsync which take no schema context instance as an argument. The context will be fetched from the provided ServiceProvider meaning the lifetime rules are adhered to - e.g. ServiceLifetime.Transient is now correctly used. This is the perferred way to execute a query

Changes

  • EntityGraphQL (the core library) targets both netstandard2.1 & net6. netstandard2.1 will be dropped around the time of net8.0 being released.
  • Introduced GraphQLFieldAttribute to allow you to rename fields in the schema as well as mark methods as fields in the schema. Method parameters will become field arguments in the same way as mutation methods. See updated docs for more information.
  • Argument types used for directvies now read DescriptionAttribute and GraphQLFieldAttribute to use different field name in the schema and set a description
  • Added GraphQLInputTypeAttribute. Whereas GraphQLArgumentsAttribute flattens the types properties into the schema, GraphQLInputTypeAttribute assumes the type is an input type and uses that as the schema argument
  • You may implement you own GraphQLValidator by implementing (and registering) IGraphQLValidator
  • Added a options.BeforeExecuting callback to allow modification of the expression before execution

Fixes

  • #266 - Fix error calling AddPossibleType() when some of the types have already been added to the schema
  • ExecutionOptions passed into IApplicationBuilder.UseGraphQLWebSockets() are now used when executing the queries for the subscription
  • #284 - Support generic class types as mutation arguments. MyClass<OtherClass> will become input MyClassOtherClass {}
  • #302 - Fix issue where using service fields with IQueryable/DbContext fields
EntityGraphQL - 4.3.0

Published by lukemurray over 1 year ago

Changes

  • #285 - Add support for implicit operators when converting types
  • Fix how EntityGraphQL evaluates the root level fields that return lists. If the return type of the field is nullable a null will be returned if the result is null. If the return type is non-nullable an empty List<T> will be returned.
public class UserDbContextNonNullable
{
    // empty list will be returned if UserIds resolves to null. If you use nullable types you can control with the ? operator (to return null)
    [GraphQLNotNull] 
    public List<string> UserIds { get; set; }
}

Fixes

  • #288 - fix stack overflow in RuntimeTypeJsonConverter
  • #291 - Fix ResolveWithService being called twice due to Expression.Condition if the field is a list and at the root level of the Query type
EntityGraphQL - 4.2.1

Published by lukemurray almost 2 years ago

Fixes

  • Fix issue selecting repeated fields from an interface and a fragment selection
  • Fix issue selecting interface fields from the concrete type in a fragment
EntityGraphQL - 4.2.0

Published by lukemurray almost 2 years ago

Changes

  • #281 - Implement allowed exceptions to allow exceptions to come into the error result when running with IsDevelopment == false as users not be able to modify the exceptions being thrown in order to have them implement IExposableException. Exceptions may be allowed with an exact type match, or allowed including all types that inherit it

Fixes

  • Prevent double SQL (when using against EF) query on base type (4.1 regression)
  • #279 - Remove duplicate fields when creating expressions
  • #280 - Fix for mutations that return interfaces/unions
EntityGraphQL - 4.1.2

Published by lukemurray almost 2 years ago

Fixes

  • Fix issue when using paging extension and aliases in the query e.g. { myList { myEdges: edges { .. } } } previously would fail
EntityGraphQL - 4.1.1

Published by lukemurray about 2 years ago

Fixes

  • #221 - Apply null check on the ToList expression built to resolve list expressions
  • Better support for service fields at the root query level
  • Fix support for service fields that take a complex type (object or enumerable) as arguments
  • Fix UseFilter() filter and UseSort() sort field arguments were incorrectly being marked as required in schema introspection
  • Fix issues with default sort values for UseSort() not appearing in the schema as default values
  • Fix output of default values in schema for lists and objects
EntityGraphQL - 4.1.0

Published by lukemurray about 2 years ago

Changes

  • #262/#205 - Option to prevent leaking internal exceptions into the 'errors' field on a result.

When running in development (read via IWebHostEnvironment.IsEnvironment("Development") or when manually creating SchemaProvider), messages of exceptions will not be dumped out into the 'errors' field of a query result, unless they implement the newly created (and empty) interface IExposableException.

  • #260 - Support default values in C# methods for mutations
  • #264 - Versions prior to .NET 7, System.Text.Json doesn't support the serialization of polymorphic type hierarchies. EntityGraphQL now registers a RuntimeTypeJsonConverter class as part of the DefaultGraphQLResponseSerializer

Fixes

  • #264 - Interface/union queries used to require you to query for at least 2 of the subtypes at once.
  • Fix issue with service fields that take nullable type fields as arguments
EntityGraphQL - 4.0.1

Published by lukemurray about 2 years ago

Fixes

  • #248 - Make sure delegates run on fields that map a list of items to a single item (e.g. myItem(id: Int!) @include(...) { ... })
  • #213 - Multiple levels of TargetInvocationException will now be unwrapped
  • #82 - SchemaBuilder can now handle fields that return Task<>. Note that the way that queries expressions are built you may still encounter issues with async fields not at the root query level. Please open an issue if you do
  • #259 - Fix introspection of nullable/non-nullable lists with nullable/non-nullable items
  • #239 - Fix issues rejoining main context from a service field
EntityGraphQL - 4.0.0

Published by lukemurray about 2 years ago

Fixes

  • #243 - support application/json; charset=utf-8 content type
EntityGraphQL - 4.0.0-beta2

Published by lukemurray about 2 years ago

Fixes

  • Fix issue related to #235 where the multiple fields are the same field with different alias and arguments

Breaking Changes

  • IFieldExtension.ProcessExpressionSelection now takes a ParameterExpression? argumentParam argument which is the argument parameter used at execution time (if there is one). Relating to #235
EntityGraphQL - 4.0.0-beta1

Published by lukemurray about 2 years ago

Breaking changes

  • DateTimeOffset is now added as a default scalar type in schema creation. It is a very common used type in EF contexts and trips up new users. If you previously were adding it as a scalar type you no longer need to. Or if you'd like to add it differently (like map it to Date) you can
services.AddGraphQLSchema<DemoContext>(options =>
{
    options.PreBuildSchemaFromContext = (schema) =>
    {
        schema.RemoveType<DateTimeOffset>();
        // add it how you want
    };
});
  • AddMutationsFrom and friends now take an optional SchemaBuilderMethodOptions options object to configure how mutations are built, following the SchemaBuilderOptions used elsewhere. See updated docs. Important defaults:
bool AutoCreateInputTypes = true; // Any input types seen will be added to the schema
bool AddNonAttributedMethods = false; // GraphQLMutationAttributes are still required by default
bool AutoCreateNewComplexTypes = true; // Return types of mutations will be added to the schema
  • SchemaBuilderOptions.IgnoreTypes Now uses Type instead of string. It is a HashSet<Type> now to avoid confusion ofwhich name to use (full name space or not)
  • ProcessExpressionSelection used in Field Extentions now takes Dictionary<IFieldKey, CompiledField> for the selectionExpressions parameter. IFieldKey is the field name and the schema type the field belongs too. Helps when dealing with inline fragments/union types where we may have multiple fields with the same name from different types.
  • MutationArgumentsAttribute renamed to GraphQLArgumentsAttribute and is used with subscriptions or mutaiton method arguments

Changes

  • Add support for GraphQL subscriptions - see updated documentation
  • Added support for definng Union types in the schema (#107)
  • Core library EntityGraphQL only targets netstandard2.1 as we do not need to multi-target and this still supports a large dotnet base (3.1+)

Fixes

  • Fix #206 - If a service field included a binary expression EntityGraphQL would sometimes build an incorrect selection expression
  • Fix #214 - The implicit conversion return type of a ArgumentHelper.Required<>() field argument is non-null
  • Fix #212 - Regression using a static or instance method in a service field
  • Fix #223 - Mutations with inline args don't support variables with different name to argument name
  • Fix #225 - Mutations with separate (not using MutationArgumentsAttribute) parameters fail if called without variables
  • Fix #229 - Using Field.Resolve() would incorrectly assume the field had a service
  • #219 - Handle conversion of variables as lists to a RequiredField<> arg of the list type
  • #215 - Fix issue using GraphQLValidator if using inline mutation arguments
  • #235 - Fix issue where arguments with the same name at the same level in a query would receive the same value
EntityGraphQL - 3.0.5

Published by lukemurray about 2 years ago

Fixes

  • Fix #197 - If a mutation returns Task<T> use T as the return type
  • Fix #204 - Nullable reference types correctly produce a nullable argument in the schema
  • If not using MutationArgumentsAttribute in mutation methods autoAddInputTypes was being ignored

From 3.0.4

  • Fix #194 - HasType() was not checking type mappings
EntityGraphQL - v3.0.3

Published by lukemurray about 2 years ago

Fixes

  • Prevent creation of invalid GraphQL schemas
    • Exception is thrown if you try to add a field with arrguments to types that do not support arguments - Enum & Input types
    • Exception is thrown if you try to add fields to a Scalar type
    • Exception is thrown on invalid type name
  • Schema builder now creates a valid GraphQL type name for generic types
  • Enum types are now added to the schema as a typed SchemaType<T> instance. Meaning you can fetch them using schema.Type<MyEnum>()
  • Fix #181 - Schema builder now correctly respects SchemaBuilderOptions.IgnoreTypes. Note it compares names against the Type.FullName
  • Fix #182 - Add missing dotnet scalar type for char. By default this is added as a schema scalar type named Char so the client can decide how to handle it. Over the wire it will serialize as a string (default for System.Text.Json). You can change default scalars and mappings by using the PreBuildSchemaFromContext action when adding your schema
services.AddGraphQLSchema<TContext>(options => {
  options.PreBuildSchemaFromContext = schema =>
  {
      // remove and/or add scalar types or mappings here. e.g.
      schema.AddScalarType<KeyValuePair<string, string>>("StringKeyValuePair", "Represents a pair of strings");
  };
})
  • When generating a field name for the field that takes an ID argument if the name generated matches the current field EntityGraphQL will add ById to the field name. E.g. a property List<LinePath> Line { get; set; } previously would try to add the line: [LinePath] field with no arguments and another field named line(id: ID!): LinePath. This causes an error. EntityGraphQL will name add lineById(id: ID!): LinePath. This is because the singularized version of "line" is "line".
  • In built field extensions now check if their extra types have already been added by using Type instead of name allowing you to add them with your own descriptions etc.
  • Fix mutations without any mutation arguments would incorrectly include the query context as an argument