Code Monkey home page Code Monkey logo

nswag.azurefunctionsv2's Introduction

NSwag Azure Functions v2 Swagger Generator

Wiki Nuget NSwag support NSwag support

Logo

Latest version

Latest published version is v1.1.3. Available from Nuget as NSwag.SwaggerGeneration.AzureFunctionsV2.

Changes in 1.1.3:

  • Added support for non-HttpRequest type HttpTrigger annotated parameters. Also in those cases when the SwaggerRequestBodyType is not explicitly set, the body Type is still automatically detected and entered to the swagger spec, but when SwaggerRequestBodyType is provided then that is used instead.

Changes in 1.1.2:

  • Added support for route prefix in host.json. AzureFunctionsV2ToSwaggerGeneratorSettings has a property called RoutePrefix, which you should set to the same as what you set your extensions.http.routePrefix in your host.json.

Changes in 1.1.1:

  • Added support for non-static Function classes

Supported versions of NSwag

  • NSwag version v12.0.14 has been tested and is supported by this library v1.0.1
  • NSwag version v13.0.4 has been tested and is supported by this library v1.1.*

Please note that v13 of NSwag introduces major naming changes and refactorings. Most names now use OpenApi prefixes instead of Swagger so some refactoring will be needed on the using side as well. This library however has made minimal changes to namings when adapting v13 of NSwag and for the most part hides NSwag behind it so you should get away with minimal changes.

Also note that since v13 the main dependency has changed from NSwag.SwaggerGeneration to NSwag.Generation.

Introduction

See the demo! https://functionsswagger.azurewebsites.net/api/swaggerui/index.html (an Azure Function App serving a Swagger UI and the Swagger JSON that is generated on the fly from the Function App assembly).

The demo source is in two projects: HttpExtensionsTestApp and HttpExtensionsTestApp.Startup.

This is an extension to NSwag, specifically a SwaggerGenerator implementation designed for Azure Functions. This implementation has the necessary discovery methods to scan assemblies for Functions and the library adds new annotations that allows you to generate Swagger documentation from the expected Function parameters and return values.

Additionally the Swagger Generator supports the AzureFunctionsV2.HttpExtensions library without any extra developer effort promoting Azure Functions to a first class Swagger citizen, with Function parameters picked up from function signatures automatically and the additional attribute-based authorization schemes supported and documented automatically. No extra annotations are necessary excluding any additional information you wish to convey via the old and new Swagger annotations.

Features

  • Enables you to generate Swagger Documents out of Azure Function classes
  • Provides the necessary new method level annotations to produce the parameter level documentation when HttpExtensions are not used
  • Supports AzureFunctionsV2.HttpExtensions which allows you to insert request parameters directly into function signature and consequently removes the requirement for having method level parameter annotations

With this you'll be able to have an up-to-date definition with your Functions at all times with minimal hassle. The main motivator for this library was to enable using HttpTriggered Functions more in the manner of a traditional API, and in that mindset having a generated Swagger definition is a must.

It's worth noting that since Functions do not really behave like ASP.NET Core despite them having some similarities, which forces us to do our customized method discovery and fill some gaps with additional annotations.

NSwag Core version compatibility

NSwag.AzureFunctionsV2 is built as a Swagger Generator implementation on top of NSwag.Core and NSwag.Generation packages and it's important to note that these projects aren't necessarily updated in sync. Hence why specific versions of this library support specific versions of NSwag. The development of NSwag is quite fluid and the API changes a lot, and it does not follow strict semantic versioning so it's quite possible that a minor and patch version updates can be breaking. That is why the supported, tested compatible versions are explicitly listed.

The shield on top (Shield) tells you the version of NSwag that the current version of NSwag.AzureFunctionsV2 has been developed and tested with. Most of the time however the latest NSwag 12.0.xx patch versions should be compatible with v1.0.1 though, but it is possible that a public API change in the NSwag projects slips in to a patch version and breaks something. At the time of writing, compatibility update v1.1.0 brings support for NSwag v13, and has been tested against v13.0.4.

