Giter Club home page Giter Club logo

graphql-aspnet's People

Contributors

dependabot[bot] avatar fgruntjes avatar fuxiune avatar kevin-carroll avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

graphql-aspnet's Issues

Dictionary is not recognizing

Hey,

Kevin I am adding a Dictionary in my model but Query/Mutation is not recognizing it.
It should must be recognize by Query at least.

public Dictionary<string,string> Address { get; set; }

Thanks,
Pramod

Repeatable Directives (Oct2021)

Implement new specification feature of allowing repeatable directives and directive order significance:

Detailed In: Spec 3.13 Directives

Example:

directive @delegateField(name: String!) repeatable on OBJECT | INTERFACE

type Book
  @delegateField(name: "pageCount")
  @delegateField(name: "author")
{
  id: ID!
}

Ensure CORS Origin Policies on Sockets

When enabling websockets for subscription support using app.UseGraphQL(true) ensure that the socket configuration can be configured to:

  • Use the same origin policies as the main pipeline
  • Its own set of origins defined in the SchemaSocketsConfiguration section

Native Support for UShort

Support has been added for a 16bit integer, short. But support is still needed for its unsigned partner, ushort.

See PR #66 for short by Fuxiune for an example of the necessary changes to add a new scalar .

Execution Directives should target the query document

Current Behavior

Directives targeting Executable Locations currently function as pseudo field resolver extensions instead of allowing for the processing or modification of a query document.

A directive aimed at the location of FRAGMENT_DEFINITION or FRAGMENT_SPREAD, for instance, does not allow for processing or modification of the fragment itself. Instead those directives are chained into the field resolver pipeline to allow for modification of an already resolved result.

While it should be possible for an execution directive to modify the results of a field this should be done by modifying or customizing the field resolver processed by the engine....not by being an additional step in field resolution itself.

This makes sense in regards to consistency of implementation as well. A type system directive modifies an ISchemaItem as its added to the schema. Its only natural for an execution directive to target an IDocumentPart.

For example, extending a resolver involves modifying the definition of a IGraphField schema item as its being constructed not at some arbitrary point in the future. This behavior is well understood and supported by the implementation of multiple other GraphQL libraries. There is no reason why execution directives should function any differently or have special handling cases.

Expected Behavior

Execution Directives should perform similarly to type system directives. Where as type system directives target schema items as the schema is built, execution directives should target query document items and allow for the alteration or expansion of a query document before its executed.

Changes Needed:

  • The current model for the query documents needs to be made extendable, modifiable and more "developer friendly" so it can be processed in a custom directive"
    • This includes the invocation contexts created during document construction
  • Query validation routines must adjusted to allow for separating and applying document construction validation differently than schema invocation validation. Currently this happens in one step with no ability for directives to get in the middle and make necessary document updates.
  • There must be explicit support for:
    • Modifying field resolvers for one specific query without effecting the resolver attached to the field on the schema
    • Dropping fields, fragement spreads and inline fragements from the as-yet-to-be-executed-query to continue to support @skip and @include correctly
  • Remove support for DirectiveInvocationPhase, the concept will no longer apply.

Related Issues: #56

Exception thrown when using BatchTypeExtension and Execution Metrics

I have followd the documentation upon using BatchTypeExtension to get nested many-to-many results and got the following exception:
Unhandled Exception | Type: 'GraphTypeDeclarationException', Message: 'Graph Type Mismatch, List<Bakery>. Collections and KeyValuePair enumerable types cannot be directly searched. Instead, search for the types supplied to the generic type declaration.

The code I am using is the code from the example in the documentation:

public class BakedGoodsCompanyController : GraphController
{
    [QueryRoot("bakeries")]
    public async Task<List<Bakery>> RetrieveBakeries(Region region){/*...*/}

    // declare the batch operation as an extension
    [BatchTypeExtension(typeof(Bakery), "orders", typeof(List<CakeOrder>))]
    public async Task<IGraphActionResult> RetrieveCakeOrders(
        IEnumerable<Bakery> bakeries,
        int limitTo = 15)
    {
        //fetch all the orders at once
        var allOrders = await _service.RetrieveCakeOrders(bakeries.Select(x => x.Id), limitTo);

        // return the batch of orders
        return this.StartBatch()
            .FromSource(bakeries, bakery => bakery.Id)
            .WithResults(allOrders, cakeOrder => cakeOrder.BakeryId)
            .Complete();
    }
}

I couldn't find any place that uses the type mentioned in the exception above.
Also the nuget package did not contain the debugging symbols and I couldn't see what the middleware that throwing this exception actually does.
After I cloned the projected and built it wil in debug mode to generate the debugging symbols I was able to determine that the exception is thrown while the ApolloTracingMatricsV1 is trying to Generate Execution Result and to write down the request DataSource at line 191.

Confusing Message for Uncoercible List Variable Value

When a supplied value for a list variable is not coercible into the required type specified by the operation the error message can be confusing at times:

image

While the variable is correctly trapped and the query failed, the message indicates that a value of null was not valid. This is because the list resolver, when it fails to coerce a value, returns null. The list value resolver should throw an UnresolvedValueException like the scalar resolvers do and supply the appropriate information indicating the reason for failure.

Bug: Default Value Selection with Variables and field Non-Nullability

All listed scenarios currently do not function as expected

Scenario 1:

When an optional variable is not supplied, the default value of the usage location should be used

public class MyController : GraphController
{
    [QueryRoot]
    public int AddFive(int param = 5)
   {
        return param + 5;
   }
}
# Sample Query
query ($arg1 Int = null) {
    addFive(param: $arg1)
}
// No Supplied Variables
{  }

Expected Result:

{
   "data": {
      "addFive" : 10
   }
}

ActualResult:

// General error about a critical failure

Scenario 2:

When an optional variable is not supplied, but defines a usable default value, the default variable value should be used

public class MyController : GraphController
{
    [QueryRoot]
    public int AddFive(int param)
   {
        return param + 5;
   }
}
# Sample Query
query ($arg1 Int = 18) {
    addFive(param: $arg1)
}
// No Supplied Variables
{  }

Expected Result:

{
   "data": {
      "addFive" : 23
   }
}

ActualResult:

// Obfuscated error due to a thrown exception and a critical failure

Scenario 3:

When an optional, nullable variable is explicitly provided as null, the value should be rejected with a field error due to a 5.8.5 failure

public class MyController : GraphController
{
    [QueryRoot]
    public int AddFive(int param = 5)
   {
        return param + 5;
   }
}
# Sample Query
query ($arg1 Int = 34) {
    addFive(param: $arg1)
}
// Explicitly supplied as null (allowed for the arg, not for the usage location)
{  "arg1" : null }

Expected Result:

{
   "errors": []  // an error reporting supplied value mismatch
   "data": null
}

ActualResult:

// Obfuscated error due to a thrown exception and a critical failure

Not getting HttpContext in Query or Mutation

Hi Team,

I am trying to identify client IP but HttpContext is not getting. Below is a line of code.
Controller:

public class AuthGraphController : GraphController
{
[MutationRoot("token")]
public string Token(LoginModel model)
{
var IP=HttpContext?.Connection.RemoteIpAddress.ToString();
return IP;
}
}

Model:
public class LoginModel
{
[Required(ErrorMessage = "User Name is required")]
public string Username { get; set; }

    [Required(ErrorMessage = "Password is required")]
    public string Password { get; set; }
}

Please suggest if there is any alternate approach.

Bug: Variables not provided and not declared with a default value are treated as null

When a variable is declared on an operation without a default value it is required and expected to be provided when executing the query. Currently, nullable yet required variables are defaulting to null instead of resulting in an error.

Scenario

public class MyController : GraphController
{
    [QueryRoot]
    public int AddFive(int param = 5)
   {
        return param + 5;
   }
}
# Sample Query with required variable definition
query ($arg1 Int) {
    addFive(param: $arg1)
}
// Variable not provided
{  }

Expected Result:

{
   "errors": [
   // Error with INVALID_VARIABLE_VALUE code
   ]
   "data": null
}

ActualResult:

