Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Azure Functions support #966

Merged
merged 18 commits into from
Dec 9, 2022
Merged

Add Azure Functions support #966

merged 18 commits into from
Dec 9, 2022

Conversation

Shane32
Copy link
Member

@Shane32 Shane32 commented Dec 7, 2022

This PR adds support for Azure Functions. To use:

  1. Configure the Azure Function to use DI - see https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection
  2. Configure GraphQL via AddGraphQL the same way as is done elsewhere
  3. Add a call to .AddAzureFunctionsMiddleware() within the AddGraphQL call
  4. Add a HTTP function that returns an appropriate ActionResult:
    [FunctionName("GraphQL")]
    public static IActionResult RunGraphQL(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");

        return new AzureGraphQLActionResult(req);
    }

UI packages add an ActionResult to easily use them with controller projects or Azure Functions.

    [FunctionName("Playground")]
    public static IActionResult RunPlayground(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest req,
        ILogger log)
    {
        _ = req;
        log.LogInformation("Getting Playground UI.");

        return new PlaygroundActionResult(opts => opts.GraphQLEndPoint = "/api/graphql");
    }

Notes

  • The sample is based on the .NET template, and I think I read it has to be 6.0 becuase that's a LTS version (??)
  • I didn't actually try this in the cloud
  • Multiple schemas are supported by using typed calls - .AddAzureFunctionsMiddleware<T>() and return new AzureGraphQLActionResult<T>().
  • The middleware can have options configured on it via .AddAzureFunctionsMiddleware<T>(opts => { });
  • It is currently not possible with the new helper functions to have two different endpoints with different configurations for the same schema.
  • No breaking changes
  • UI packages add a dependency when using them with ASP.NET Core 2.x -- but no new dependency for ASP.NET Core 3.1+

Comments / questions:

  • Technically the new AzureGraphQLActionResult is not specific to Azure Functions. It could be used for ASP.NET Core also, but it is harder to use and inferior to the middleware technique we already support. In any case, we could drop the "Azure Functions" naming from the new classes/interfaces and call it something like GraphQLExecutionActionResult
  • We could eliminate the need to register the middleware in DI, similar to how the UI action results work, but then there is a bit of startup overhead for each request. Not sure if this occurs anyway for azure functions or not, or which would be a better approach.

Todo:

  • Peer review
  • Add similar ActionResult classes to the other UI projects
  • Add documentation in the readme for usage within Azure Functions
  • Add tests to ensure that the new sample application works correctly

@Shane32 Shane32 self-assigned this Dec 7, 2022
Shane32 and others added 4 commits December 8, 2022 09:34
Co-authored-by: Ivan Maximov <sungam3r@yandex.ru>
Co-authored-by: Ivan Maximov <sungam3r@yandex.ru>
Co-authored-by: Ivan Maximov <sungam3r@yandex.ru>
Co-authored-by: Ivan Maximov <sungam3r@yandex.ru>
@sungam3r
Copy link
Member

sungam3r commented Dec 8, 2022

Technically the new AzureGraphQLActionResult is not specific to Azure Functions.

I would keep naming as is to accent on Azure applicability.

@sungam3r
Copy link
Member

sungam3r commented Dec 8, 2022

We could eliminate the need to register the middleware in DI, similar to how the UI action results work...

50/50 here, not sure. IAzureGraphQLMiddleware interface looks a bit odd.

@codecov-commenter
Copy link

Codecov Report

Merging #966 (483ba72) into master (833e804) will decrease coverage by 2.39%.
The diff coverage is 17.91%.

@@            Coverage Diff             @@
##           master     #966      +/-   ##
==========================================
- Coverage   95.11%   92.71%   -2.40%     
==========================================
  Files          42       44       +2     
  Lines        2087     2142      +55     
  Branches      359      364       +5     
==========================================
+ Hits         1985     1986       +1     
- Misses         59      113      +54     
  Partials       43       43              
Impacted Files Coverage Δ
...NetCore/AzureFunctions/AzureGraphQLActionResult.cs 0.00% <0.00%> (ø)
...spNetCore/AzureFunctions/AzureGraphQLMiddleware.cs 0.00% <0.00%> (ø)
....AspNetCore/Extensions/GraphQLBuilderExtensions.cs 69.41% <0.00%> (-27.31%) ⬇️
src/Transports.AspNetCore/GraphQLHttpMiddleware.cs 95.17% <92.30%> (+0.01%) ⬆️

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@Shane32
Copy link
Member Author

Shane32 commented Dec 8, 2022

We could eliminate the need to register the middleware in DI, similar to how the UI action results work...

50/50 here, not sure. IAzureGraphQLMiddleware interface looks a bit odd.

I'll do a separate PR after merging this so we can both review the alternative design. I'm 50/50 also.

@Shane32 Shane32 changed the title [WIP] Add Azure Functions support Add Azure Functions support Dec 8, 2022
@Shane32
Copy link
Member Author

Shane32 commented Dec 8, 2022

@sungam3r I added tests, documentation, and etc. Ready to complete review and merge.

@Shane32 Shane32 requested a review from sungam3r December 8, 2022 18:09
Comment on lines +245 to +248
Please note that the GraphQL schema needs to be initialized for every call through
Azure Functions, since it is a serverless environment. This is done automatically
but will come at a performance cost. If you are using a schema that is expensive
to initialize, you may want to consider using a different hosting environment.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspected that the schema should be created every time so your note about overhead here

We could eliminate the need to register the middleware in DI, similar to how the UI action results work, but then there is a bit of startup overhead for each request. Not sure if this occurs anyway for azure functions or not, or which would be a better approach.

will not affect the overall costs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking the same thing. I think we will find that the alternative approach for Azure Functions is better overall.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible that if multiple calls are made in succession maybe then the schema would not need to be reinitialized.

But regardless, I looked at GraphQLHttpMiddleware and it seems that we can make some private readonly fields static anyway. At which point, initializing one class should have little effect on speed/memory.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will have any effect only if Azure Function environment does not unload entirely the whole app (dll/domain/process/whatever) from memory.

@sungam3r sungam3r added enhancement New feature or request new API New non breaking public APIs added labels Dec 8, 2022
@Shane32 Shane32 merged commit 9c0926c into master Dec 9, 2022
@Shane32 Shane32 deleted the azure_functions branch December 9, 2022 01:56
@Shane32 Shane32 added this to the 7.2 milestone Dec 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request new API New non breaking public APIs added
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants