Code Monkey home page Code Monkey logo

graphql-aspnetcore's Introduction

GraphQl.AspNetCore

This repo is outdated. See https://github.com/graphql-dotnet to use a really good GraphQL library for .NET

The feedback about my last blog post about the GraphQL end-point in ASP.NET Core was amazing. That post was mentioned on reddit, many times shared on twitter, lInked on http://asp.net and - I'm pretty glad about that - it was mentioned in the ASP.NET Community Standup.

Because of that and because GraphQL is really awesome, I decided to make the GraphQL MiddleWare available as a NuGet package. I did some small improvements to make this MiddleWare more configurable and more easy to use in the Startup.cs

Branches & contributing & testing

The master branch is the stable branch and I don't axcept PRs to that branch. To contribute, please create PRs based on the develop branch. To play around with the latest changes, please also use the develop branch.

Changes on the develop branch ("next version" branch) will be pushed as preview releases to MyGet. To see whether this branch is stable, follow the builds on AppVeyor: Build status

Changes on the master branch ("current version" branch) will be pushed as releases to NuGet. To see whether this branch is stable, follow the builds on AppVeyor: Build status

Usage and short documentation

NuGet

Preview builds on MyGet and release builds on NuGet.

Install that package via Package Manager Console:

PM> Install-Package GraphQl.AspNetCore

Install via dotnet CLI:

dotnet add package GraphQl.AspNetCore

Using the library

You still need to configure your GraphQL schema using the graphql-dotnet library, as described in my last post.

First configure your schema(s) in the ConfigureServices method in Startup.cs. Make sure all referenced graph types are registered as well so they can be resolved from the container.

// Configure the default schema
services.AddGraphQl(schema =>
{
    schema.SetQueryType<BooksQuery>();
    schema.SetMutationType<BooksMutation>();
});

// Also register all graph types
services.AddSingleton<BooksQuery>();
services.AddSingleton<BooksMutation>();
services.AddSingleton<BookType>();
services.AddSingleton<AuthorType>();
services.AddSingleton<PublisherType>();
// ... more types if needed

In the Configure method, you add the GraphQL middleware like this:

You can use different ways to register the GraphQlMiddleware:

// the simplest form to use GraphQl. defaults to '/graphql' with default options
app.UseGraphQl();

// or specify options only (default path)
app.UseGraphQl(new GraphQlMiddlewareOptions
{
    FormatOutput = true, // default
    ComplexityConfiguration = new ComplexityConfiguration()); //default
});

app.UseGraphQl(options =>
{
    options.EnableMetrics = true;
});

// or specify path and options

app.UseGraphQl("/graphql", new GraphQlMiddlewareOptions
{
    FormatOutput = true, // default
    ComplexityConfiguration = new ComplexityConfiguration()); //default
});

// or like this:

app.UseGraphQl("/graph-api", options =>
{
    options.SchemaName = "OtherSchema"; // only if additional schemas were registered in ConfigureServices
    //options.AuthorizationPolicy = "Authenticated"; // optional
});

Personally I prefer the second way, which is more readable in my opinion.

Options

The GraphQlMiddlewareOptions are pretty simple.

  • SchemaName: This specifies the registered schema name to use. Leave null for the default schema.
  • AuthorizationPolicy: This configures the authorization policy name to apply to the GraphQL endpoint.
  • FormatOutput: This property defines whether the output is prettified and indented for debugging purposes. The default is set to true.
  • ComplexityConfiguration: This property is used to customize the complexity configuration.
  • ExposeExceptions: This property controls whether exception details such as stack traces should be returned to clients. This defaults to false and should only be set to true in the Development environment.
  • EnableMetrics: Enable metrics defaults to false. See GraphQL .net client documentation how to create a stats report.

This should be enough for the first time. If needed it is possible to expose the Newtonsoft.JSON settings, which are used in GraphQL library later on.

GraphQL.AspNetCore.Graphiql

This library provides a middleware to add a GraphiQL UI to your GraphQL endpoint. To learn more about it and the way I created it, read the blog post about it: GraphiQL for ASP.NET Core

NuGet

Preview builds on MyGet and release builds on NuGet.

Install that package via Package Manager Console:

PM> Install-Package GraphQl.AspNetCore.Graphiql

Install via dotnet CLI:

