Skip to content

Instantly share code, notes, and snippets.

@kean
Last active December 20, 2021 20:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kean/118ae053c5d610069a8e60d37e2d999b to your computer and use it in GitHub Desktop.
Save kean/118ae053c5d610069a8e60d37e2d999b to your computer and use it in GitHub Desktop.
import UIKit
// Almost pseudocode, but should be possible to write in proper Swift
// MARK: High-Level APIs
// Decodes the document. By default, ignores errors and warnings.
func decode(data: Data, isStrict: Bool = false) -> throws OpenAPI.Document {
let parser = JSONDecoder().decoder(DocumentParser.self, from: data)
// Or maybe be even more granular: "strict", "ignoreWarnings", "ignoreAll"?
if isSrict && (!document.errors.isEmpty || !document.warnings.isEmpty) {
throw DocumentError(document.errors, document.warnigs)
}
// In non-strict, return a document even if there were errors (e.g. failed to
// parse one of the schemas completely) or warnings (e.g. a schemas with
// type "string" has properties from "array")
return parser.document
}
func validate(data: Data) -> ([Errror, Warnings] {
let document = JSONDecoder().decoder(DocumentDecoder.self, from: data)
return (document.errors, document.warnings)
}
// MARK: Parsers
struct DocumentParser: Decodable {
// Schemas that were parsed succesfully
let schemas: [OpenAPI.Schema]
// Errors encountered during schemas parsing
var errors: [Error]
// Warnings encountered during schemas parsing
var warnings: [Warning]
init(from decoder: Decoder) {
// ..
let schemas = try decoder.decode(DecodableResult<SchemaParser>.self, forKey: "schemas")
self.schemas = schemas.compactMap { $0.result.value }
self.errors = schemas.compactMap { $0.result.error }
self.warnings = schemas.compactMap { $0.result.value }.flatMap { $0.warnings }
// perform validations across schemas if needed, e.g. duplicate names
self.warnings = ...
}
}
struct SchemaParser: Decodable {
let schema: OpenAPI.Schema
let warnings: [Warning]
init(from decoder: Decoder) {
// decode and throw if there are critical errors
// entity could probably decode itself
self.schema = ...
// perform validations
self.warnings = [...]
}
}
// A critical errors, e.g. failed to parse one of the schemas completely
struct Error {}
// A warning, e.g. a schemas with type "string" has properties from "array"
struct Warning {}
// Catches errors and saves them a results instead of throwing
struct DecodableResult<T: Decodable>: Decodable {
let result: Result<T, Errors>?
init(from decoder: Decoder) throws {
do {
let container = try decoder.singleValueContainer()
self.value = .success(try container.decode(T.self))
} catch { error as Warnings
self.result =. failure(error)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment