Skip to content

Commit

Permalink
Use operation summary and description in generated function docs (#67)
Browse files Browse the repository at this point in the history
### Motivation

For generated functions for each operations we generate reference
documentation. Currently this only states the HTTP information and the
operation ID, and doesn't include either the `summary` or the
`description`
that may be present in the OpenAPI document.

### Modifications

Change the reference documentation to include both the summary and the
description if they are provided.

### Result

Reference documentation for operation functions contains the
documentation from
the OpenAPI document.

### Test Plan

The OpenAPI document used in the reference test includes operations with
and
without these fields.

### Resolves

- Resolves #64.

---------

Signed-off-by: Si Beaumont <[email protected]>
  • Loading branch information
simonjbeaumont authored Jun 15, 2023
1 parent 907abfa commit cfe0780
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,31 +133,46 @@ extension ResponseKind {

extension Comment {

/// Returns a documentation comment for an OpenAPI operation.
/// Returns a reference documentation string to attach to the generated function for an operation.
init(from operationDescription: OperationDescription) {
self.init(
summary: operationDescription.operation.summary,
description: operationDescription.operation.description,
httpMethod: operationDescription.httpMethod,
path: operationDescription.path,
openAPIDocumentPath: operationDescription.jsonPathComponent
)
}

/// Returns a reference documentation string to attach to the generated function for an operation.
///
/// For example: "Operation `getPet` performs `GET` on `/pets/{petId}`".
/// - Parameters:
/// - operationID: The identifier of the OpenAPI operation.
/// - method: The HTTP method of the OpenAPI operation.
/// - path: The URL path of the OpenAPI operation.
static func operation(
operationID: String?,
method: OpenAPI.HttpMethod,
path: OpenAPI.Path
) -> Self {
let operationName: String
if let operationID {
operationName = "`\(operationID)` "
} else {
operationName = ""
}
/// - summary: A short summary of what the operation does.
/// - description: A verbose explanation of the operation behavior.
/// - path: The path associated with this operation.
/// - httpMethod: The HTTP method associated with this operation.
/// - openAPIDocumentPath: JSONPath to the operation element in the OpenAPI document.
init(
summary: String?,
description: String?,
httpMethod: OpenAPI.HttpMethod,
path: OpenAPI.Path,
openAPIDocumentPath: String
) {
var lines: [String] = []
lines.append("Operation \(operationName)performs `\(method.rawValue.uppercased())` on `\(path.rawValue)`")
if let operationID {
if let summary {
lines.append(summary)
lines.append("")
}
if let description {
lines.append(description)
lines.append("")
lines.append("- Remark: Generated from the `\(operationID)` operation.")
}
return .doc(lines.joined(separator: "\n"))
lines.append(contentsOf: [
"- Remark: HTTP `\(httpMethod.rawValue.uppercased()) \(path.rawValue)`.",
"- Remark: Generated from `\(openAPIDocumentPath)`.",
])
self = .doc(lines.joined(separator: "\n"))
}

/// Returns a documentation comment for the Operations namespace.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,7 @@ extension OperationDescription {
/// Returns a documentation comment for the method implementing
/// the OpenAPI operation.
var comment: Comment {
.operation(
operationID: operation.operationId,
method: httpMethod,
path: path
)
.init(from: self)
}

/// Returns the type name of the namespace unique to the operation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ public struct Client: APIProtocol {
)
}
private var converter: Converter { client.converter }
/// Operation `listPets` performs `GET` on `/pets`
/// List all pets
///
/// - Remark: Generated from the `listPets` operation.
/// You can fetch all the pets here
///
/// - Remark: HTTP `GET /pets`.
/// - Remark: Generated from `#/paths//pets/get(listPets)`.
public func listPets(_ input: Operations.listPets.Input) async throws
-> Operations.listPets.Output
{
Expand Down Expand Up @@ -124,9 +127,10 @@ public struct Client: APIProtocol {
}
)
}
/// Operation `createPet` performs `POST` on `/pets`
/// Create a pet
///
/// - Remark: Generated from the `createPet` operation.
/// - Remark: HTTP `POST /pets`.
/// - Remark: Generated from `#/paths//pets/post(createPet)`.
public func createPet(_ input: Operations.createPet.Input) async throws
-> Operations.createPet.Output
{
Expand Down Expand Up @@ -207,9 +211,8 @@ public struct Client: APIProtocol {
}
)
}
/// Operation `probe` performs `POST` on `/probe`
///
/// - Remark: Generated from the `probe` operation.
/// - Remark: HTTP `POST /probe`.
/// - Remark: Generated from `#/paths//probe/post(probe)`.
public func probe(_ input: Operations.probe.Input) async throws -> Operations.probe.Output {
try await client.send(
input: input,
Expand All @@ -230,9 +233,10 @@ public struct Client: APIProtocol {
}
)
}
/// Operation `updatePet` performs `PATCH` on `/pets/{petId}`
/// Update just a specific property of an existing pet. Nothing is updated if no request body is provided.
///
/// - Remark: Generated from the `updatePet` operation.
/// - Remark: HTTP `PATCH /pets/{petId}`.
/// - Remark: Generated from `#/paths//pets/{petId}/patch(updatePet)`.
public func updatePet(_ input: Operations.updatePet.Input) async throws
-> Operations.updatePet.Output
{
Expand Down Expand Up @@ -289,9 +293,10 @@ public struct Client: APIProtocol {
}
)
}
/// Operation `uploadAvatarForPet` performs `PUT` on `/pets/{petId}/avatar`
/// Upload an avatar
///
/// - Remark: Generated from the `uploadAvatarForPet` operation.
/// - Remark: HTTP `PUT /pets/{petId}/avatar`.
/// - Remark: Generated from `#/paths//pets/{petId}/avatar/put(uploadAvatarForPet)`.
public func uploadAvatarForPet(_ input: Operations.uploadAvatarForPet.Input) async throws
-> Operations.uploadAvatarForPet.Output
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ extension APIProtocol {
}
}
fileprivate extension UniversalServer where APIHandler: APIProtocol {
/// Operation `listPets` performs `GET` on `/pets`
/// List all pets
///
/// - Remark: Generated from the `listPets` operation.
/// You can fetch all the pets here
///
/// - Remark: HTTP `GET /pets`.
/// - Remark: Generated from `#/paths//pets/get(listPets)`.
func listPets(request: Request, metadata: ServerRequestMetadata) async throws -> Response {
try await handle(
request: request,
Expand Down Expand Up @@ -167,9 +170,10 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol {
}
)
}
/// Operation `createPet` performs `POST` on `/pets`
/// Create a pet
///
/// - Remark: Generated from the `createPet` operation.
/// - Remark: HTTP `POST /pets`.
/// - Remark: Generated from `#/paths//pets/post(createPet)`.
func createPet(request: Request, metadata: ServerRequestMetadata) async throws -> Response {
try await handle(
request: request,
Expand Down Expand Up @@ -261,9 +265,8 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol {
}
)
}
/// Operation `probe` performs `POST` on `/probe`
///
/// - Remark: Generated from the `probe` operation.
/// - Remark: HTTP `POST /probe`.
/// - Remark: Generated from `#/paths//probe/post(probe)`.
func probe(request: Request, metadata: ServerRequestMetadata) async throws -> Response {
try await handle(
request: request,
Expand Down Expand Up @@ -295,9 +298,10 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol {
}
)
}
/// Operation `updatePet` performs `PATCH` on `/pets/{petId}`
/// Update just a specific property of an existing pet. Nothing is updated if no request body is provided.
///
/// - Remark: Generated from the `updatePet` operation.
/// - Remark: HTTP `PATCH /pets/{petId}`.
/// - Remark: Generated from `#/paths//pets/{petId}/patch(updatePet)`.
func updatePet(request: Request, metadata: ServerRequestMetadata) async throws -> Response {
try await handle(
request: request,
Expand Down Expand Up @@ -363,9 +367,10 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol {
}
)
}
/// Operation `uploadAvatarForPet` performs `PUT` on `/pets/{petId}/avatar`
/// Upload an avatar
///
/// - Remark: Generated from the `uploadAvatarForPet` operation.
/// - Remark: HTTP `PUT /pets/{petId}/avatar`.
/// - Remark: Generated from `#/paths//pets/{petId}/avatar/put(uploadAvatarForPet)`.
func uploadAvatarForPet(request: Request, metadata: ServerRequestMetadata) async throws
-> Response
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,30 @@ import Foundation
#endif
/// A type that performs HTTP operations defined by the OpenAPI document.
public protocol APIProtocol: Sendable {
/// Operation `listPets` performs `GET` on `/pets`
/// List all pets
///
/// - Remark: Generated from the `listPets` operation.
/// You can fetch all the pets here
///
/// - Remark: HTTP `GET /pets`.
/// - Remark: Generated from `#/paths//pets/get(listPets)`.
func listPets(_ input: Operations.listPets.Input) async throws -> Operations.listPets.Output
/// Operation `createPet` performs `POST` on `/pets`
/// Create a pet
///
/// - Remark: Generated from the `createPet` operation.
/// - Remark: HTTP `POST /pets`.
/// - Remark: Generated from `#/paths//pets/post(createPet)`.
func createPet(_ input: Operations.createPet.Input) async throws -> Operations.createPet.Output
/// Operation `probe` performs `POST` on `/probe`
///
/// - Remark: Generated from the `probe` operation.
/// - Remark: HTTP `POST /probe`.
/// - Remark: Generated from `#/paths//probe/post(probe)`.
func probe(_ input: Operations.probe.Input) async throws -> Operations.probe.Output
/// Operation `updatePet` performs `PATCH` on `/pets/{petId}`
/// Update just a specific property of an existing pet. Nothing is updated if no request body is provided.
///
/// - Remark: Generated from the `updatePet` operation.
/// - Remark: HTTP `PATCH /pets/{petId}`.
/// - Remark: Generated from `#/paths//pets/{petId}/patch(updatePet)`.
func updatePet(_ input: Operations.updatePet.Input) async throws -> Operations.updatePet.Output
/// Operation `uploadAvatarForPet` performs `PUT` on `/pets/{petId}/avatar`
/// Upload an avatar
///
/// - Remark: Generated from the `uploadAvatarForPet` operation.
/// - Remark: HTTP `PUT /pets/{petId}/avatar`.
/// - Remark: Generated from `#/paths//pets/{petId}/avatar/put(uploadAvatarForPet)`.
func uploadAvatarForPet(_ input: Operations.uploadAvatarForPet.Input) async throws
-> Operations.uploadAvatarForPet.Output
}
Expand Down Expand Up @@ -670,9 +675,12 @@ public enum Components {
}
/// API operations, with input and output types, generated from `#/paths` in the OpenAPI document.
public enum Operations {
/// Operation `listPets` performs `GET` on `/pets`
/// List all pets
///
/// - Remark: Generated from the `listPets` operation.
/// You can fetch all the pets here
///
/// - Remark: HTTP `GET /pets`.
/// - Remark: Generated from `#/paths//pets/get(listPets)`.
public enum listPets {
public static let id: String = "listPets"
public struct Input: Sendable, Equatable, Hashable {
Expand Down Expand Up @@ -887,9 +895,10 @@ public enum Operations {
case `default`(statusCode: Int, Operations.listPets.Output.Default)
}
}
/// Operation `createPet` performs `POST` on `/pets`
/// Create a pet
///
/// - Remark: Generated from the `createPet` operation.
/// - Remark: HTTP `POST /pets`.
/// - Remark: Generated from `#/paths//pets/post(createPet)`.
public enum createPet {
public static let id: String = "createPet"
public struct Input: Sendable, Equatable, Hashable {
Expand Down Expand Up @@ -995,9 +1004,8 @@ public enum Operations {
case undocumented(statusCode: Int, OpenAPIRuntime.UndocumentedPayload)
}
}
/// Operation `probe` performs `POST` on `/probe`
///
/// - Remark: Generated from the `probe` operation.
/// - Remark: HTTP `POST /probe`.
/// - Remark: Generated from `#/paths//probe/post(probe)`.
public enum probe {
public static let id: String = "probe"
public struct Input: Sendable, Equatable, Hashable {
Expand Down Expand Up @@ -1081,9 +1089,10 @@ public enum Operations {
case undocumented(statusCode: Int, OpenAPIRuntime.UndocumentedPayload)
}
}
/// Operation `updatePet` performs `PATCH` on `/pets/{petId}`
/// Update just a specific property of an existing pet. Nothing is updated if no request body is provided.
///
/// - Remark: Generated from the `updatePet` operation.
/// - Remark: HTTP `PATCH /pets/{petId}`.
/// - Remark: Generated from `#/paths//pets/{petId}/patch(updatePet)`.
public enum updatePet {
public static let id: String = "updatePet"
public struct Input: Sendable, Equatable, Hashable {
Expand Down Expand Up @@ -1212,9 +1221,10 @@ public enum Operations {
case undocumented(statusCode: Int, OpenAPIRuntime.UndocumentedPayload)
}
}
/// Operation `uploadAvatarForPet` performs `PUT` on `/pets/{petId}/avatar`
/// Upload an avatar
///
/// - Remark: Generated from the `uploadAvatarForPet` operation.
/// - Remark: HTTP `PUT /pets/{petId}/avatar`.
/// - Remark: Generated from `#/paths//pets/{petId}/avatar/put(uploadAvatarForPet)`.
public enum uploadAvatarForPet {
public static let id: String = "uploadAvatarForPet"
public struct Input: Sendable, Equatable, Hashable {
Expand Down

0 comments on commit cfe0780

Please sign in to comment.