{
   "data": {
        "addFive" : 10
    }
}

Explanation: The variable $arg1 is being defaulted to null allowing the default value for param to take effect. Since the variable does not define a default value, it is required and must be provided.

Scoped Controllers causing a Race Condition in Ef Core DbContext

Hi
I really appreciate this library and the concept of it.
I have a small challenge.
I try to perform this query:
`# Write your query or mutation here
query {

vendor{
loadAll{id name}
loadById(id: "a07a864d-77a6-44a7-a3d8-20e21e1d8887") {
name
id
}
}
}`
But only the second operation gets a result, the first one is always null

The code for the 2 operations looks like this and both endpoints are hit and returns data:
` [Query]
public async Task<Vendor?> LoadById(Guid id)
{
var data = await _vendorService.LoadById(id);
return data != null ? new Vendor(data) : null;
}

    [Query]
    public async Task<IEnumerable<Vendor>> LoadAll()
    {
        var data = await _vendorService.LoadAll();
        return data != null ? data.Select(m=> new Vendor(m)) : Array.Empty<Vendor>();
    }`

The result always looks like this:
{ "data": { "vendor": { "loadAll": null, "loadById": { "name": "KlostergadeCentret", "id": "a07a864d-77a6-44a7-a3d8-20e21e1d8887" } } } }

Am i doing something wrong or is this a limit in the current version ?
I am using the newest one.

Query Plan Serialization for OutOfProcess Storage

Currently query plans are stored in process with all method and pointers intact. Develop a way to serialize query plans such that they can be serialized to Reddis or other out of process medium then re-hydrated with appropriate resolvers when brought in process and deserialized.

Order of assigning Custom Http Processors with the Multipart Extension

When using the multipart form extension if you disable the extension's ability to register its own http processor, but still require that it check for a compatible custom processor an exception will be thrown indicating that your custom processor is not compatible even when it is.

// startup code
services.AddGraphQL(options => {    

    options.QueryHandler.HttpProcessorType = typeof(MyCustomCompatiableProcessor);

    // register the extension but tell it not to swap out the processor
    options.AddMultipartRequestSupport(mpOptions =>  {
          mpOptions.RegisterMultipartRequestHttpProcessor = false;
    });    
});

โœ… Expected Behavior: The extension should continue to function as expected. The above scenario is valid.

โŒ Actual Behavior: An exception is thrown with the message:

The HttpProcessorType registered by the MultipartRequestServerExtension was removed or 
replaced during the configuration of schema 'GraphScehma`. Extension initialization cannot be completed.

Work around:

Register the extension first, allowing it to register its own processor, then assign your's that inherits from the multipart processor.

// startup code
services.AddGraphQL(options => {    
    options.AddMultipartRequestSupport();    
    options.QueryHandler.HttpProcessorType = typeof(MyCustomCompatiableProcessor);
});

Support for Default Values on INPUT_OBJECT fields

Currently a field on an INPUT_OBJECT can be inferred as required or not (depending on the nullability of the datatype) but there is no mechanism to supply a non-null, default value for a field on an INPUT_OBJECT when the field is not supplied on a query document.

This ability to supply a default value is required as outlined in section 3.10 of the specification.

Proposed Solution:

Add an additional parameter to [GraphField] to allow for the definition of a default value:

Example:

public class Person
{
   public string FirstName { get; set; }
   public string LastName { get; set; }

   [GraphFIeld(DefaultValue = true)]
   public bool IsHappy{ get; set; }
}

The DefaultValue property would be ignored if the C# type is used as an OBJECT graph type.

This has the effect of marking IsHappy as not required and have the following values in the following query situations

# isHappy= true
query { 
   addPerson(person: {firstName: "bob", lastName: "smith"})    
}

# isHappy= true
query { 
   addPerson(person: {firstName: "bob", lastName: "smith", isHappy: true})    
}

# isDeceased = false
query { 
   addPerson(person: {firstName: "bob", lastName: "smith", isHappy: false})    
}

# error, value cannot be null
query { 
   addPerson(person: {firstName: "bob", lastName: "smith", isHappy: null})    
}

Support for Minimal API

Add support for Minimal APIs in a manner consistent with what Microsoft has done with REST controllers in .NET 6.

Theoretical Example:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IPersonService, PersonService>();
var app = builder.Build();




// An Example Query 
app.MapQuery( "person", 
    (IPersonService service, int id ) => 
      {
          return service.FindPerson(id)
      });

// An Example Mutation
app.MapMutation("updatePerson", 
    (IPersonService service, Person person ) => 
      {
          var completedSuccessfully = service.UpdatePerson(person);
          return completedSuccessfully;
      });

app.Run();

Issues to consider:

  • How to distinguish input parameters from injected services in the method signature in order to build the schema?
    1. One version of minimal apis used a [FromServices] attribute to make the distinction, perhaps something is similar could work here?
    2. Delay schema generation until later in the start up sequence and use the DI container itself to determine what parameters are injectable while constructing the runtime schema?
    3. Something else?

EF Core lazy-loading proxies trigger rule 6.4.3

When using Microsoft.EntityFrameworkCore.Proxies for lazy-loading the relations, rule 6.4.3 of the GraphQL spec is triggered.

This is because the actual models, e.g. Person are wrapped by a proxy class like Castle.Proxies.PersonProxy that extend the actual model.

The critical class is GraphQL.AspNet.ValidationRules.RuleSets.FieldResolution.FieldCompletion.Rule_6_4_3_ServerValueCompletion, specifically line 65. context.Schema.KnownTypes.FindGraphType() returns null, since the proxy is not registered.

I'm not sure what the best solution is, especially because I just started looking into the source code.

Field Authorization Fails when specifying an Authentication Scheme

When adding authorization requirements to a graph method that specify that only certain schemes can be used authorization fails.

For instance if the user authenticated with a Bearer Token:

This executes as expected for an authenticated user

[QueryRoot]
[Authorize]
public int MyMethod()
{
    return 0; // Success!
}

This fails even though the user was authenticated with a JWT bearer token:

[QueryRoot]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public int MyMethod()
{
    return 0; // User does not pass authorization, method is never called.
}

Method-based field inheritance is not working

Given a field declared on a base class, child classes exposed on a schema do not expose the fields even though they should.

Given this model:

public class Person
{
    [GraphField]
    public int AgeInYear(int year)
    {
        return year - this.BirthYear;
    }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public int BirthYear { get; set; }
}

public class Employee : Person
{
    public string FullName => $"{this.FirstName} {this.LastName}";
}

Current Behavior:

The resultant schema type for Employee is:

 # Note that ageInYear is not present
type Employee {
  fullName: String
  firstName: String
  lastName: String
  birthYear: Int!
}

Expected Behavior

ageinYear, an explicitly declared field, should be present on the employee type in the same way that property fields show.

type Employee {
  ageInYear(year: Int!): Int!
  fullName: String
  firstName: String
  lastName: String
  birthYear: Int!
}

How to create custom exception?

I really thanks to you all, develop this library. Because this is the best for aspdotnet, for me.

but I found it difficult to create informative custom exception

for example:

if (!Guid.TryParse(userId, out actorID))
{
            throw new GraphqlException("userID not valid");
}

in GraphqlException only simple GraphqlException: Exception I dont make any logic in it.

it will only return problem in server.

any suggestion for custom exception?

or may be I can use success error message schema?

Thanks for dicussion

Non-Aliased, unmergable fields on multiple fragments do not fail Validation

Consider the query:

query {
     allPeopleMovers {
         ... on Elevator {
                 id
                 name
                 speed(inMeters: false)
         }
         ... EscaFragment
         ... ElevFragment
     }
}

fragment EscaFragment on Escalator {
  id
  name
  speed(inMeters: false)
}

fragment ElevFragment on Elevator {
  id
  name
  speed(inMeters: true)
}

The inline fragment on Elevator and the named fragment ElevFragment both include the field speed but with different arguments. These fields are not mergable and are both present in the allPeopleMovers selection set.

Expected Behavior

Rule 5.3.2 should trigger and fail validation. The query should be rejected with an INVALID_DOCUMENT code.