dotnet add package GraphQl.AspNetCore.Graphiql

Using the library

Open your Startup.cs and configure the middleware in the Configure method.

You can use two different ways to register the GraphiqlMiddleware:

app.UseGraphiql("/graphiql", new GraphQlMiddlewareOptions
{
    GraphQlEndpoint = "/graphql"
});


app.UseGraphiql("/graphiql", options =>
{
    options.GraphQlEndpoint = "/graphql";
});

Personally I prefer the second way, which is more readable in my opinion.

The GraphQlEndpoint needs to match the path a GraphQL endpoint.

Options

Currently the options just have two properties:

  • GraphQlEndpoint: This is the path of your GraphQL end-point, configured with the GraphQlMiddleware. In theory it could be any possible path or URL that provides an GraphQL endpoint. Until now, I just tested it with the GraphQlMiddleware.

One more thing

I would be happy, if you try this library and get me some feedback about it. A demo application to quickly start playing around with it, is available here on GitHub. Feel free to raise some issues and to create some PRs to improve this MiddleWare.

graphql-aspnetcore's People

Contributors

asynts avatar codetherapist avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar enkodellc avatar hd-devops avatar johanneshoppe avatar juergengutsch avatar lextas avatar peterbucher avatar poulad avatar sunsided 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  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-aspnetcore's Issues

Support to resolve instance of DocumentExecuter that were registered per scope

Related to #29

This issue is also to decide whether we add the DocumentExecuter as singleton or as scoped instance to the IoC. It seems the IoC is not able to resolve the DocumentExecuter from scope, even if the MiddleWare is running in the default ASP.NET Core pipeline.
(We should also do some investigation on why it is not working)

System.InvalidOperationException: 'Sequence contains no matching element'

{
book(isbn: "822-5-315140-65-3"){
isbn,
name
}
}

System.InvalidOperationException occurred
HResult=0x80131509
Message=Sequence contains no matching element
Source=
StackTrace:
at System.Linq.Enumerable.First[TSource](IEnumerable1 source, Func2 predicate)
at GraphQlDemo.Data.BookRepository.BookByIsbn(String isbn) in D:\Test2\graphql-aspnetcore\GraphQlDemo\data\PersonRepository.cs:line 65
at GraphQlDemo.Query.GraphQlTypes.BooksQuery.<>c__DisplayClass0_0.<.ctor>b__0(ResolveFieldContext1 context) in D:\Test2\graphql-aspnetcore\GraphQlDemo.Query\GraphQlTypes\BookQuery.cs:line 16 at GraphQL.Resolvers.FuncFieldResolver2.GraphQL.Resolvers.IFieldResolver.Resolve(ResolveFieldContext context)
at GraphQL.Instrumentation.MiddlewareResolver.d__2.MoveNext()

Scope Issue

Hi @JuergenGutsch,
Can you please publish a new beta release to have the latest changes regarding Scope fixes.

Best regards,
Rajiv.

FluentValidation integration

Hi,
It would be great to have such support of FluentValidation on the pipe to easilly add validation for incoming mutations and queries like made here.

Best regards,
Rajiv.

Consider implementing Caching

By definition GraphQL can't use caching of routes, since it's always the same route. The following is just an idea to implement a Cache in the middleware component.

If we intercept every query coming to the server, create a hash and store it in a lookup table. the next time the request comes in(in x amount of seconds), simply return the cached item instead of resolving the entire query.

Coding standards improvements

