mirror of
https://github.com/encounter/JSONAPI.git
synced 2026-03-30 11:18:38 -07:00
Remove encoder requirement to almost all Open API Node constructors. Made a new protocol for the few places where an encoder did need to be passed in.
This commit is contained in:
@@ -9,8 +9,8 @@ import JSONAPI
|
||||
import Foundation
|
||||
|
||||
extension Includes: OpenAPINodeType where I: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
let includeNode = try I.openAPINode(using: encoder)
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
let includeNode = try I.openAPINode()
|
||||
|
||||
return .array(.init(format: .generic,
|
||||
required: true),
|
||||
@@ -20,113 +20,113 @@ extension Includes: OpenAPINodeType where I: OpenAPINodeType {
|
||||
}
|
||||
|
||||
extension Include0: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
throw OpenAPITypeError.invalidNode
|
||||
}
|
||||
}
|
||||
|
||||
extension Include1: OpenAPINodeType where A: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
return try .one(of: [A.openAPINode(using: encoder)])
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
return try .one(of: [A.openAPINode()])
|
||||
}
|
||||
}
|
||||
|
||||
extension Include2: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
return try .one(of: [
|
||||
A.openAPINode(using: encoder),
|
||||
B.openAPINode(using: encoder)
|
||||
A.openAPINode(),
|
||||
B.openAPINode()
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
extension Include3: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
return try .one(of: [
|
||||
A.openAPINode(using: encoder),
|
||||
B.openAPINode(using: encoder),
|
||||
C.openAPINode(using: encoder)
|
||||
A.openAPINode(),
|
||||
B.openAPINode(),
|
||||
C.openAPINode()
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
extension Include4: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
return try .one(of: [
|
||||
A.openAPINode(using: encoder),
|
||||
B.openAPINode(using: encoder),
|
||||
C.openAPINode(using: encoder),
|
||||
D.openAPINode(using: encoder)
|
||||
A.openAPINode(),
|
||||
B.openAPINode(),
|
||||
C.openAPINode(),
|
||||
D.openAPINode()
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
extension Include5: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType, E: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
return try .one(of: [
|
||||
A.openAPINode(using: encoder),
|
||||
B.openAPINode(using: encoder),
|
||||
C.openAPINode(using: encoder),
|
||||
D.openAPINode(using: encoder),
|
||||
E.openAPINode(using: encoder)
|
||||
A.openAPINode(),
|
||||
B.openAPINode(),
|
||||
C.openAPINode(),
|
||||
D.openAPINode(),
|
||||
E.openAPINode()
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
extension Include6: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType, E: OpenAPINodeType, F: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
return try .one(of: [
|
||||
A.openAPINode(using: encoder),
|
||||
B.openAPINode(using: encoder),
|
||||
C.openAPINode(using: encoder),
|
||||
D.openAPINode(using: encoder),
|
||||
E.openAPINode(using: encoder),
|
||||
F.openAPINode(using: encoder)
|
||||
A.openAPINode(),
|
||||
B.openAPINode(),
|
||||
C.openAPINode(),
|
||||
D.openAPINode(),
|
||||
E.openAPINode(),
|
||||
F.openAPINode()
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
extension Include7: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType, E: OpenAPINodeType, F: OpenAPINodeType, G: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
return try .one(of: [
|
||||
A.openAPINode(using: encoder),
|
||||
B.openAPINode(using: encoder),
|
||||
C.openAPINode(using: encoder),
|
||||
D.openAPINode(using: encoder),
|
||||
E.openAPINode(using: encoder),
|
||||
F.openAPINode(using: encoder),
|
||||
G.openAPINode(using: encoder)
|
||||
A.openAPINode(),
|
||||
B.openAPINode(),
|
||||
C.openAPINode(),
|
||||
D.openAPINode(),
|
||||
E.openAPINode(),
|
||||
F.openAPINode(),
|
||||
G.openAPINode()
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
extension Include8: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType, E: OpenAPINodeType, F: OpenAPINodeType, G: OpenAPINodeType, H: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
return try .one(of: [
|
||||
A.openAPINode(using: encoder),
|
||||
B.openAPINode(using: encoder),
|
||||
C.openAPINode(using: encoder),
|
||||
D.openAPINode(using: encoder),
|
||||
E.openAPINode(using: encoder),
|
||||
F.openAPINode(using: encoder),
|
||||
G.openAPINode(using: encoder),
|
||||
H.openAPINode(using: encoder)
|
||||
A.openAPINode(),
|
||||
B.openAPINode(),
|
||||
C.openAPINode(),
|
||||
D.openAPINode(),
|
||||
E.openAPINode(),
|
||||
F.openAPINode(),
|
||||
G.openAPINode(),
|
||||
H.openAPINode()
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
extension Include9: OpenAPINodeType where A: OpenAPINodeType, B: OpenAPINodeType, C: OpenAPINodeType, D: OpenAPINodeType, E: OpenAPINodeType, F: OpenAPINodeType, G: OpenAPINodeType, H: OpenAPINodeType, I: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
return try .one(of: [
|
||||
A.openAPINode(using: encoder),
|
||||
B.openAPINode(using: encoder),
|
||||
C.openAPINode(using: encoder),
|
||||
D.openAPINode(using: encoder),
|
||||
E.openAPINode(using: encoder),
|
||||
F.openAPINode(using: encoder),
|
||||
G.openAPINode(using: encoder),
|
||||
H.openAPINode(using: encoder),
|
||||
I.openAPINode(using: encoder)
|
||||
A.openAPINode(),
|
||||
B.openAPINode(),
|
||||
C.openAPINode(),
|
||||
D.openAPINode(),
|
||||
E.openAPINode(),
|
||||
F.openAPINode(),
|
||||
G.openAPINode(),
|
||||
H.openAPINode(),
|
||||
I.openAPINode()
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,38 +13,38 @@ private protocol _Optional {}
|
||||
extension Optional: _Optional {}
|
||||
|
||||
extension Attribute: OpenAPINodeType where RawValue: OpenAPINodeType {
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
// If the RawValue is not required, we actually consider it
|
||||
// nullable. To be not required is for the Attribute itself
|
||||
// to be optional.
|
||||
if try !RawValue.openAPINode(using: encoder).required {
|
||||
return try RawValue.openAPINode(using: encoder).requiredNode().nullableNode()
|
||||
if try !RawValue.openAPINode().required {
|
||||
return try RawValue.openAPINode().requiredNode().nullableNode()
|
||||
}
|
||||
return try RawValue.openAPINode(using: encoder)
|
||||
return try RawValue.openAPINode()
|
||||
}
|
||||
}
|
||||
|
||||
extension Attribute: RawOpenAPINodeType where RawValue: RawRepresentable, RawValue.RawValue: OpenAPINodeType {
|
||||
static public func rawOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func rawOpenAPINode() throws -> JSONNode {
|
||||
// If the RawValue is not required, we actually consider it
|
||||
// nullable. To be not required is for the Attribute itself
|
||||
// to be optional.
|
||||
if try !RawValue.RawValue.openAPINode(using: encoder).required {
|
||||
return try RawValue.RawValue.openAPINode(using: encoder).requiredNode().nullableNode()
|
||||
if try !RawValue.RawValue.openAPINode().required {
|
||||
return try RawValue.RawValue.openAPINode().requiredNode().nullableNode()
|
||||
}
|
||||
return try RawValue.RawValue.openAPINode(using: encoder)
|
||||
return try RawValue.RawValue.openAPINode()
|
||||
}
|
||||
}
|
||||
|
||||
extension Attribute: WrappedRawOpenAPIType where RawValue: RawOpenAPINodeType {
|
||||
public static func wrappedOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
public static func wrappedOpenAPINode() throws -> JSONNode {
|
||||
// If the RawValue is not required, we actually consider it
|
||||
// nullable. To be not required is for the Attribute itself
|
||||
// to be optional.
|
||||
if try !RawValue.rawOpenAPINode(using: encoder).required {
|
||||
return try RawValue.rawOpenAPINode(using: encoder).requiredNode().nullableNode()
|
||||
if try !RawValue.rawOpenAPINode().required {
|
||||
return try RawValue.rawOpenAPINode().requiredNode().nullableNode()
|
||||
}
|
||||
return try RawValue.rawOpenAPINode(using: encoder)
|
||||
return try RawValue.rawOpenAPINode()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,14 +61,14 @@ extension Attribute: AnyWrappedJSONCaseIterable where RawValue: AnyJSONCaseItera
|
||||
}
|
||||
|
||||
extension TransformedAttribute: OpenAPINodeType where RawValue: OpenAPINodeType {
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
// If the RawValue is not required, we actually consider it
|
||||
// nullable. To be not required is for the Attribute itself
|
||||
// to be optional.
|
||||
if try !RawValue.openAPINode(using: encoder).required {
|
||||
return try RawValue.openAPINode(using: encoder).requiredNode().nullableNode()
|
||||
if try !RawValue.openAPINode().required {
|
||||
return try RawValue.openAPINode().requiredNode().nullableNode()
|
||||
}
|
||||
return try RawValue.openAPINode(using: encoder)
|
||||
return try RawValue.openAPINode()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ extension ToOneRelationship: OpenAPINodeType {
|
||||
// Will use "enum" with one possible value for now.
|
||||
|
||||
// TODO: metadata & links
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
let nullable = Identifiable.self is _Optional.Type
|
||||
return .object(.init(format: .generic,
|
||||
required: true),
|
||||
@@ -111,7 +111,7 @@ extension ToManyRelationship: OpenAPINodeType {
|
||||
// Will use "enum" with one possible value for now.
|
||||
|
||||
// TODO: metadata & links
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .object(.init(format: .generic,
|
||||
required: true),
|
||||
.init(properties: [
|
||||
@@ -122,7 +122,7 @@ extension ToManyRelationship: OpenAPINodeType {
|
||||
}
|
||||
}
|
||||
|
||||
extension Entity: OpenAPINodeType where Description.Attributes: Sampleable, Description.Relationships: Sampleable {
|
||||
extension Entity: OpenAPIEncodedNodeType, OpenAPINodeType where Description.Attributes: Sampleable, Description.Relationships: Sampleable {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
// NOTE: const for json `type` not supported by OpenAPI 3.0
|
||||
// Will use "enum" with one possible value for now.
|
||||
@@ -165,13 +165,13 @@ extension Entity: OpenAPINodeType where Description.Attributes: Sampleable, Desc
|
||||
}
|
||||
}
|
||||
|
||||
extension SingleResourceBody: OpenAPINodeType where Entity: OpenAPINodeType {
|
||||
extension SingleResourceBody: OpenAPIEncodedNodeType, OpenAPINodeType where Entity: OpenAPIEncodedNodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
return try Entity.openAPINode(using: encoder)
|
||||
}
|
||||
}
|
||||
|
||||
extension ManyResourceBody: OpenAPINodeType where Entity: OpenAPINodeType {
|
||||
extension ManyResourceBody: OpenAPIEncodedNodeType, OpenAPINodeType where Entity: OpenAPIEncodedNodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
return .array(.init(format: .generic,
|
||||
required: true),
|
||||
@@ -179,7 +179,7 @@ extension ManyResourceBody: OpenAPINodeType where Entity: OpenAPINodeType {
|
||||
}
|
||||
}
|
||||
|
||||
extension Document: OpenAPINodeType where PrimaryResourceBody: OpenAPINodeType, IncludeType: OpenAPINodeType {
|
||||
extension Document: OpenAPIEncodedNodeType, OpenAPINodeType where PrimaryResourceBody: OpenAPIEncodedNodeType, IncludeType: OpenAPINodeType {
|
||||
public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
// TODO: metadata, links, api description, errors
|
||||
// TODO: represent data and errors as the two distinct possible outcomes
|
||||
@@ -190,7 +190,7 @@ extension Document: OpenAPINodeType where PrimaryResourceBody: OpenAPINodeType,
|
||||
|
||||
let includeNode: JSONNode?
|
||||
do {
|
||||
includeNode = try Includes<Include>.openAPINode(using: encoder)
|
||||
includeNode = try Includes<Include>.openAPINode()
|
||||
} catch let err as OpenAPITypeError {
|
||||
guard err == .invalidNode else {
|
||||
throw err
|
||||
|
||||
@@ -13,12 +13,25 @@ import Foundation
|
||||
/// Anything conforming to `OpenAPINodeType` can provide an
|
||||
/// OpenAPI schema representing itself.
|
||||
public protocol OpenAPINodeType {
|
||||
static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode
|
||||
static func openAPINode() throws -> JSONNode
|
||||
}
|
||||
|
||||
extension OpenAPINodeType where Self: Sampleable, Self: Encodable {
|
||||
public static func openAPINodeWithExample(using encoder: JSONEncoder = JSONEncoder()) throws -> JSONNode {
|
||||
return try openAPINode(using: encoder).with(example: Self.successSample ?? Self.sample, using: encoder)
|
||||
return try openAPINode().with(example: Self.successSample ?? Self.sample, using: encoder)
|
||||
}
|
||||
}
|
||||
|
||||
/// Anything conforming to `OpenAPIEncodedNodeType` can provide an
|
||||
/// OpenAPI schema representing itself but it may need an Encoder
|
||||
/// to do its job.
|
||||
public protocol OpenAPIEncodedNodeType: OpenAPINodeType {
|
||||
static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode
|
||||
}
|
||||
|
||||
extension OpenAPIEncodedNodeType {
|
||||
public static func openAPINode() throws -> JSONNode {
|
||||
return try openAPINode(using: JSONEncoder())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +42,7 @@ extension OpenAPINodeType where Self: Sampleable, Self: Encodable {
|
||||
/// different schema. The "different" conditions have to do
|
||||
/// with Raw Representability, hence the name of this protocol.
|
||||
public protocol RawOpenAPINodeType {
|
||||
static func rawOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode
|
||||
static func rawOpenAPINode() throws -> JSONNode
|
||||
}
|
||||
|
||||
/// Anything conforming to `RawOpenAPINodeType` can provide an
|
||||
@@ -39,7 +52,7 @@ public protocol RawOpenAPINodeType {
|
||||
/// different schema. The "different" conditions have to do
|
||||
/// with Optionality, hence the name of this protocol.
|
||||
public protocol WrappedRawOpenAPIType {
|
||||
static func wrappedOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode
|
||||
static func wrappedOpenAPINode() throws -> JSONNode
|
||||
}
|
||||
|
||||
/// Anything conforming to `RawOpenAPINodeType` can provide an
|
||||
@@ -52,7 +65,7 @@ public protocol DoubleWrappedRawOpenAPIType {
|
||||
// NOTE: This is definitely a rabbit hole... hopefully I
|
||||
// will realize I've been missing something obvious
|
||||
// and dig my way back out at some point...
|
||||
static func wrappedOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode
|
||||
static func wrappedOpenAPINode() throws -> JSONNode
|
||||
}
|
||||
|
||||
/// Anything conforming to `AnyJSONCaseIterable` can provide a
|
||||
@@ -282,15 +295,14 @@ public enum JSONNode: Equatable {
|
||||
nullable: Bool = false,
|
||||
// constantValue: Format.SwiftType? = nil,
|
||||
allowedValues: [AnyCodable]? = nil,
|
||||
example: AnyCodable? = nil,
|
||||
using encoder: JSONEncoder = JSONEncoder()) {
|
||||
example: (codable: AnyCodable, encoder: JSONEncoder)? = nil) {
|
||||
self.format = format
|
||||
self.required = required
|
||||
self.nullable = nullable
|
||||
// self.constantValue = constantValue
|
||||
self.allowedValues = allowedValues
|
||||
self.example = example
|
||||
.flatMap { try? encoder.encode($0)}
|
||||
.flatMap { try? $0.encoder.encode($0.codable)}
|
||||
.flatMap { String(data: $0, encoding: .utf8) }
|
||||
}
|
||||
|
||||
@@ -331,13 +343,13 @@ public enum JSONNode: Equatable {
|
||||
}
|
||||
|
||||
/// Return this context with the given example
|
||||
public func with(example: AnyCodable) -> Context {
|
||||
public func with(example: AnyCodable, using encoder: JSONEncoder) -> Context {
|
||||
return .init(format: format,
|
||||
required: required,
|
||||
nullable: nullable,
|
||||
// constantValue: constantValue,
|
||||
allowedValues: allowedValues,
|
||||
example: example)
|
||||
example: (codable: example, encoder: encoder))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,17 +574,17 @@ public enum JSONNode: Equatable {
|
||||
|
||||
switch self {
|
||||
case .boolean(let context):
|
||||
return .boolean(context.with(example: example))
|
||||
return .boolean(context.with(example: example, using: encoder))
|
||||
case .object(let contextA, let contextB):
|
||||
return .object(contextA.with(example: example), contextB)
|
||||
return .object(contextA.with(example: example, using: encoder), contextB)
|
||||
case .array(let contextA, let contextB):
|
||||
return .array(contextA.with(example: example), contextB)
|
||||
return .array(contextA.with(example: example, using: encoder), contextB)
|
||||
case .number(let context, let contextB):
|
||||
return .number(context.with(example: example), contextB)
|
||||
return .number(context.with(example: example, using: encoder), contextB)
|
||||
case .integer(let context, let contextB):
|
||||
return .integer(context.with(example: example), contextB)
|
||||
return .integer(context.with(example: example, using: encoder), contextB)
|
||||
case .string(let context, let contextB):
|
||||
return .string(context.with(example: example), contextB)
|
||||
return .string(context.with(example: example, using: encoder), contextB)
|
||||
case .all, .one, .any, .not:
|
||||
return self
|
||||
}
|
||||
|
||||
@@ -33,26 +33,26 @@ Any object:
|
||||
**/
|
||||
|
||||
extension Optional: OpenAPINodeType where Wrapped: OpenAPINodeType {
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
return try Wrapped.openAPINode(using: encoder).optionalNode()
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return try Wrapped.openAPINode().optionalNode()
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: RawOpenAPINodeType where Wrapped: RawRepresentable, Wrapped.RawValue: OpenAPINodeType {
|
||||
static public func rawOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
return try Wrapped.RawValue.openAPINode(using: encoder).optionalNode()
|
||||
static public func rawOpenAPINode() throws -> JSONNode {
|
||||
return try Wrapped.RawValue.openAPINode().optionalNode()
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: WrappedRawOpenAPIType where Wrapped: RawOpenAPINodeType {
|
||||
static public func wrappedOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
return try Wrapped.rawOpenAPINode(using: encoder).optionalNode()
|
||||
static public func wrappedOpenAPINode() throws -> JSONNode {
|
||||
return try Wrapped.rawOpenAPINode().optionalNode()
|
||||
}
|
||||
}
|
||||
|
||||
extension Optional: DoubleWrappedRawOpenAPIType where Wrapped: WrappedRawOpenAPIType {
|
||||
static public func wrappedOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
return try Wrapped.wrappedOpenAPINode(using: encoder).optionalNode()
|
||||
static public func wrappedOpenAPINode() throws -> JSONNode {
|
||||
return try Wrapped.wrappedOpenAPINode().optionalNode()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ extension Optional: AnyJSONCaseIterable where Wrapped: CaseIterable, Wrapped: Co
|
||||
}
|
||||
|
||||
extension String: OpenAPINodeType {
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .string(.init(format: .generic,
|
||||
required: true),
|
||||
.init())
|
||||
@@ -71,22 +71,22 @@ extension String: OpenAPINodeType {
|
||||
}
|
||||
|
||||
extension Bool: OpenAPINodeType {
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .boolean(.init(format: .generic,
|
||||
required: true))
|
||||
}
|
||||
}
|
||||
|
||||
extension Array: OpenAPINodeType where Element: OpenAPINodeType {
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .array(.init(format: .generic,
|
||||
required: true),
|
||||
.init(items: try Element.openAPINode(using: encoder)))
|
||||
.init(items: try Element.openAPINode()))
|
||||
}
|
||||
}
|
||||
|
||||
extension Double: OpenAPINodeType {
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .number(.init(format: .double,
|
||||
required: true),
|
||||
.init())
|
||||
@@ -94,7 +94,7 @@ extension Double: OpenAPINodeType {
|
||||
}
|
||||
|
||||
extension Float: OpenAPINodeType {
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .number(.init(format: .float,
|
||||
required: true),
|
||||
.init())
|
||||
@@ -102,7 +102,7 @@ extension Float: OpenAPINodeType {
|
||||
}
|
||||
|
||||
extension Int: OpenAPINodeType {
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .integer(.init(format: .generic,
|
||||
required: true),
|
||||
.init())
|
||||
@@ -110,7 +110,7 @@ extension Int: OpenAPINodeType {
|
||||
}
|
||||
|
||||
extension Int32: OpenAPINodeType {
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .integer(.init(format: .int32,
|
||||
required: true),
|
||||
.init())
|
||||
@@ -118,7 +118,7 @@ extension Int32: OpenAPINodeType {
|
||||
}
|
||||
|
||||
extension Int64: OpenAPINodeType {
|
||||
static public func openAPINode(using encoder: JSONEncoder) throws -> JSONNode {
|
||||
static public func openAPINode() throws -> JSONNode {
|
||||
return .integer(.init(format: .int64,
|
||||
required: true),
|
||||
.init())
|
||||
|
||||
@@ -69,16 +69,16 @@ extension Sampleable {
|
||||
let maybeOpenAPINode: JSONNode? = try {
|
||||
switch type(of: child.value) {
|
||||
case let valType as OpenAPINodeType.Type:
|
||||
return try valType.openAPINode(using: encoder)
|
||||
return try valType.openAPINode()
|
||||
|
||||
case let valType as RawOpenAPINodeType.Type:
|
||||
return try valType.rawOpenAPINode(using: encoder)
|
||||
return try valType.rawOpenAPINode()
|
||||
|
||||
case let valType as WrappedRawOpenAPIType.Type:
|
||||
return try valType.wrappedOpenAPINode(using: encoder)
|
||||
return try valType.wrappedOpenAPINode()
|
||||
|
||||
case let valType as DoubleWrappedRawOpenAPIType.Type:
|
||||
return try valType.wrappedOpenAPINode(using: encoder)
|
||||
return try valType.wrappedOpenAPINode()
|
||||
|
||||
default:
|
||||
return nil
|
||||
|
||||
@@ -6,15 +6,23 @@
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import SwiftCheck
|
||||
import JSONAPI
|
||||
import JSONAPIOpenAPI
|
||||
|
||||
class JSONAPIDocumentOpenAPITests: XCTestCase {
|
||||
func test_SingleResourceDocument() {
|
||||
let node = try! SingleEntityDocument.openAPINode()
|
||||
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateStyle = .medium
|
||||
dateFormatter.timeStyle = .none
|
||||
dateFormatter.locale = Locale(identifier: "en_US")
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = .prettyPrinted
|
||||
encoder.dateEncodingStrategy = .formatted(dateFormatter)
|
||||
|
||||
let node = try! SingleEntityDocument.openAPINodeWithExample(using: encoder)
|
||||
|
||||
print(String(data: try! encoder.encode(node), encoding: .utf8)!)
|
||||
}
|
||||
@@ -27,9 +35,11 @@ extension JSONAPIDocumentOpenAPITests {
|
||||
|
||||
struct Attributes: JSONAPI.Attributes, Sampleable {
|
||||
let name: Attribute<String>
|
||||
let date: Attribute<Date>
|
||||
|
||||
static var sample: Attributes {
|
||||
return .init(name: "hello world")
|
||||
return .init(name: "hello world",
|
||||
date: .init(value: Date()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,3 +50,29 @@ extension JSONAPIDocumentOpenAPITests {
|
||||
|
||||
typealias SingleEntityDocument = Document<SingleResourceBody<TestEntity>, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>
|
||||
}
|
||||
|
||||
extension Id: Sampleable where RawType == String {
|
||||
public static var sample: Id<RawType, IdentifiableType> {
|
||||
return .init(rawValue: String.arbitrary.generate)
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONAPI.Entity: Sampleable where Description.Attributes: Sampleable, Description.Relationships: Sampleable, MetaType: Sampleable, LinksType: Sampleable, EntityRawIdType == String {
|
||||
public static var sample: JSONAPI.Entity<Description, MetaType, LinksType, EntityRawIdType> {
|
||||
return JSONAPI.Entity(id: .sample,
|
||||
attributes: .sample,
|
||||
relationships: .sample,
|
||||
meta: .sample,
|
||||
links: .sample)
|
||||
}
|
||||
}
|
||||
|
||||
extension Document: Sampleable where PrimaryResourceBody: Sampleable, MetaType: Sampleable, LinksType: Sampleable, IncludeType: Sampleable, APIDescription: Sampleable, Error: Sampleable {
|
||||
public static var sample: Document<PrimaryResourceBody, MetaType, LinksType, IncludeType, APIDescription, Error> {
|
||||
return Document(apiDescription: .sample,
|
||||
body: .sample,
|
||||
includes: .sample,
|
||||
meta: .sample,
|
||||
links: .sample)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user