I have a project in Visual Studio using the "Azure Functions" template and the "Http trigger with OpenApi" function, and want to use an OpenApiRequestBodyAttribute
to indicate that the function requires a multipart/form-data request, where the "server" parameter is a JSON object, and the "file" parameter is some binary data. Unfortunately, the documentation on the Microsoft.OpenApi library seems pretty sparse, and I haven't been able to find any examples that do exactly what I'm trying to.
So far, this was the best I could come up with:
public class SFTPEndpoints
{
private readonly ILogger<SFTPEndpoints> _logger;
public SFTPEndpoints(ILogger<SFTPEndpoints> log)
{
_logger = log;
}
public record Server(string Url, string Username, string Password, int Port, string Path);
public record ServerWithFileBytes(Server Server, byte[] File);
[FunctionName("sftp-string-upload")]
[OpenApiOperation(operationId: "sftp-string-upload", tags: new[] { "sftp" })]
[OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
[OpenApiRequestBody("multipart/form-data", typeof(ServerWithFileBytes), Description = "Upload a file to the SFTP Server.")]
[OpenApiResponseWithoutBody(HttpStatusCode.OK, Summary = "The file was uploaded successfully.")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req)
{
_logger.LogInformation("C# HTTP trigger function processed a request.");
await Console.Out.WriteLineAsync(req.ToString());
return new OkObjectResult(JsonConvert.SerializeObject(req));
}
}
This gets me close, and renders the following at the localhost/api/swagger/ui
endpoint:
But when I click the "Try it out" button, the text box for the "server" property is blank. I know from writing the doc for this by hand that when it's configured properly, the box should be pre-populated with the schema for the Server
record. The problem is, I don't know how to look at the actual YAML (or JSON?) spec the library is creating from this code, so I'm not sure how to even verify whether the issue is with the UI endpoint, the spec generator, or my annotations. I also tried looking at the OpenApi endpoint, but that always returns an "Invalid OpenApi Version" error no matter what version I specify (in this case localhost/api/openapi/3.0
):
If it makes any difference, I've overridden the DefaultOpenApiConfigurationOptions
class to force OpenApi3, because without that, the request body would show up as completely blank.
internal class OpenApiConfigurationOptions : DefaultOpenApiConfigurationOptions
{
public override OpenApiVersionType OpenApiVersion { get; set; } = OpenApiVersionType.V3;
}
Here's the spec I wrote by hand before I was cursed with trying to do this within the function code itself:
openapi: 3.0.3
info:
version: 1.0.0
title: FTP Server API
description:
API methods for interacting with SFTP and FTPS file servers.
servers:
- url: example.com/api
paths:
/sftp/upload/file:
put:
summary: Upload a file to the SFTP server.
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
ServerData:
$ref: "#/components/schemas/Server"
File:
type: string
format: binary
responses:
200:
description: File uploaded successfully.
components:
schemas:
Server:
type: object
properties:
Url:
type: string
description: Can be a URL or an IP.
example: ftp.example.com
Username:
type: string
Password:
type: string
format: password
Port:
type: integer
Path:
type: string
ServerWithFile:
allOf:
- $ref: "#/components/schemas/Server"
- type: object
properties:
Filename:
type: string
File:
type: string
format: byte
If someone knows either how to fix my annotations or even just look at the spec that the library generates, that would be really helpful. Thanks!