RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.81k stars 1.3k forks source link

NSwag FromForm nested #2822

Open onetsmr opened 4 years ago

onetsmr commented 4 years ago

Hello, I can't find solution. Please advise how I should implement it.

I have the controller and it has FromForm parameter.

[Route("api/[controller]")]
[ApiController]
[Produces("application/json")]
public class OnboardingController : ControllerBase
{
    [HttpPost]
    [Route("save")]
    [Consumes("multipart/form-data")]
    [SwaggerResponse(HttpStatusCode.OK, typeof(OnboardingModel))]
    public OnboardingModel Save([FromForm] OnboardingForm form)
    {
        return new OnboardingModel
        {
            User = new UserModel
            {
                Login = form.User?.Login,
                Roles = form.User?.Roles?.Select(e => new RoleModel
                {
                    Name = e.Name
                }).ToList()
            }
        };
    }
}

OnboardingForm has nested FromForm and array of another FromForm's

public class OnboardingForm
{
    [Description("User")]
    [FromForm(Name = "user")]
    public UserForm User { get; set; }
}

public class UserForm
{
    [Description("Login of user")]
    [FromForm(Name = "login")]
    public string Login { get; set; }

    [Description("Avatar picture of user")]
    [FromForm(Name = "avatar")]
    public IFormFile AvatarFile { get; set; }

    [Description("Roles of user")]
    [FromForm(Name = "roles")]
    public List<RoleForm> Roles { get; set; }
}

public class RoleForm
{
    [Description("Name of role")]
    [FromForm(Name = "name")]
    public string Name { get; set; }
}

What I see in the swagger UI: https://www.screencast.com/t/kmwZSx3JtwB

And what I have expected:

  1. login parameter should be "user.login" because it is nested
  2. avatar parameter should be "user.avatar" because it is nested
  3. roles parameter should expand details of RoleForm (it contains "name" field)

That is my tests using Postman:

  1. It doesn't work when I send 'login' parameter as described in the swagger doc: https://www.screencast.com/t/iEbDscOh9P0
  2. And it works fine when I send 'user.login' parameter as it should be: https://www.screencast.com/t/TZ1TolmB841w

The Swagger document (auto generated):

{
  "x-generator": "NSwag v13.4.2.0 (NJsonSchema v10.1.11.0 (Newtonsoft.Json v11.0.0.0))",
  "swagger": "2.0",
  "info": {
    "title": "My Title",
    "version": "1.0.0"
  },
  "host": "localhost:5000",
  "schemes": [
    "http"
  ],
  "consumes": [
    "multipart/form-data"
  ],
  "produces": [
    "application/json"
  ],
  "paths": {
    "/api/Onboarding/save": {
      "post": {
        "tags": [
          "Onboarding"
        ],
        "operationId": "Onboarding_Save",
        "parameters": [
          {
            "type": "string",
            "name": "login",
            "in": "formData",
            "description": "Login of user",
            "x-nullable": true
          },
          {
            "type": "file",
            "name": "avatar",
            "in": "formData",
            "description": "Avatar picture of user",
            "x-nullable": true
          },
          {
            "type": "array",
            "name": "roles",
            "in": "formData",
            "description": "Roles of user",
            "collectionFormat": "multi",
            "x-nullable": true,
            "items": {
              "$ref": "#/definitions/RoleForm"
            }
          }
        ],
        "responses": {
          "200": {
            "x-nullable": false,
            "description": "",
            "schema": {
              "$ref": "#/definitions/OnboardingModel"
            }
          }
        }
      }
    }
  },
  "definitions": {
    "OnboardingModel": {
      "type": "object",
      "properties": {
        "user": {
          "$ref": "#/definitions/UserModel"
        }
      }
    },
    "UserModel": {
      "type": "object",
      "properties": {
        "login": {
          "type": "string"
        },
        "roles": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/RoleModel"
          }
        }
      }
    },
    "RoleModel": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        }
      }
    },
    "RoleForm": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Name of role"
        }
      }
    }
  }
}
fantom3527 commented 3 weeks ago

Hello, did you manage to solve the issue?

onetsmr commented 3 weeks ago

@fantom3527 No