Please note that the naming scheme has changed between NSwag v12 and v13, and classes starting with Swagger in v12 are for the most part been renamed to start with OpenApi in v13.

Examples

Basic usage

The basic functionality largely revolves around the new annotations; SwaggerAuthorizeAttribute, SwaggerFormDataAttribute, SwaggerFormDataFileAttribute, SwaggerQueryParameterAttribute , SwaggerRequestBodyTypeAttribute and SwaggerRequestHeaderAttribute which are all applied on the method level. For example:

[SwaggerQueryParameter("queryParam", false /* not a required param */, typeof(string), "A query parameter")]
[SwaggerResponse(200, typeof(string), Description = "OK result")]
[FunctionName("SwaggerQueryParamAttribute1")]
public static async Task<IActionResult> SwaggerQueryParamAttribute1(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
    ILogger log)
{
    return new OkResult();
}

Produces:

"/api/SwaggerQueryParamAttribute1": {
  "get": {
    "tags": [
      "GenerationAnnotationTests"
    ],
    "operationId": "GenerationAnnotationTests_SwaggerQueryParamAttribute1",
    "parameters": [
      {
        "type": "string",
        "name": "queryParam",
        "in": "query",
        "description": "A query parameter",
        "x-nullable": true
      }
    ],
    "responses": {
      "200": {
        "x-nullable": true,
        "description": "OK result",
        "schema": {
          "type": "string"
        }
      }
    }
  }
}

And to actually share the Swagger document with the world, we can create a Function in our Function App that produces and serves it:

[OpenApiIgnore]
[FunctionName("swagger")]
public static async Task<IActionResult> Swagger(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]
    HttpRequest req,
    ILogger log)
{
    var settings = new AzureFunctionsV2ToSwaggerGeneratorSettings();
    settings.Title = "Azure Functions Swagger example";
    var generator = new AzureFunctionsV2ToSwaggerGenerator(settings);    
    var document = await generator.GenerateForAzureFunctionClassAsync(typeof(MyFunctionApp));
    var json = document.ToJson();
    return new OkObjectResult(json);
}

Usage with AzureFunctionsV2.HttpExtensions

Since the HttpExtensions enables us to put request parameters directly into the function signature, things become a lot easier since you no longer need to add any attributes to the method - the parameters are automatically discovered by the Swagger Generator. In a similar example to the above one, here we have list of integers here defined as a query parameter, and nothing extra is required to generate the proper definition as parameters in the signature get picked up automatically.

[SwaggerResponse(200, typeof(string), Description = "OK response")]
[FunctionName("HttpExtensionsQueryParams2")]
public static async Task<IActionResult> HttpExtensionsQueryParams2(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
    [HttpQuery]HttpParam<List<int>> queryParam,
    ILogger log)
{
    return new OkResult();
}

Produces:

"/api/HttpExtensionsQueryParams2": {
  "get": {
    "tags": [
      "HttpExtensionTests"
    ],
    "operationId": "HttpExtensionTests_HttpExtensionsQueryParams2",
    "parameters": [
      {
        "type": "array",
        "name": "queryParam",
        "in": "query",
        "collectionFormat": "multi",
        "x-nullable": true,
        "items": {
          "type": "integer",
          "format": "int32"
        }
      }
    ],
    "responses": {
      "200": {
        "x-nullable": true,
        "description": "OK response",
        "schema": {
          "type": "string"
        }
      }
    }
  }
}

Advanced usage

Authentication/authorization is also supported in both "Swagger annotations only" and "HttpExtensions with Swagger" scenarios. This'll require some additional configuration, namely you'll need to provide the AzureFunctionsV2ToSwaggerGeneratorSettings the security schemes you're using. For example:

settings.DocumentProcessors.Add(
  new SecurityDefinitionAppender("MyBasicAuth", new OpenApiSecurityScheme()
{
    Type = OpenApiSecuritySchemeType.Basic,
    Scheme = "Basic",
    Description = "Basic auth"
}));
settings.OperationProcessors.Add(
  new OperationSecurityProcessor("MyBasicAuth", OpenApiSecuritySchemeType.Basic));

And with this, the following Function annotation will properly be documented and accessible via Swagger UI as well:

[SwaggerAuthorize(AuthScheme.Basic)]
[SwaggerResponse(200, typeof(string), Description = "OK result")]
[FunctionName("SwaggerAuthorizeAttribute1")]
public static async Task<IActionResult> SwaggerAuthorizeAttribute1(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
    ILogger log)
{
    return new OkResult();
}

This produces:

"/api/SwaggerAuthorizeAttribute1": {
  "get": {
    "tags": [
      "GenerationAnnotationTests"
    ],
    "operationId": "GenerationAnnotationTests_SwaggerAuthorizeAttribute1",
    "responses": {
      "200": {
        "x-nullable": true,
        "description": "OK result",
        "schema": {
          "type": "string"
        }
      }
    },
    "security": [
      {
        "MyBasicAuth": []
      }
    ]
  }
},
...
"securityDefinitions": {
  "MyBasicAuth": {
    "type": "basic",
    "description": "Basic auth"
  }
}

So as a summary, you declared a security scheme called "Basic", with the type being OpenApiSecuritySchemeType.Basic (this produces the security definition at the end of the JSON), and the an OperationSecurityProcessor (which gets run for all the Functions) that you tell to bind Basic authentication schemes to a security definition called "Basic", resulting in the above Swagger JSON.

More advanced examples (including OAuth2 and ApiKey configurations) can be found from the wiki.

Known issues

The XML documentation reading is unfortunately not working correctly at the moment. It works locally, provided that you have enabled the XML documentation generation from the project settings and you copy the generated XML doc to your binaries folder. However in Azure the file paths seem to generate some problems for the time being.

nswag.azurefunctionsv2's People

Contributors

jusas avatar

Stargazers

 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

nswag.azurefunctionsv2's Issues

Solve XML documentation in Azure

Hi,

I know there is a known issue about the XML documentation in Azure.

I want to help. Do you know where the xml document is added. I think this is done in the RunOperationProcessorsAsync method. To be more specific, I think it is getting the xml document/path from the context right? So line:

var context = new OperationProcessorContext(document, operationDescription, staticAzureFunctionClassType,
                methodInfo, swaggerGenerator, Settings.SchemaGenerator, schemaResolver, Settings, allOperations);

Which setting is used for the XML file path? I can't find it.

Support for non static functions

Hi there,
First of all, thanks for your great project. I'm a big fan of NSwag and want to use it for my Azure Functions Host. In my project, I'm using DI as described here => https://docs.microsoft.com/de-de/azure/azure-functions/functions-dotnet-dependency-injection. So my functions are not static. The generated document is empty, when I use your example swagger endpoint.

{
  "x-generator": "NSwag v13.0.4.0 (NJsonSchema v10.0.21.0 (Newtonsoft.Json v11.0.0.0))",
  "swagger": "2.0",
  "info": {
    "title": "Swagger",
    "version": "1.0.0"
  },
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ]
}

Do you have some plans to support also non static functions?

Thanks,
Mariusz

Project test names are a bit long

Hello,

Can you rename the test projects please ?
This is quite long if you do not work at the root of your drive : NSwag.AzureFunctionsV2\src\NSwag.SwaggerGeneration.AzureFunctionsV2.Tests.HttpExtensionsApp.Startup\obj\Debug\netstandard2.0\NSwag.SwaggerGeneration.AzureFunctionsV2.Tests.HttpExtensionsApp.Startup.assets.cache

I had the move my repo in order to build, vs failed :
Path: obj\Debug\netstandard2.0\NSwag.SwaggerGeneration.AzureFunctionsV2.Tests.HttpExtensionsApp.Startup.AssemblyInfoInputs.cache exceeds the OS max path limit. The fully qualified file name must be less than 260 characters.

Add link to this project

Great project - well documented and code looks nice, thank you!

Can you ping me if you think it makes sense to put a link to this repo on the NSwag readme file?

You probably won’t be able to always update this library when a new nswag version is released... maybe it would make sense to test whether it’s possible to reference a newer nswag version in the function project - if this picks up the latest version (given no breaking changes) it would make sense to describe this in your wiki...