Can we do the following (This really won't make any difference but standards should be maintained) -

  • app.UseGraphQl(); should be app.UseGraphQL();. this can be implemented throughout the project where we have GraphQl.
  • Moq testing.

options.RootGraphType must be a type

options.RootGraphType must be a type and not an instance in order to use DI.
In real world, bookrepo is a scoped service because it injects a DbContext.

options.RootGraphType = typeof(IBookRepository);

Query is too complex to execute.

I just wanted to play around with the demo.
Steps to reproduce

  1. Checkout 11c7156
  2. Open .sln in VS2017, compile & debug GraphQLDemo
  3. Open http://localhost:56416/graphiql
    Server sends immediately Exception: Internal Server Error
An unhandled exception occurred while processing the request.
AggregateException: One or more errors occurred. (Query is too complex to execute. The field with the highest complexity is: FragmentSpread{name='FullType', directives=GraphQL.Language.AST.Directives})
GraphQl.AspNetCore.GraphQlMiddleware.CheckForErrors(ExecutionResult result) in GraphQlMiddleware.cs, line 85

Exception: Query is too complex to execute. The field with the highest complexity is: FragmentSpread{name='FullType', directives=GraphQL.Language.AST.Directives}
GraphQl.AspNetCore.GraphQlMiddleware.CheckForErrors(ExecutionResult result)

Thrown here. Because of the failed IntrospectionQuery GraphiQL gets into a bogus state, e.g auto-completion does not work any longer.

  1. Now everything is screwed, e.g.
{
  books{
    isbn,
    name,
    author{
      id,
      name,
      birthdate
    }
  }
}

(as shown here: #3 (comment))

  1. this works
{
  books{
    isbn,
    name
  }
}

Suggestion:
The demo should have a lower ComplexityConfiguration. It's pretty uncool that the demo starts with an exception. E.g:

options.ComplexityConfiguration = new ComplexityConfiguration { MaxDepth = 15 }; 

A small PR is following soon.

CORS problem

Hi,
How to apply CORS policy for Graphql endpoint?

Best regards,
Dyesse.

Stable NuGet release

Hi
I see two issues tagged as bug here. Are those the reasons for not having a stable release?

Please let me know what stops a stable release to nuget. I'd like to help.

publish 1.1.4 to nuget

hi,
i'm using you library in one of my projects but i have to use the 1.1.4 version because i'm overriding the DocumentBuilder to return a custom document :).
would it be possible to publish that version to nuget? because every time i use the project i have to get the package from myget...
if not, do you have an idea on when a new release (even if its prerelease) gets published to the official nuget feed?
thanks in advance and keep up the great work! :)
greetings

GraphiQL fails to load schema

It seems GraphiQL page breaks on mobile browsers when loading my schema. But browsers load a sample implementation just fine. The GrahpiQL version used in this package is 0.11.2 and latest version is 0.11.11. How can I upgrade the GraphiQL HTML file used?

I also should mention that

  • this issue is not reproducible using the demo app provided in this repo
  • you can test this on a PC by enabling the mobile view in the browser
getNamedType@https://unpkg.com/[email protected]/graphiql.min.js:1:673502
getType@https://unpkg.com/[email protected]/graphiql.min.js:1:673306
getType@https://unpkg.com/[email protected]/graphiql.min.js:1:673126
getInputType@https://unpkg.com/[email protected]/graphiql.min.js:1:673782
buildInputValue@https://unpkg.com/[email protected]/graphiql.min.js:1:677522
[98]</exports.default/<@https://unpkg.com/[email protected]/graphiql.min.js:1:556376
[98]</exports.default@https://unpkg.com/[email protected]/graphiql.min.js:1:556321
buildInputValueDefMap@https://unpkg.com/[email protected]/graphiql.min.js:1:677353
buildFieldDefMap/<@https://unpkg.com/[email protected]/graphiql.min.js:1:677239
[98]</exports.default/<@https://unpkg.com/[email protected]/graphiql.min.js:1:556376
[98]</exports.default@https://unpkg.com/[email protected]/graphiql.min.js:1:556321
buildFieldDefMap@https://unpkg.com/[email protected]/graphiql.min.js:1:676947
fields@https://unpkg.com/[email protected]/graphiql.min.js:1:675632
resolveThunk@https://unpkg.com/[email protected]/graphiql.min.js:1:602132
defineFieldMap@https://unpkg.com/[email protected]/graphiql.min.js:1:603174
[112]</exports.GraphQLObjectType</GraphQLObjectType.prototype.getFields@https://unpkg.com/[email protected]/graphiql.min.js:1:611833
typeMapReducer@https://unpkg.com/[email protected]/graphiql.min.js:1:646099
GraphQLSchema@https://unpkg.com/[email protected]/graphiql.min.js:1:650168
[122]</exports.buildClientSchema@https://unpkg.com/[email protected]/graphiql.min.js:1:679656
value/<@https://unpkg.com/[email protected]/graphiql.min.js:1:46280

IQueryable support

First off I'm really impressed with how easy it was to get setup. Everything is done the "aspnetcore" way, and the graphiql addition... I love it!

