Skip to content

Commit

Permalink
1.35.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dankinsoid committed Jul 28, 2024
1 parent 05ee0db commit 27b3e87
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 27 deletions.
19 changes: 17 additions & 2 deletions Sources/SwiftAPIClient/Modifiers/HTTPResponseValidator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public extension HTTPResponseValidator {
static func statusCode(_ codes: ClosedRange<Int>) -> Self {
HTTPResponseValidator { response, _, configs in
guard codes.contains(response.status.code) || configs.ignoreStatusCodeValidator else {
throw Errors.invalidStatusCode(response.status.code)
throw InvalidStatusCode(response.status)
}
}
}
Expand All @@ -42,12 +42,27 @@ public extension HTTPResponseValidator {
static func statusCode(_ kind: HTTPResponse.Status.Kind) -> Self {
HTTPResponseValidator { response, _, configs in
guard response.status.kind == kind || configs.ignoreStatusCodeValidator else {
throw Errors.invalidStatusCode(response.status.code)
throw InvalidStatusCode(response.status)
}
}
}
}

public struct InvalidStatusCode: Error, LocalizedError, CustomStringConvertible {

/// The invalid status code.
public let status: HTTPResponse.Status

public init(_ status: HTTPResponse.Status) {
self.status = status
}

public var errorDescription: String? { description }
public var description: String {
"Invalid status code: \(status.code) \(status.reasonPhrase)"
}
}

public extension HTTPResponseValidator {

/// A validator that always considers the response as successful.
Expand Down
3 changes: 0 additions & 3 deletions Sources/SwiftAPIClient/Types/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import Foundation
enum Errors: LocalizedError, CustomStringConvertible {

case unknown
case invalidStatusCode(Int)
case notConnected
case mockIsMissed(Any.Type)
case unimplemented
Expand All @@ -21,8 +20,6 @@ enum Errors: LocalizedError, CustomStringConvertible {
switch self {
case .unknown:
return "Unknown error"
case let .invalidStatusCode(code):
return "Invalid status code: \(code)"
case .notConnected:
return "Not connected to the internet"
case let .mockIsMissed(type):
Expand Down
5 changes: 0 additions & 5 deletions Sources/SwiftAPIClient/Utils/Coders/URLQuery/QueryValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,6 @@ enum QueryValue {
}
}

enum Errors: Error {

case noEqualSign(String), unknown, expectedKeyedValue, prohibitedNesting, repeatKeyAt
}

struct Key {

let value: String
Expand Down
61 changes: 44 additions & 17 deletions Sources/SwiftAPIClient/Utils/Coders/URLQuery/URLQueryEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public struct URLQueryEncoder: QueryEncoder {
public func encode<T: Encodable>(_ value: T, percentEncoded: Bool = false) throws -> [URLQueryItem] {
let encoder = _URLQueryEncoder(path: [], context: self)
let query = try encoder.encode(value)
return try getQueryItems(from: query, percentEncoded: percentEncoded)
return try getQueryItems(from: query, value: value, percentEncoded: percentEncoded)
}

public func encodeQuery<T: Encodable>(_ value: T) throws -> String {
Expand All @@ -65,7 +65,7 @@ public struct URLQueryEncoder: QueryEncoder {
return result
}

public enum ArrayEncodingStrategy {
public enum ArrayEncodingStrategy: CustomStringConvertible {

/// value1,value2
case separator(String)
Expand All @@ -79,6 +79,19 @@ public struct URLQueryEncoder: QueryEncoder {
public static var commaSeparator: Self {
.separator(",")
}

public var description: String {
switch self {
case let .separator(separator):
return "separator(\(separator))"
case let .brackets(indexed):
return "brackets(indexed: \(indexed))"
case .repeatKey:
return "repeatKey"
case .custom:
return "custom"
}
}
}

public enum BoolEncodingStrategy {
Expand All @@ -97,11 +110,11 @@ public struct URLQueryEncoder: QueryEncoder {
}
}

private func getQueryItems(from output: QueryValue, percentEncoded: Bool) throws -> [URLQueryItem] {
private func getQueryItems(from output: QueryValue, value: Any, percentEncoded: Bool) throws -> [URLQueryItem] {
let array: QueryValue.Keyed
switch output {
case .single, .unkeyed, .null:
throw QueryValue.Errors.expectedKeyedValue
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Expected a keyed value."))
case let .keyed(dictionary):
array = try encode(dictionary.map { (.string($0.0), $0.1) })
}
Expand All @@ -110,7 +123,7 @@ public struct URLQueryEncoder: QueryEncoder {
switch nestedEncodingStrategy {
case .brackets:
guard var key = $0.0.first?.value else {
throw QueryValue.Errors.unknown
throw EncodingError.invalidValue($0.1, EncodingError.Context(codingPath: [], debugDescription: "No key found."))
}
let chain = $0.0.dropFirst().map(\.value).joined(separator: "][")
if $0.0.count > 1 {
Expand Down Expand Up @@ -168,6 +181,7 @@ public struct URLQueryEncoder: QueryEncoder {
}

private func encode(_ array: [QueryValue], path: [QueryValue.Key]) throws -> QueryValue.Keyed {
let codingKeysPath = path.map { PlainCodingKey($0.value) }
switch arrayEncodingStrategy {
case let .brackets(indexed):
return try encode(
Expand All @@ -176,35 +190,48 @@ public struct URLQueryEncoder: QueryEncoder {
)
case .repeatKey:
guard let key = path.last else {
throw QueryValue.Errors.unknown
throw EncodingError.invalidValue(
array,
EncodingError.Context(codingPath: codingKeysPath, debugDescription: "No key found.")
)
}
return try encode(
array.enumerated().map { (key, $0.element) },
path: path.dropLast()
)
default:
guard let string = try getString(from: .unkeyed(array)) else { return [] }
guard let string = try getString(from: .unkeyed(array), path: codingKeysPath) else { return [] }
return [(path, string)]
}
}

private func getString(from output: QueryValue) throws -> String? {
private func getString(from output: QueryValue, path: [CodingKey]) throws -> String? {
switch output {
case let .single(value):
return value
case .null:
return nil
case let .unkeyed(array):
switch arrayEncodingStrategy {
case let .separator(separator):
return try array.compactMap(getString).joined(separator: separator)
case .brackets, .repeatKey:
throw QueryValue.Errors.prohibitedNesting
case let .custom(block):
return try block([], array.compactMap(getString))
}
switch arrayEncodingStrategy {
case let .separator(separator):
return try array.enumerated().compactMap { try getString(from: $0.element, path: path + [PlainCodingKey(intValue: $0.offset)]) }
.joined(separator: separator)
case .brackets, .repeatKey:
throw EncodingError.invalidValue(
array,
EncodingError.Context(codingPath: path, debugDescription: "Nested arrays are not allowed for .\(arrayEncodingStrategy) array encoding strategy.")
)
case let .custom(block):
return try block(
[],
array.enumerated().compactMap { try getString(from: $0.element, path: path + [PlainCodingKey(intValue: $0.offset)]) }
)
}
case .keyed:
throw QueryValue.Errors.prohibitedNesting
throw EncodingError.invalidValue(
output,
EncodingError.Context(codingPath: path, debugDescription: "Nested keyed objects are not allowed.")
)
}
}
}
Expand Down

0 comments on commit 27b3e87

Please sign in to comment.