Unable to set property names to be generated in Camel Case.

I am using Azure Functions v2; I am not using MVC. In my startup, I have the following code that correctly sets the behavior of NewtonSoft Json Serialization, to be ordered, and camel cased (the OrderedContractResolver inherits from CamelCasePropertyNamesContractResolver).

            JsonConvert.DefaultSettings = () =>
            {
                var settings = new JsonSerializerSettings();
                settings.Converters.Add(new StringEnumConverter());
                settings.ContractResolver = new OrderedContractResolver();
#if DEBUG
                settings.Formatting = Formatting.Indented;
#else
                settings.Formatting = Formatting.None;
#endif

                return settings;
            };
        }

I have a Function, to generate the Swagger Json:

        [OpenApiIgnore]
        [FunctionName("Swagger")]
        public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "swagger/json")]
            HttpRequest req, ILogger log)
        {
            var title = Assembly.GetExecutingAssembly().GetName().ToString().Replace(".", " ");
            var settings = new AzureFunctionsV2ToSwaggerGeneratorSettings { Title = title };

            var generator = new AzureFunctionsV2ToSwaggerGenerator(settings);

            var types = AzureFunctionsV2ToSwaggerGenerator.GetAzureFunctionClasses(Assembly.GetExecutingAssembly());
            var document =
                await generator.GenerateForAzureFunctionClassesAsync(types, null).ConfigureAwait(false);
            var json = document.ToJson();
            return new OkObjectResult(json);
        }

I have tried explicitly setting the "obsolete" property of

settings.GeneratorSettings.DefaultPropertyNameHandling = NJsonSchema.PropertyNameHandling.CamelCase;

And also:

            settings.SerializerSettings = new JsonSerializerSettings();
            settings.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

            var generator = new AzureFunctionsV2ToSwaggerGenerator(settings);

However, the generated json is not Camel Cased:

CreateProductRequest: {
type: "object",
properties: {
CompanyId: {
type: "string"
},
Description: {
type: "string"
},
HsCode: {
type: "string"
},
Name: {
type: "string"
},
SKU: {
type: "string"
}
}
},

Any ideas... ?

How do I add a response header

Hi

I have a number of headers that I return in the response such as X-RateLimit-Limit etc.
How do I go about describing these to nswag.
I would like to produce the following output for the response

thanks!

 responses:
        '200':
          x-nullable: true
          description: OK result
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Request limit per hour.
          schema:
            type: array
            items:
              $ref: '#/definitions/MediaResponse'

Azure Function Version 4 Runtime Incompatibility

Hello, I am trying to generate swagger docs for azure function endpoint with no success. I am using the latest runtime version for an Azure function (v4) and .net 6. After some review, it appears that when trying to generate an OpenApiDocument via GenerateForAzureFunctionClassesAsync method, no documents are generated. Looking at the code for the above method, it seems it is trying to filter on FunctionNameAttribute class. However because of a change in v4, this has been renamed to "FunctionAttribute."
Is it possible to update this tool for use with version 4 of Azure functions?

Thanks,
Javad

Function with POST trigger and POST body model does not show up

This function

[FunctionName("PostWebhookAsync")]
[SwaggerResponse(200, typeof(WebhookResponse), Description = "OK result")]
public async Task<IActionResult> PostWebhookAsync(
    [HttpTrigger(AuthorizationLevel.Function, "post", Route = "tenants/{tenantId}/webhooks")] WebhookBodyRequest request,
    [NotNull]string tenantId, ILogger log)
{

does not show up in the spec.

If i change WebhookBodyRequest request to HttpRequest request then it shows up. Am I missing something?

How to generate the Api Description .json file

This project looks pretty awesome, but what I'm really trying to do is generate c# clients. I know I can do that once I have the description.json file. And previously I was getting the file by using nswag with this aspnetcore2openapi when it was an asp.net core project. Now that I'm moving to azure functions I seem to be unable to replicate that functionality. Any help would be appreciated.

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.