But I found this library https://github.com/ckimes89/graphql-net that makes generating a schema and querying against it really really easy.
So I was wondering if some collaboration was possible :)

I mean services.AddGraphQl(schema => schema.AddType<Book>().AddAllFields()); would be a dream come true :D

RootValue is null

Thanks for this project!
I used the FileUpload types, mutations you provided on this project; I am using Apollo Client in my react application with the following configuration:

import { InMemoryCache } from "apollo-cache-inmemory";
import { ApolloLink } from "apollo-boost";
import ApolloClient from "apollo-client";
import { setContext } from "apollo-link-context";
import { createUploadLink } from "apollo-upload-client";

const authLink = setContext(async (_, { headers }) => {
   // auth link settings
});

const httpLink = createUploadLink({
  uri: "https://localhost:5001/graphql"
});
const cache = new InMemoryCache({
  dataIdFromObject: object => object.id
});
export const client = new ApolloClient({
  cache,
  link: ApolloLink.from([authLink, httpLink])
});

When I upload a file from my react application, RootValue gets null (var httpContext = (HttpContext)context.RootValue;). any idea?

GraphiQL not showing correctly

When I execute the current solution in master and open the graphiql endpoint, it doesn't appear correctly as shown in this screenshot.

2017-11-04 15_23_35-graphiql

Demo incomplete - No QueryArgument for limit

In your blogpost you show the following example:

The list is too large? Just limit the result, to get only 20 items:

{
  books(limit: 20) {
    isbn,
    name,
    author{
      id,
      name,
      birthdate
    }
  }
}

Problem:
This is not implemented in the demo, see here -- there is only a QueryArgument for isbn.

If I'm going to executing the query, the following error comes up:

An unhandled exception occurred while processing the request.
AggregateException: One or more errors occurred. (Unknown argument "limit" on field "books" of type "BooksQuery".)
GraphQl.AspNetCore.GraphQlMiddleware.CheckForErrors(ExecutionResult result) in GraphQlMiddleware.cs, line 85

Exception: Unknown argument "limit" on field "books" of type "BooksQuery".
GraphQl.AspNetCore.GraphQlMiddleware.CheckForErrors(ExecutionResult result)

Unable to convert list of string from input

There is an issue with parsing input types of ListGraphType<StringGraphType>. Check last commit on this branch to reproduce the issue.

https://github.com/pouladpld/graphql-aspnetcore/tree/string-list

Request

POST localhost:5000/graphql

{
    "query": "mutation FooMutation($foo: FooInput) { addFoo(foo: $foo) { bar, baz } }",
    "variables": {
        "foo": {
            "bar": "BAR",
            "baz": [ "BAZ", "baz" ]
        }
    }
}

Response

{
    "errors": [
        {
            "message": "Cannot convert value to AST: BAZ"
        }
    ]
}

I'm still investigating it and will try to make a PR.
This seems to be the cause of problem in GraphQL package:

graphql-dotnet/graphql-dotnet#389
graphql-dotnet/graphql-dotnet#394

Error with mutations with complex input types: "Unable to parse input as a type. Did you provide a List or Scalar value accidentally?"

Based on your code on development branch, and having the following:

On the server:

FieldAsync<OrganizationType>(
                "updateOrganization",
                arguments: new QueryArguments(
                new QueryArgument<NonNullGraphType<OrganizationUpdateType>> { Name = "organization" }
                ),
                resolve: async context =>
                {

                    var organization = context.GetArgument<Organization>("organization");
                    organization = await repository.OrganizationService.UpdateAsync(organization);
                    return organization;
                });

and this on the client, eg. graphiql:

mutation ($input: OrganizationUpdate!) {
  updateOrganization(organization: $input) {
    id
    name
    description
  }
}

(Query Variables)

{
  "input": {
    "id": 1,
    "name": "Some org, just renamed",
    "description": "sample description"
  } 
}  

posting this will result in graphql-net's error: Unable to parse input as a type. Did you provide a List or Scalar value accidentally?

Debugging GraphQlParameters, I noticed that when the client sends complex objects as inputs (see example above: the variable $input is an object, not a primitive type), that input get's json-deserialized into a JObject that looks like this:

Notice the double curly braces:

{{
  "id": 1,
  "name": "Some org, just renamed",
  "description": "sample description"
}}

This will cause the underlying graphql-net library to throw the error above.