Current Behavior

Indeterminate. No error occurs. One field is chosen (typically the first one) to be resolved. All other fields are quietly dropped.

How to set nullable Guid?

I already create Model with nullable guid like this

public class MyModel {
  public Guid? MyID {get; set;}
}

and I place it as parameter

[MutationRoot("createSalesOrder", typeof(Response<Guid>))]
    public async Task<IGraphActionResult> Create(MyModel param)
    {
        return Ok(new Response<Guid>(Guid.NewGuid(), "Success"));
    }

and this is my mutation:

mutation SalesCreate($myId Guid){
   createSalesOrder(param : {myId: $myId}){
       data,
       error
   }
}

and I tried with empty variable {} or {myId: null}

but I get this error:

{
  "errors": [
    {
      "message": "The value '\"\"' cannot be coerced or resolved for the target location (System Type: Guid).",
      "locations": [
        {
          "line": 1,
          "column": 1
        }
      ],
      "extensions": {
        "code": "INVALID_VARIABLE_VALUE",
        "timestamp": "2022-12-28T05:15:13.836+07:00",
        "severity": "CRITICAL"
      }
    }
  ]
}

so how to set nullable Guid properly?

Expose Http Request Cancelation Token to Graph Controllers

Action methods on regular ASP.NET Controllers have the ability to accept a CancellationToken supplied by the .net runtime governing the entire HTTP request. Add this option to GraphController methods such that if the user defines a CancellationToken, the runtime will fill it with this top level CancelToken to allow user code to work with it.

Also, there is one point in the runtime where, when the query begins to execute, the runtime will generate a new CancellationToken to facilitate a timeout mechanism. favor the Http Request cancel token when its available instead of creating a new cancel source.

Not supplying an input object when nullable throws an exception

Summary
Nullable arguments, (fields and directives) without a defined default value, when not supplied to a field or directive on a query, should be interpreted as being optional per rule 5.4.2.1. While the validation engine is correctly validating the document, the runtime incorrectly thinks the argument is required since it doesn't declare an explicit default value and tries to extract a non-existent argument declaration from the supplied collection.

Given this scenario:

Controller:

public class MyController: GraphController
{
   [QueryRoot]
   public List<Person> SearchPersons(SearchParams data)
   {
       return null;
   }
}

Sample Query:

quey {
    searchPersons { 
        id
         name
    }
}

Expected Behavior:
With the data argument being nullable and not supplied on the query the SearchPersons method should receive null for the parameter data as defined by rule 5.4.2.1.

Current Behavior
Since the argument has no default value defined the engine is incorrectly interpreting the argument as being required and expecting a value to be present in the arguments collection and throws a KeyNotFoundException.

Additional Info:
Given the above controller and assuming the input object SearchParams has no required fields the following queries should be accepted as valid as well:

quey {
    searchPersons(data: null) { 
        id
         name
    }
}
quey {
    searchPersons(data: {}) { 
        id
         name
    }
}

Description for Inherited interface fields not shown during Introspection

Extended interfaces do not render the description for parent interface fields as part of the introspection data as expected:

Given:

public interface IPerson 
{
    [Description("The Person's Name")]
    public string Name { get; set; }
}

public interface ITeacher : IPerson
{
    [Description("The school the teacher teaches at")]
    public string School {get; set;}
}

And an Introspection Query:

 {
   __type(name: "ITeacher") {
        name
        kind
        interfaces {
            name
        }
        fields {
             name
             description
        }
    }
}

Expected Result:

 {
     "data": {
         "__type": {
              "name": "ITeacher",
              "kind":"INTERFACE",
              "interfaces": [
                  {
                     "name": "IPerson"
                  }
              ],
              "fields": [
                  {
                      "name": "name",
                      "description": "The Person's Name"
                  },
                  {
                      "name": "school",
                      "description": "The school the teacher teaches at"
                  }
              ]
          }
      }
}

