2019-09-29 14:56:04 -07:00
//
2019-10-02 20:02:11 -07:00
// BasicJSONAPIError.swift
2019-09-29 14:56:04 -07:00
// JSONAPI
//
// Created by Mathew Polzin on 9/29/19.
//
/// Most of the JSON:API Spec defined Error fields.
2019-11-05 19:03:51 -08:00
public struct BasicJSONAPIErrorPayload < IdType : Codable & Equatable >: Codable , Equatable , ErrorDictType , CustomStringConvertible {
2019-09-29 14:56:04 -07:00
/// a unique identifier for this particular occurrence of the problem
2019-09-29 16:49:38 -07:00
public let id : IdType ?
2019-11-05 22:37:48 -08:00
// public let links: Links? // we skip this for now to avoid adding complexity to using this basic type.
2019-09-29 14:56:04 -07:00
/// the HTTP status code applicable to this problem
2019-09-29 16:49:38 -07:00
public let status : String ?
2019-09-29 14:56:04 -07:00
/// an application-specific error code
2019-09-29 16:49:38 -07:00
public let code : String ?
2019-09-29 14:56:04 -07:00
/// a short, human-readable summary of the problem that SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization
2019-09-29 16:49:38 -07:00
public let title : String ?
2019-09-29 14:56:04 -07:00
/// a human-readable explanation specific to this occurrence of the problem. Like `title`, this field’ s value can be localized
2019-09-29 16:49:38 -07:00
public let detail : String ?
2019-09-29 14:56:04 -07:00
/// an object containing references to the source of the error
2019-09-29 16:49:38 -07:00
public let source : Source ?
2019-11-05 22:37:48 -08:00
// public let meta: Meta? // we skip this for now to avoid adding complexity to using this basic type
2019-09-29 16:49:38 -07:00
public init ( id : IdType ? = nil ,
status : String ? = nil ,
code : String ? = nil ,
title : String ? = nil ,
detail : String ? = nil ,
source : Source ? = nil ) {
self . id = id
self . status = status
self . code = code
self . title = title
self . detail = detail
self . source = source
}
2019-09-29 14:56:04 -07:00
public struct Source : Codable , Equatable {
/// a JSON Pointer [RFC6901] to the associated entity in the request document [e.g. "/data" for a primary data object, or "/data/attributes/title" for a specific attribute].
2019-09-29 16:49:38 -07:00
public let pointer : String ?
2019-09-29 14:56:04 -07:00
/// which URI query parameter caused the error
2019-09-29 16:49:38 -07:00
public let parameter : String ?
public init ( pointer : String ? = nil ,
parameter : String ? = nil ) {
self . pointer = pointer
self . parameter = parameter
}
2019-09-29 14:56:04 -07:00
}
public var definedFields : [ String : String ] {
let keysAndValues = [
id . map { ( "id" , String ( describing : $0 )) },
status . map { ( "status" , $0 ) },
code . map { ( "code" , $0 ) },
title . map { ( "title" , $0 ) },
detail . map { ( "detail" , $0 ) },
source . flatMap { $0 . pointer . map { ( "pointer" , $0 ) } },
source . flatMap { $0 . parameter . map { ( "parameter" , $0 ) } }
]. compactMap { $0 }
return Dictionary ( uniqueKeysWithValues : keysAndValues )
}
2019-11-05 19:03:51 -08:00
public var description : String {
return definedFields . map { " \( $0 . key ) : \( $0 . value ) " }. sorted (). joined ( separator : ", " )
}
2019-09-29 14:56:04 -07:00
}
/// `BasicJSONAPIError` optionally decodes many possible fields
/// specified by the JSON:API 1.0 Spec. It gives no type-guarantees of what
/// will be non-nil, but could provide good diagnostic information when
/// you do not know what error structure to expect.
///
/// ```
/// Fields:
/// - id
/// - status
/// - code
/// - title
/// - detail
/// - source
/// - pointer
/// - parameter
/// ```
///
/// The JSON:API Spec does not dictate the type of this particular Id field,
/// so you must specify whether to expect, for example, an `Int` or a `String`
/// in the id field.
///
/// Something like `AnyCodable` from *Flight-School* could be
/// a good option if you do not know what to expect. You could also use
/// `Either<Int, String>` (provided by the `Poly` package that is
/// already a dependency of `JSONAPI`).
2019-09-29 15:20:08 -07:00
///
/// - Important: The `definedFields` property will include fields
/// with non-nil values in a flattened way. There will be no `source` key
/// but there will be `pointer` and `parameter` keys (if those values
/// are non-nil).
2019-09-29 14:56:04 -07:00
public typealias BasicJSONAPIError < IdType : Codable & Equatable > = GenericJSONAPIError < BasicJSONAPIErrorPayload < IdType > >