mirror of
https://github.com/encounter/JSONAPI.git
synced 2026-03-30 11:18:38 -07:00
Add support for 'const' via OpenAPI 3.0 workaround suggested by others: Use 'enum' with one value. Add Sampleable support for requesting samples representing 'success' and 'failure' if available.
This commit is contained in:
@@ -72,13 +72,14 @@ extension TransformedAttribute: OpenAPINodeType where RawValue: OpenAPINodeType
|
||||
}
|
||||
|
||||
extension RelationshipType {
|
||||
static func relationshipNode(nullable: Bool) -> JSONNode {
|
||||
static func relationshipNode(nullable: Bool, jsonType: String) -> JSONNode {
|
||||
let propertiesDict: [String: JSONNode] = [
|
||||
"id": .string(.init(format: .generic,
|
||||
required: true),
|
||||
.init()),
|
||||
"type": .string(.init(format: .generic,
|
||||
required: true),
|
||||
required: true,
|
||||
allowedValues: [.init(jsonType)]),
|
||||
.init())
|
||||
]
|
||||
|
||||
@@ -97,7 +98,7 @@ extension ToOneRelationship: OpenAPINodeType {
|
||||
return .object(.init(format: .generic,
|
||||
required: true),
|
||||
.init(properties: [
|
||||
"data": ToOneRelationship.relationshipNode(nullable: nullable)
|
||||
"data": ToOneRelationship.relationshipNode(nullable: nullable, jsonType: Identifiable.jsonType)
|
||||
]))
|
||||
}
|
||||
}
|
||||
@@ -111,14 +112,16 @@ extension ToManyRelationship: OpenAPINodeType {
|
||||
.init(properties: [
|
||||
"data": .array(.init(format: .generic,
|
||||
required: true),
|
||||
.init(items: ToManyRelationship.relationshipNode(nullable: false)))
|
||||
.init(items: ToManyRelationship.relationshipNode(nullable: false, jsonType: Relatable.jsonType)))
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
extension Entity: OpenAPINodeType where Description.Attributes: Sampleable, Description.Relationships: Sampleable {
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
// TODO: const for json `type`
|
||||
// NOTE: const for json `type` not supported by OpenAPI 3.0
|
||||
// Will use "enum" with one possible value for now.
|
||||
|
||||
// TODO: metadata, links
|
||||
|
||||
let idNode = JSONNode.string(.init(format: .generic,
|
||||
@@ -127,7 +130,8 @@ extension Entity: OpenAPINodeType where Description.Attributes: Sampleable, Desc
|
||||
let idProperty = ("id", idNode)
|
||||
|
||||
let typeNode = JSONNode.string(.init(format: .generic,
|
||||
required: true),
|
||||
required: true,
|
||||
allowedValues: [.init(Entity.jsonType)]),
|
||||
.init())
|
||||
let typeProperty = ("type", typeNode)
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ extension JSONNode.Context: Encodable {
|
||||
case allowedValues = "enum"
|
||||
case nullable
|
||||
case example
|
||||
// case constantValue = "const"
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@@ -28,6 +29,10 @@ extension JSONNode.Context: Encodable {
|
||||
try container.encode(allowedValues, forKey: .allowedValues)
|
||||
}
|
||||
|
||||
// if constantValue != nil {
|
||||
// try container.encode(constantValue, forKey: .constantValue)
|
||||
// }
|
||||
|
||||
try container.encode(nullable, forKey: .nullable)
|
||||
|
||||
if example != nil {
|
||||
|
||||
@@ -18,7 +18,7 @@ public protocol OpenAPINodeType {
|
||||
|
||||
extension OpenAPINodeType where Self: Sampleable, Self: Encodable {
|
||||
public static func openAPINodeWithExample() throws -> JSONNode {
|
||||
return try openAPINode().with(example: Self.sample)
|
||||
return try openAPINode().with(example: Self.successSample ?? Self.sample)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,6 +255,10 @@ public enum JSONNode: Equatable {
|
||||
public let required: Bool
|
||||
public let nullable: Bool
|
||||
|
||||
// NOTE: "const" is supported by the newest JSON Schema spec but not
|
||||
// yet by OpenAPI. Instead, will use "enum" with one possible value for now.
|
||||
// public let constantValue: Format.SwiftType?
|
||||
|
||||
/// The OpenAPI spec calls this "enum"
|
||||
/// If not specified, it is assumed that any
|
||||
/// value of the given format is allowed.
|
||||
@@ -276,11 +280,13 @@ public enum JSONNode: Equatable {
|
||||
public init(format: Format,
|
||||
required: Bool,
|
||||
nullable: Bool = false,
|
||||
// constantValue: Format.SwiftType? = nil,
|
||||
allowedValues: [AnyCodable]? = nil,
|
||||
example: AnyCodable? = nil) {
|
||||
self.format = format
|
||||
self.required = required
|
||||
self.nullable = nullable
|
||||
// self.constantValue = constantValue
|
||||
self.allowedValues = allowedValues
|
||||
self.example = example
|
||||
.flatMap { try? JSONEncoder().encode($0)}
|
||||
@@ -292,6 +298,7 @@ public enum JSONNode: Equatable {
|
||||
return .init(format: format,
|
||||
required: false,
|
||||
nullable: nullable,
|
||||
// constantValue: constantValue,
|
||||
allowedValues: allowedValues)
|
||||
}
|
||||
|
||||
@@ -300,6 +307,7 @@ public enum JSONNode: Equatable {
|
||||
return .init(format: format,
|
||||
required: true,
|
||||
nullable: nullable,
|
||||
// constantValue: constantValue,
|
||||
allowedValues: allowedValues)
|
||||
}
|
||||
|
||||
@@ -308,6 +316,7 @@ public enum JSONNode: Equatable {
|
||||
return .init(format: format,
|
||||
required: required,
|
||||
nullable: true,
|
||||
// constantValue: constantValue,
|
||||
allowedValues: allowedValues)
|
||||
}
|
||||
|
||||
@@ -316,6 +325,7 @@ public enum JSONNode: Equatable {
|
||||
return .init(format: format,
|
||||
required: required,
|
||||
nullable: nullable,
|
||||
// constantValue: constantValue,
|
||||
allowedValues: allowedValues)
|
||||
}
|
||||
|
||||
@@ -324,6 +334,7 @@ public enum JSONNode: Equatable {
|
||||
return .init(format: format,
|
||||
required: required,
|
||||
nullable: nullable,
|
||||
// constantValue: constantValue,
|
||||
allowedValues: allowedValues,
|
||||
example: example)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,20 @@ public protocol Sampleable {
|
||||
/// same value every time, or it can be an arbitrarily random
|
||||
/// value each time.
|
||||
static var sample: Self { get }
|
||||
|
||||
/// Get an example of success, if that is meaningful and
|
||||
/// available. If not, will be nil.
|
||||
static var successSample: Self? { get }
|
||||
|
||||
/// Get an example of failure, if that is meaningful and
|
||||
/// available. If not, will be nil.
|
||||
static var failureSample: Self? { get }
|
||||
}
|
||||
|
||||
public extension Sampleable {
|
||||
public static var successSample: Self? { return nil }
|
||||
|
||||
public static var failureSample: Self? { return nil }
|
||||
}
|
||||
|
||||
extension Sampleable {
|
||||
|
||||
Reference in New Issue
Block a user