Actual Result:

 {
     "data": {
         "__type": {
              "name": "ITeacher",
              "kind":"INTERFACE",
              "interfaces": [
                  {
                     "name": "IPerson"
                  }
              ],
              "fields": [
                  {
                      "name": "name",
                      "description": null
                  },
                  {
                      "name": "school",
                      "description": "The school the teacher teaches at"
                  }
              ]
          }
      }
}

Add custom type support for OBJECT and INPUT_OBJECT

Currently all OBJECT and INPUT_OBJECT type generation is done via templating. This is proving a bit limiting for some special use cases where a developer may want to provide custom serialization and deserialization logic to support non-traditional or unsupported use cases by the templating system.

For example, KeyValuePair<,> has no declared setters for Key and Value and as a result the library cannot populate the properties when used as an INPUT_OBJECT.

This issue tracks the development of a feature such that OBJECT and INPUT_OBJECT types can be declared explicitly in a manner similar to defining scalars, bypassing the templating system altogether.

Once complete, the library will natively support KeyValuePair<,> as an INPUT_OBJECT

Example of unit testing on the StarWars schema

Hello,

I am trying to make work the unit tests, provided by that library. My idea was to perform the actual queries and compare the result, provided by controller from mock DB, to the expected output.

My actual test code looks so:

            var builder = new TestServerBuilder();
            builder.AddGraphQL(o =>
            {
                o.AddGraphType<Test>();
            });
            builder.Authorization.AddClaimPolicy("RequiresPolicy5", "testClaim5", "testClaim5Value");

            // method policy
            builder.Authorization.AddRolePolicy("RequiresRole1", "role1");

            // user meets controller policy
            builder.User.AddUserClaim("testClaim5", "testClaim5Value");

            // user does not meet method policy
            builder.User.AddUserRole("role5");

            var server = builder.Build();

            var query = @"
                {
                    test {
                        locations() {
                            data {
                                id
                            }
                        }
                    }
                }
            ";

            var processor = server.CreateHttpQueryProcessor();
            var httpContext = server.CreateHttpContext(new GraphQueryData()
            {
                Query = query,
                OperationName = null,
            });
            httpContext.Request.Headers.Add("Authorization", "Bearer sdflkjdsf");

            var response = httpContext.Response;
            await processor.Invoke(httpContext);

            string responseText;

            response.Body.Seek(0, SeekOrigin.Begin);
            using (var reader = new StreamReader(response.Body))
                responseText = reader.ReadToEnd();

Test controller works fine in the dev environment, and I am able to get the actual data using GraphQL Playground. But if I try to run that in unit tests and put breakpoints in the test case and inside the controller method, breakpoint in the controller is never called (seems like it is not called at all?), and responseText has the following content:

   "errors":[
      {
         "message":"Operation failed.",
         "locations":[
            {
               "line":4,
               "column":25
            }
         ],
         "path":[
            "kpi",
            "locations"
         ],
         "extensions":{
            "code":"UNHANDLED_EXCEPTION",
            "timestamp":"2021-10-22T15:54:15.340+00:00",
            "severity":"CRITICAL"
         }
      }
   ]
}

What am I missing in that case?

Schema with mandatory and optional attributes

I couldn't find anywhere in the docs:
If I create a class that will represent a GraphQL Input object, ALL my attributes are optional.
Is there a way to make them mandatory with Annotations?

Allow Origin Filtering per schema

ASPNET core requires a set of origins be supplied on the UseWebSockets call when configuring them. However, individual schemas should be allowed to further restrict this list on a "per schema basis".

GraphQL File Upload Support

Add intrinsic support for the graphql-multipart-request-spec to support file uploads through a graphql query.

Note submission of the below queries requires conforming to the specification for defining the operations and map fields in the multi-part form data payload. A compatible client must be used or the operation will fail.

Configuration

Support can be added via a server extension. The extension will ship as part of the core library, but must be explicitly added to be enabled:

// Startup Code
services.AddGraphQL(options => 
{
     options.RegisterExtension<MuitipartRequestServerExtension>();
});

Single File Upload

A class named FileUpload representing a single file will be registered as a scalar and will capture the details of the file reference:

public class MyUploadController: GraphController
{