A workaround is to check the type of each value in Variables and, if it's not a primitive type (but it's an instance of JObject), serialize that object, and then deserialized it again (to get rid of the nesting (double braces).

`This is a complete workaround (fix), but it seems ugly, you probably have a better solution:

using System.Collections.Generic;
using GraphQL;
using System.Linq;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;

namespace GraphQl.AspNetCore
{
    internal class GraphQlParameters
    {
        public string Query { get; set; }
        public string OperationName { get; set; }
        public Dictionary<string, object> Variables { get; set; }

        public Inputs GetInputs()
        {
            Dictionary<string, object> sanitizedVariables = null;

            if (Variables != null && Variables.Any())
            {
                sanitizedVariables = new Dictionary<string, object>();

                foreach (var key in Variables.Keys)
                {
                    var value = Variables[key];

                    if (value is JObject)
                    {
                        // fix the nesting ( {{ }} )
                        var serialized = JsonConvert.SerializeObject(value);
                        var deserialized = JsonConvert.DeserializeObject<Dictionary<string, object>>(serialized);
                        sanitizedVariables.Add(key, deserialized);
                    }
                    else
                    {
                        sanitizedVariables.Add(key, value);
                    }
                }

                return new Inputs(sanitizedVariables);
            }
            else
            {
                return (Variables != null) ? new Inputs(Variables) : new Inputs();
            }
        }
    }
}
``

Fix the AppVeyor Build

Currently the AppVeyor build is not running, because of an path issue. This need to be fixed asap

What is it ?

From the readme, it is not clear what GraphQL is or what it's use is, could you please enlighten us ?

named schemas

Hi,
I've just started working with the library, so I may be approaching this in the wrong way. To support multiple queries, it seems I need multiple endpoints and schemas. To allow for this, schemas need to be named. The following non-breaking change makes this possible (adding the schemaName parameter).

        public static IGraphQlBuilder AddGraphQl(this IServiceCollection services,
            Action<SchemaConfiguration> configure, string schemaName = null)
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services));

            if (configure == null)
                throw new ArgumentNullException(nameof(configure));

            services.AddSingleton<IDocumentExecuter, DocumentExecuter>();

            var builder = new GraphQlBuilder(services);

  // **** use schemaName parameter here
            var schema = new SchemaConfiguration(schemaName);
            configure(schema);

            return builder.AddSchema(schema);
        }

Then in ConfigureServices(...)

services.AddGraphQl(schema =>
{
	schema.SetQueryType<BooksQuery>();
}, "book");

and in Configure(...)

app.UseGraphQl("/graphql/book", options =>
{
	options.SchemaName = "book"; 
	options.FormatOutput = false;
	options.ComplexityConfiguration = new ComplexityConfiguration { MaxDepth = 15 };

});

Could you add this change?

OAuth 2.0?

Heya @JuergenGutsch ,

I'm really liking your work. I'm looking at integrating it in a project and I was thinking about security. If I am able to spend time getting OAuth 2.0 working with your middleware, would you be interested in having that contribution?

Great work so far!

Allow for tab indentation

The settings view only allows for space based indentation. All of our other languages are setup for tab indents. Please provide this option

API suggestions

I have some suggested improvements to the API. Let me know if you're open to them, and I'd be happy to make the changes.

I think something like this would be better for configuring the middleware:

app.UseGraphQl<BooksQuery>("/graph-api", options =>
{
    options.AuthorizationPolicy = "AuthenticatedUser";
    options.FormatOutput = false;
});

This has the following advantages:

  1. The root graph type is passed as a type parameter. This makes the code look cleaner, but more importantly, will allow the middleware to resolve the type from the container on each request. Currently all dependencies will be singletons.
  2. I think moving the path configuration to the method call makes it more obvious. It also allows you to add the middleware to the pipeline using Map(), so you don't need to check the path within the middleware itself.
  3. Finally, adding an AuthorizationPolicy property allows one to apply a defined authorization policy to the endpoint.

Multiple graphql endpoints

I am using "areas" in my ASP.NET Core application, and I am considering adding one graphql endpoint in each of the areas. Is it possible to use this middleware when adding multiple endpoints? Thanks!

Subscriptions Example

Hi,
I'm struggling trying to make subscriptions works.
Any tips, please?

Best regards,
Rajiv.

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.