Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,15 @@ let package = Package(
.library(name: "Postie", targets: ["Postie"]),
.library(name: "PostieMock", targets: ["PostieMock"])
],
dependencies: [
.package(url: "https://github.com/MaxDesiatov/XMLCoder", .upToNextMajor(from: "0.1.3"))
],
targets: [
.target(name: "Postie", dependencies: ["URLEncodedFormCoding", "PostieUtils"]),
.target(name: "Postie", dependencies: [
"URLEncodedFormCoding",
"PostieUtils",
"XMLCoder"
]),
.testTarget(name: "PostieTests", dependencies: ["Postie", "PostieMock"]),

.target(name: "PostieMock", dependencies: ["Postie"]),
Expand Down
2 changes: 2 additions & 0 deletions Sources/Postie/Decoder/Decodables/XMLDecodable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// A type that can decode itself from an external JSON representation.
public typealias XMLDecodable = Decodable & XMLFormatProvider
23 changes: 15 additions & 8 deletions Sources/Postie/Decoder/ResponseDecoding.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation
import PostieUtils
import URLEncodedFormCoding
import XMLCoder

internal struct ResponseDecoding: Decoder {

Expand All @@ -21,7 +22,7 @@ internal struct ResponseDecoding: Decoder {
}

func unkeyedContainer() throws -> UnkeyedDecodingContainer {
fatalError()
fatalError("not implemented")
}

func singleValueContainer() throws -> SingleValueDecodingContainer {
Expand Down Expand Up @@ -51,7 +52,7 @@ internal struct ResponseDecoding: Decoder {
}

func decodeBody<E: Decodable>(to type: [E].Type) throws -> [E] {
fatalError()
fatalError("not implemented")
}

func decodeBody<T: Decodable>(to type: T.Type) throws -> T {
Expand All @@ -64,6 +65,9 @@ internal struct ResponseDecoding: Decoder {
if type is JSONDecodable.Type {
return try createJSONDecoder().decode(type, from: data)
}
if type is XMLDecodable.Type {
return try createXMLDecoder().decode(type, from: data)
}

if type is CollectionProtocol.Type {
guard let collectionType = type as? CollectionProtocol.Type else {
Expand All @@ -80,19 +84,16 @@ internal struct ResponseDecoding: Decoder {
if elementType is JSONDecodable.Type {
return try createJSONDecoder().decode(type, from: data)
}
if elementType is XMLDecodable.Type {
return try createXMLDecoder().decode(type, from: data)
}
}
fatalError("Unsupported body type: \(type)")
}

private func createJSONDecoder() -> JSONDecoder {
let decoder = LoggingJSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
// switch dateFormat {
// case .iso8601:
// decoder.dateDecodingStrategy = .iso8601
// case .iso8601Full:
// decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full)
// }
return decoder
}

Expand All @@ -114,4 +115,10 @@ internal struct ResponseDecoding: Decoder {
}
return value
}

private func createXMLDecoder() -> XMLDecoder {
let decoder = XMLDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
return decoder
}
}
10 changes: 5 additions & 5 deletions Sources/Postie/Decoder/ResponseKeyedDecodingContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ResponseKeyedDecodingContainer<Key>: KeyedDecodingContainerProtocol where
}

func decodeNil(forKey key: Key) throws -> Bool {
fatalError()
fatalError("not implemented")
}

func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T: Decodable {
Expand All @@ -28,18 +28,18 @@ class ResponseKeyedDecodingContainer<Key>: KeyedDecodingContainerProtocol where
}

func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey: CodingKey {
fatalError()
fatalError("not implemented")
}

func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
fatalError()
fatalError("not implemented")
}

func superDecoder() throws -> Decoder {
fatalError()
fatalError("not implemented")
}

func superDecoder(forKey key: Key) throws -> Decoder {
fatalError()
fatalError("not implemented")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ResponseSingleValueDecodingContainer: SingleValueDecodingContainer {
}

func decodeNil() -> Bool {
fatalError()
fatalError("not implemented")
}

func decode<T>(_ type: T.Type) throws -> T where T: Decodable {
Expand Down
10 changes: 10 additions & 0 deletions Sources/Postie/Encoder/Encodables/XMLEncodable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/// A type that should encode itself to a JSON representation.
public typealias XMLEncodable = Encodable & XMLFormatProvider & XMLBodyProvider

public protocol XMLBodyProvider {

associatedtype Body: Encodable

var body: Body { get }

}
17 changes: 17 additions & 0 deletions Sources/Postie/Encoder/RequestEncoder.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation
import URLEncodedFormCoding
import Combine
import XMLCoder

public class RequestEncoder {

Expand Down Expand Up @@ -65,6 +66,22 @@ public class RequestEncoder {
return data
}

// MARK: - XML

public func encodeXML<Request>(request: Request) throws -> URLRequest where Request: XMLEncodable {
var urlRequest = try encodeToBaseURLRequest(request)
urlRequest.httpBody = try encodeXMLBody(request.body)
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("text/xml", forHTTPHeaderField: "Content-Type")
}
return urlRequest
}

private func encodeXMLBody<Body: Encodable>(_ body: Body) throws -> Data {
let encoder = XMLEncoder()
return try encoder.encode(body)
}

// MARK: - Shared

private func encodeToBaseURLRequest<Request: Encodable>(_ request: Request) throws -> URLRequest {
Expand Down
1 change: 1 addition & 0 deletions Sources/Postie/Formats/APIDataFormat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ public enum APIDataFormat {
case plain
case json
case formURLEncoded
case xml

}
14 changes: 14 additions & 0 deletions Sources/Postie/Formats/XMLFormatProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/// A type that has a default format of xml
public protocol XMLFormatProvider {

/// Format of data, default extension is set to `.xml`
static var format: APIDataFormat { get }

}

extension XMLFormatProvider {

public static var format: APIDataFormat {
.xml
}
}
34 changes: 17 additions & 17 deletions Sources/Postie/Path/RequestPathParameter.swift
Original file line number Diff line number Diff line change
@@ -1,75 +1,75 @@
/// Protocol used for untyped access to the embedded value
internal protocol RequestPathParameterProtocol {

/// Custom name of the path parameter, can be nil
var name: String? { get }

/// Path parameter value which should be serialized and inserted into the path
var untypedValue: RequestPathParameterValue { get }

}

@propertyWrapper
public struct RequestPathParameter<T> where T: RequestPathParameterValue {

public var name: String?
public var wrappedValue: T

public init(wrappedValue: T) {
self.wrappedValue = wrappedValue
}

public init(name: String?, defaultValue: T) {
self.name = name
self.wrappedValue = defaultValue
}

public static func getParameterType() -> Any.Type {
return T.self
}
}

extension RequestPathParameter: RequestPathParameterProtocol {

internal var untypedValue: RequestPathParameterValue {
wrappedValue
}
}

extension RequestPathParameter where T == String {

public init(name: String?) {
self.name = name
self.wrappedValue = ""
}
}

extension RequestPathParameter where T == Int {

public init(name: String?) {
self.name = name
self.wrappedValue = -1
}
}

extension RequestPathParameter where T == Int16 {

public init(name: String?) {
self.name = name
self.wrappedValue = -1
}
}

extension RequestPathParameter where T == Int32 {

public init(name: String?) {
self.name = name
self.wrappedValue = -1
}
}

extension RequestPathParameter where T == Int64 {

public init(name: String?) {
self.name = name
self.wrappedValue = -1
Expand All @@ -79,7 +79,7 @@ extension RequestPathParameter where T == Int64 {
extension RequestPathParameter: Encodable where T: Encodable {}

extension RequestPathParameter: ExpressibleByNilLiteral where T: ExpressibleByNilLiteral {

public init(nilLiteral: ()) {
self.wrappedValue = nil
}
Expand All @@ -88,18 +88,18 @@ extension RequestPathParameter: ExpressibleByNilLiteral where T: ExpressibleByNi
extension RequestPathParameter: ExpressibleByStringLiteral,
ExpressibleByExtendedGraphemeClusterLiteral,
ExpressibleByUnicodeScalarLiteral where T == String {

public typealias ExtendedGraphemeClusterLiteralType = String.ExtendedGraphemeClusterLiteralType
public typealias UnicodeScalarLiteralType = String.UnicodeScalarLiteralType
public typealias StringLiteralType = String.StringLiteralType

public init(stringLiteral value: String) {
wrappedValue = value
}
}

extension RequestPathParameter: ExpressibleByIntegerLiteral where T == IntegerLiteralType {

public init(integerLiteral value: IntegerLiteralType) {
wrappedValue = value
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Postie/Path/RequestPathParameterValue.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
public protocol RequestPathParameterValue {

var serialized: String { get }
}

Expand Down
2 changes: 2 additions & 0 deletions Sources/Postie/Requests/XMLRequest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// Protocol indicating a given request should be encoded into an XML request
public typealias XMLRequest = Request & XMLEncodable
Loading