   [MutationRoot("submitData")]
    public async Task<int>  SubmitData(FileUpload file)
    {
       if (file?.FileStream != null) {
          // do something with the file stream
       }

       return 0;
    }
}
# Sample query
mutation  ($file1: Upload!) {
    submitData(file: $file1)
}
// variables, expecting 1 single file uploaded
{
    "file": null
}

Multi-File Upload

Like with any other list or array in graphql, declare a variable as [Upload] and accept multiple files to your controller.

public class MyUploadController: GraphController
{
   [MutationRoot("submitData")]
    public async Task<int>  SubmitData(IList<FileUpload> allFiles)
    {
        foreach (FileUpload file in allFiles)
        {
              if (file?.FileStream != null) {
                 // do something with the file stream
             }
        }
       return 0;
    }
}
# Sample query
mutation  ($filesCollection: [Upload!]) {
    submitData(allFiles: $filesCollection)
}
// variables, expecting 3 uploaded and mapped files
{
    "filesCollection": [null, null, null]
}

Issue while using Multiple JWTToken Bearer

Hi,

we have a requirement to add multiple jwt token bearer. One using the B2C authentication and other Azure AD authentication.
Following is the code snippet from the Startup.cs class.

services.AddAuthentication()
.AddJwtBearer("AzureAD", options =>
{

                options.Authority = $"XXXXXXXXXXXXXX";
                options.Audience = $"XXXXXXXXXXXXXX";
                
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidIssuer = $"XXXXXXXX",
                    ValidAudience = $"XXXXXXXXXXXXXX",
                };
            })
         .AddJwtBearer("B2C",options =>
          {
              options.Audience = $"XXXXXXXXXXXXXX";
              options.Authority = $"XXXXXXXXXXXXXX";                  
              options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
              {
                  ValidAudience = $"XXXXXXXXXXXXXX",
                  ValidIssuer = $"XXXXXXXXXXXXXX"
              };
          });

        services.AddAuthorization(options =>
        {
            var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
                "B2C",
                "AzureAD");
            defaultAuthorizationPolicyBuilder =
                defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
            options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
        });

It works if we change the route attribute in the controller to use ASP.NET Route attribute but breaks if we use GraphRoute attribute at the controller level.

Works:
[Authorize]
[Route("abc")]
public class AbcController : GraphController
{
}

Error:
[Authorize]
[GraphRoute("abc")]
public class AbcController : GraphController
{
}

Request you kindly help us in solving the problem.

Allow same Enum Value

