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
23 changes: 17 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,7 @@ You can also use a `Session` object. [`Session`](https://pjechris.github.io/Simp

```swift

let session = Session(
baseURL: URL(string: "https://github.com")!,
encoder: JSONEncoder(),
decoder: JSONDecoder()
)
let session = Session(baseURL: URL(string: "https://github.com")!)

try await session.response(for: .login(UserBody(username: "pjechris", password: "MyPassword")))

Expand All @@ -65,9 +61,24 @@ try await session.response(for: .login(UserBody(username: "pjechris", password:
A few words about Session:

- `baseURL` will be prepended to all call paths
- You can skip encoder and decoder if you use JSON
- By default JSON is used for both encoding and decoding, so you don't have to configure anything for JSON APIs
- You can provide a custom `URLSession` instance if ever needed

### Customizing encoders/decoders

Encoders and decoders are configured per content type through a `SessionConfiguration`. Pass a `ContentDataCodersConfiguration` to register the coders you need:

```swift
let session = Session(
baseURL: URL(string: "https://github.com")!,
configuration: SessionConfiguration(
data: ContentDataCodersConfiguration()
.encoding(.json, with: JSONEncoder())
.decoding(.json, with: JSONDecoder())
)
)
```

## Send a body

Request support two body types:
Expand Down
76 changes: 0 additions & 76 deletions Sources/SimpleHTTP/ContentData/ContentDataCoderConfiguration.swift

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Foundation

public typealias ContentDataEncodersConfiguration = [HTTPContentType: ContentDataEncoder]
public typealias ContentDataDecodersConfiguration = [HTTPContentType: ContentDataDecoder]

/// Defines the list of encoders and decoders to use.
public struct ContentDataCodersConfiguration {
public var encoders: ContentDataEncodersConfiguration
public var decoders: ContentDataDecodersConfiguration
public let defaultType: HTTPContentType

public init(
default: HTTPContentType,
encoders: ContentDataEncodersConfiguration,
decoders: ContentDataDecodersConfiguration,
) {
self.encoders = encoders
self.decoders = decoders
self.defaultType = `default`
}

/// Creates a configuration with default coders and decoders.
///
/// - Note: default encoder/decoder is set to JSON
public init() {
self.init(
default: .json,
encoders: [
.json: JSONEncoder(),
.formURLEncoded: FormURLEncoder()
],
decoders: [
.json: JSONDecoder()
]
)
}
}

extension ContentDataCodersConfiguration {
/// defines a single encoder to use for encoding `contentType` requests. If an encoder was already defined it will be replaced with the new value
public func encoding(_ contentType: HTTPContentType, with encoder: ContentDataEncoder) -> Self {
var copy = self
copy.encoders[contentType] = encoder
return copy
}

/// defines a single decoder for decoding `contentType` responses. If a decoder was already defined it will be replaced with the new value
public func decoding(_ contentType: HTTPContentType, with decoder: ContentDataDecoder) -> Self {
var copy = self
copy.decoders[contentType] = decoder
return copy
}
}
6 changes: 3 additions & 3 deletions Sources/SimpleHTTP/Session/Session.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class Session {
public func response<Output: Decodable>(for request: Request<Output>) async throws -> Output {
let result = try await dataPublisher(for: request)

guard let decoder = config.data.decoder[result.contentType] else {
guard let decoder = config.data.decoders[result.contentType] else {
throw SessionConfigurationError.missingDecoder(result.contentType)
}

Expand Down Expand Up @@ -77,10 +77,10 @@ extension Session {
// FIXME: we also check body inside toURLRequest
switch modifiedRequest.body {
case .encodable:
encoder = config.data.encoder[requestContentType]
encoder = config.data.encoders[requestContentType]
case .multipart, .none:
// this one is supposed to never be nil
encoder = config.data.encoder[config.data.defaultType]
encoder = config.data.encoders[config.data.defaultType]
}

guard let encoder else {
Expand Down
10 changes: 5 additions & 5 deletions Sources/SimpleHTTP/Session/SessionConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Foundation
/// a type defining some parameters for a `Session`
public struct SessionConfiguration {
/// data encoders/decoders configuration per content type
let data: ContentDataCoderConfiguration
let data: ContentDataCodersConfiguration
/// queue on which to decode data
let decodingQueue: DispatchQueue
/// an interceptor to apply custom behavior on the session requests/responses.
Expand All @@ -16,7 +16,7 @@ public struct SessionConfiguration {
/// - Parameter decodeQueue: queue on which to decode data
/// - Parameter interceptors: interceptor list to apply on the session requests/responses
public init(
data: ContentDataCoderConfiguration = .init(),
data: ContentDataCodersConfiguration = .init(),
decodingQueue: DispatchQueue = .main,
interceptors: CompositeInterceptor = []) {
self.data = data
Expand All @@ -26,14 +26,14 @@ public struct SessionConfiguration {

/// - Parameter dataError: Error type to use when having error with data
public init<DataError: Error & Decodable>(
data: ContentDataCoderConfiguration,
data: ContentDataCodersConfiguration,
decodingQueue: DispatchQueue = .main,
interceptors: CompositeInterceptor = [],
dataError: DataError.Type
) {
self.init(data: data, decodingQueue: decodingQueue, interceptors: interceptors)
self.errorConverter = { [decoder=data.decoder] data, contentType in
guard let decoder = decoder[contentType] else {
self.errorConverter = { [decoders=data.decoders] data, contentType in
guard let decoder = decoders[contentType] else {
throw SessionConfigurationError.missingDecoder(contentType)
}
return try decoder.decode(dataError, from: data)
Expand Down
6 changes: 3 additions & 3 deletions Tests/SimpleHTTPTests/Session/SessionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import XCTest

class SessionAsyncTests: XCTestCase {
let baseURL = URL(string: "https://sessionTests.io")!
let data = ContentDataCoderConfiguration(
let data = ContentDataCodersConfiguration(
default: .json,
encoder: [.json: JSONEncoder()],
decoder: [.json: JSONDecoder()]
encoders: [.json: JSONEncoder()],
decoders: [.json: JSONDecoder()]
)

func test_response_responseIsValid_decodedOutputIsReturned() async throws {
Expand Down
Loading