OpenAPI.NET.OData/tool/Microsoft.OpenApi/Models/OpenApiOperation.cs

286 lines
12 KiB
C#

// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
{
/// <summary>
/// Operation Object.
/// </summary>
public class OpenApiOperation : OpenApiElement, IOpenApiExtension
{
/// <summary>
/// Default value for <see cref="Deprecated"/>.
/// </summary>
public const bool DeprecatedDefault = false;
/// <summary>
/// A list of tags for API documentation control.
/// Tags can be used for logical grouping of operations by resources or any other qualifier.
/// </summary>
public IList<OpenApiTag> Tags { get; set; } = new List<OpenApiTag>();
/// <summary>
/// A short summary of what the operation does.
/// </summary>
public string Summary { get; set; }
/// <summary>
/// A verbose explanation of the operation behavior.
/// CommonMark syntax MAY be used for rich text representation.
/// </summary>
public string Description { get; set; }
/// <summary>
/// Additional external documentation for this operation.
/// </summary>
public OpenApiExternalDocs ExternalDocs { get; set; }
/// <summary>
/// Unique string used to identify the operation. The id MUST be unique among all operations described in the API.
/// Tools and libraries MAY use the operationId to uniquely identify an operation, therefore,
/// it is RECOMMENDED to follow common programming naming conventions.
/// </summary>
public string OperationId { get; set; }
/// <summary>
/// A list of parameters that are applicable for this operation.
/// If a parameter is already defined at the Path Item, the new definition will override it but can never remove it.
/// The list MUST NOT include duplicated parameters. A unique parameter is defined by a combination of a name and location.
/// The list can use the Reference Object to link to parameters that are defined at the OpenAPI Object's components/parameters.
/// </summary>
public IList<OpenApiParameter> Parameters { get; set; } = new List<OpenApiParameter>();
/// <summary>
/// The request body applicable for this operation.
/// The requestBody is only supported in HTTP methods where the HTTP 1.1 specification RFC7231
/// has explicitly defined semantics for request bodies.
/// In other cases where the HTTP spec is vague, requestBody SHALL be ignored by consumers.
/// </summary>
public OpenApiRequestBody RequestBody { get; set; }
/// <summary>
/// REQUIRED. The list of possible responses as they are returned from executing this operation.
/// </summary>
public OpenApiResponses Responses { get; set; }
/// <summary>
/// A map of possible out-of band callbacks related to the parent operation.
/// The key is a unique identifier for the Callback Object.
/// Each value in the map is a Callback Object that describes a request
/// that may be initiated by the API provider and the expected responses.
/// The key value used to identify the callback object is an expression, evaluated at runtime,
/// that identifies a URL to use for the callback operation.
/// </summary>
public IDictionary<string, OpenApiCallback> Callbacks { get; set; } = new Dictionary<string, OpenApiCallback>();
/// <summary>
/// Declares this operation to be deprecated. Consumers SHOULD refrain from usage of the declared operation.
/// </summary>
public bool Deprecated { get; set; } = DeprecatedDefault;
/// <summary>
/// A declaration of which security mechanisms can be used for this operation.
/// The list of values includes alternative security requirement objects that can be used.
/// Only one of the security requirement objects need to be satisfied to authorize a request.
/// This definition overrides any declared top-level security.
/// To remove a top-level security declaration, an empty array can be used.
/// </summary>
public IList<OpenApiSecurityRequirement> Security { get; set; } = new List<OpenApiSecurityRequirement>();
/// <summary>
/// An alternative server array to service this operation.
/// If an alternative server object is specified at the Path Item Object or Root level,
/// it will be overridden by this value.
/// </summary>
public IList<OpenApiServer> Servers { get; set; } = new List<OpenApiServer>();
/// <summary>
/// This object MAY be extended with Specification Extensions.
/// </summary>
public IDictionary<string, IOpenApiAny> Extensions { get; set; }
/// <summary>
/// Creates a <see cref="OpenApiResponse"/> object and add it to <see cref="Responses"/>.
/// </summary>
public void CreateResponse(string key, Action<OpenApiResponse> configure)
{
var response = new OpenApiResponse();
configure(response);
Responses.Add(key, response);
}
/// <summary>
/// Serialize <see cref="OpenApiOperation"/> to Open Api v3.0.
/// </summary>
internal override void WriteAsV3(IOpenApiWriter writer)
{
if (writer == null)
{
throw Error.ArgumentNull(nameof(writer));
}
writer.WriteStartObject();
// tags
writer.WriteOptionalCollection(OpenApiConstants.Tags, Tags, (w, t) => t.WriteAsV3(w));
// summary
writer.WriteProperty(OpenApiConstants.Summary, Summary);
// description
writer.WriteProperty(OpenApiConstants.Description, Description);
// externalDocs
writer.WriteOptionalObject(OpenApiConstants.ExternalDocs, ExternalDocs, (w, e) => e.WriteAsV3(w));
// operationId
writer.WriteProperty(OpenApiConstants.OperationId, OperationId);
// parameters
writer.WriteOptionalCollection(OpenApiConstants.Parameters, Parameters, (w, p) => p.WriteAsV3(w));
// requestBody
writer.WriteOptionalObject(OpenApiConstants.RequestBody, RequestBody, (w, r) => r.WriteAsV3(w));
// responses
writer.WriteOptionalObject(OpenApiConstants.Responses, Responses, (w, r) => r.WriteAsV3(w));
// callbacks
writer.WriteOptionalMap(OpenApiConstants.Callbacks, Callbacks, (w, c) => c.WriteAsV3(w));
// deprecated
writer.WriteProperty(OpenApiConstants.Deprecated, Deprecated, false);
// security
writer.WriteOptionalCollection(OpenApiConstants.Security, Security, (w, s) => s.WriteAsV3(w));
// servers
writer.WriteOptionalCollection(OpenApiConstants.Servers, Servers, (w, s) => s.WriteAsV3(w));
// specification extensions
writer.WriteExtensions(Extensions);
writer.WriteEndObject();
}
/// <summary>
/// Serialize <see cref="OpenApiOperation"/> to Open Api v2.0.
/// </summary>
internal override void WriteAsV2(IOpenApiWriter writer)
{
if (writer == null)
{
throw Error.ArgumentNull(nameof(writer));
}
writer.WriteStartObject();
// tags
writer.WriteOptionalCollection(OpenApiConstants.Tags, Tags, (w, t) => t.WriteAsV2(w));
// summary
writer.WriteProperty(OpenApiConstants.Summary, Summary);
// description
writer.WriteProperty(OpenApiConstants.Description, Description);
// externalDocs
writer.WriteOptionalObject(OpenApiConstants.ExternalDocs, ExternalDocs, (w, e) => e.WriteAsV2(w));
// operationId
writer.WriteProperty(OpenApiConstants.OperationId, OperationId);
var parameters = new List<OpenApiParameter>(Parameters);
if (RequestBody != null)
{
// consumes
writer.WritePropertyName(OpenApiConstants.Consumes);
writer.WriteStartArray();
var consumes = RequestBody.Content.Keys.Distinct().ToList();
foreach (var mediaType in consumes)
{
writer.WriteValue(mediaType);
}
writer.WriteEndArray();
// Create a parameter as BodyParameter type and add to Parameters.
// This type will be used to populate the In property as "body" when Parameters is serialized.
var bodyParameter = new BodyParameter
{
Description = RequestBody.Description,
Schema = RequestBody.Content.First().Value.Schema,
Format = new List<string>(consumes)
};
parameters.Add(bodyParameter);
}
if (Responses != null)
{
var produces = Responses.Where(r => r.Value.Content != null)
.SelectMany(r => r.Value.Content?.Keys)
.Distinct()
.ToList();
if (produces.Any())
{
// produces
writer.WritePropertyName(OpenApiConstants.Produces);
writer.WriteStartArray();
foreach (var mediaType in produces)
{
writer.WriteValue(mediaType);
}
writer.WriteEndArray();
}
}
// parameters
// Use the parameters created locally to include request body if exists.
writer.WriteOptionalCollection(OpenApiConstants.Parameters, parameters, (w, p) => p.WriteAsV2(w));
// responses
writer.WriteOptionalMap(OpenApiConstants.Responses, Responses, (w, r) => r.WriteAsV2(w));
// schemes
// All schemes in the Servers are extracted, regardless of whether the host matches
// the host defined in the outermost Swagger object. This is due to the
// inaccessibility of information for that host in the context of an inner object like this Operation.
var schemes = Servers.Select(
s =>
{
Uri.TryCreate(s.Url, UriKind.RelativeOrAbsolute, out var url);
return url?.Scheme;
})
.Where(s => s != null)
.Distinct()
.ToList();
writer.WriteOptionalCollection(OpenApiConstants.Schemes, schemes, (w, s) => w.WriteValue(s));
// deprecated
writer.WriteProperty(OpenApiConstants.Deprecated, Deprecated, false);
// security
writer.WriteOptionalCollection(OpenApiConstants.Security, Security, (w, s) => s.WriteAsV2(w));
// specification extensions
writer.WriteExtensions(Extensions);
writer.WriteEndObject();
}
}
}