really hoping to help you out as much as possible (:
Consider the following

// Cc.cs
    [GraphType]
    [Description("CC")]
     public enum Cc : uint
    {
        None = 0,
        First = 287,
        NvUndefineSpaceSpecial = 287,
        EvictControl = 288,
// Omitted for brevity
      Application startup exception
      System.ArgumentException: An item with the same key has already been added. Key: NVUNDEFINESPACESPECIAL
         at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
         at GraphQL.AspNet.Defaults.TypeMakers.EnumGraphTypeMaker.CreateGraphType(Type concreteType)
         at GraphQL.AspNet.Schemas.GraphSchemaManager.EnsureGraphType(Type type, Nullable`1 kind)
         at GraphQL.AspNet.Execution.GraphSchemaInitializer.Initialize(ISchema schema)
         at GraphQL.AspNet.Configuration.Mvc.GraphQLSchemaInjector`1.BuildNewSchemaInstance(IServiceProvider serviceProvider)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
         at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
         at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
         at GraphQL.AspNet.ApolloSubscriptionServerSchemaExtension`1.CreateSubscriptionServer(IServiceProvider sp)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)

         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
         at Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)

Furthermore I will more than likely discuss flagged based enums as well... Because it does feed into this example...

Whether this helps or not... From my understanding (without looking throughout your code) KEY = uint/int/etc... VALUE=the label assigned? if this is correct then it should be supper to make the Value some list (assuming you are tracking it as a string) you could go through check on GraphQL object side if object attribute is list then the resulting C# Enum.HasFlag() and its value results to X ( | or all the keys in the map) if not then the input GraphQl data coming in would result to the Key in the map to which the Value contains the string.

Just a suggestion.. and maybe inaccurate/incomplete.

This is amazing!!! cheers.

SignalR connector for Apollo Client

Investigate and create a network adapter for the Apollo javascript client that allows apollo to do subscriptions over signalR as opposed to a flat web sockets.

Add additional log events when "development" settings are used in a production environment

When the configured environment is not Development (as defined by the environment variables) and any of the "development intensive" configuration settings are set, add a log event at the warning level indicating such.

Settings that if true would trigger the warning:

Execution.EnableMetrics
Execution.AwaitEachRequestedField
Response.ExposeExceptions
Rsponse.ExposeMetrics

HTTP GET support and query url param

The GraphQL recommendation is to support both GET and POST.

But when trying GET on graphql-aspnet it's throwing error:

GraphQL queries should be executed as a POST request

Even when using POST, there's a recommendation of accepting the query parameter from the URL query string, like:
http://myapi/graphql?query={me{name}}

attempting this it also fails trying to parse the body.

Missing __DirectiveLocation options

Hello,

I have recently found that excellent project, but I have a problem of implementation the directive. I have followed the docs and implemented sample directive, which is visible in a schema, but how do I apply it to the certain query?

The result I would like to have:
type Query { sampleQuery: [String] @sampleDir }

Is it possible to have something like this in schema?

Description for [TypeExtension] not available during introspection

Declaring a [TypeExtension] to add a field to an OBJECT does not render the description as part of the introspection data as expected:

Given:

public class Person 
{
    [Description("The Person's First Name")]
    public string FirstName { get; set; }
}

public class PersonExtensionController: GraphController
{
  [TypeExtension(typeof(Person), "lastName")]
  [Description("The Person's Last name")]
   public string LastName(Person person)
  {
      return "Some Last Name";  
  }
}

And an Introspection Query:

 {
   __type(name: "Person") {
        name
        kind
        fields {
             name
             description
        }
    }
}

Expected Result:

 {
     "data": {
         "__type": {
              "name": "TwoPropertyObject",
              "kind":"OBJECT",
              "fields": [
                  {
                      "name": "firstName",
                      "description": "The Person's First Name"
                  },
                  {
                      "name": "lastName",
                      "description": "The Person's Last Name"
                  }
              ]
          }
      }
}

Actual Result:

 {
     "data": {
         "__type": {
              "name": "TwoPropertyObject",
              "kind":"OBJECT",
              "fields": [
                  {
                      "name": "firstName",
                      "description": "The Person's First Name"
                  },
                  {
                      "name": "lastName",
                      "description": null
                  }
              ]
          }
      }
}

How to use the new MuitipartRequestServerExtension() with a Custom-HttpProcessor ?

Hi,

After the GraphQL File Upload Support was released I tried to integrate it into my solution which already contains a custom HTTP processor. However, the features are conflicting, as seen in my Program.cs (DI settings).

image

When I try to start up my solution I have this error below:

image

I've already tried to change the settings order but then I received an "overwrite" error, where it seems HttpProcessorType of MultipartRequestServerExtension was removed/overwritten by my custom HTTP processor, as you can see below:

image
image

Could someone help me by making my custom HTTP Processor and MultipartRequestServerExtension work together?

PS. So far to unblock me I create another schema for managing file upload, it is working but it's still a workaround.

Tks

EF lazy-loading for related data

Just came across this project and it looks awesome!
Im trying query lazy-loaded related data on a ef-context, but im receiving null. (You can have a look at my code here).

Is there a way to fix this apart from creating a type extension?

My model:

public class Blog
    {
        public int BlogId { get; set; }
        public string Url { get; set; }

        public virtual IList<Post> Posts { get; set; }
    }

    public class Post
    {
        public int PostId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }

        public int BlogId { get; set; }
        public virtual Blog Blog { get; set; }
    }

When querying Posts on a Blog, the posts field will be null:

query {
  blogs {
    blogId
    url
    posts {
      content
    }
  }
}

Above returns:

{
  "data": {
    "blogs": [
      {
        "blogId": 1,
        "url": "test",
        "posts": null
      }
    ]
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.