Skip to content

Commit 544e732

Browse files
Merge pull request #83 from futuredapp/housekeep/inline-documentation-1-2-3-rev2
Inline documentation
2 parents db527a2 + 3db581b commit 544e732

15 files changed

Lines changed: 247 additions & 28 deletions

.github/workflows/macos-latest.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
name: Test – macOS
22

33
on:
4-
- pull_request
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- '*'
510

611
jobs:
712
test:

.github/workflows/ubuntu-latest.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
name: Test – Ubuntu
22

33
on:
4-
- pull_request
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- '*'
510

611
jobs:
712
ubuntu-swift-latest:

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
![Cocoapods platforms](https://img.shields.io/cocoapods/p/FTAPIKit)
77
![License](https://img.shields.io/cocoapods/l/FTAPIKit)
88

9+
![macOS](https://github.com/futuredapp/FTAPIKit/actions/workflows/macos-latest.yml/badge.svg?branch=main)
10+
![Ubuntu](https://github.com/futuredapp/FTAPIKit/actions/workflows/ubuntu-latest.yml/badge.svg?branch=main)
11+
912
Declarative and generic REST API framework using Codable.
1013
With standard implementation using URLSesssion and JSON encoder/decoder.
1114
Easily extensible for your asynchronous framework or networking stack.

Sources/FTAPIKit/APIError.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,28 @@ import Foundation
44
import FoundationNetworking
55
#endif
66

7+
/// Error protocol used in types conforming to `URLServer` protocol. Default implementation called `APIErrorStandard`
8+
/// is provided. A type conforming to `APIError` protocol can be provided to `URLServer`
9+
/// to use custom error handling.
10+
///
11+
/// - Note: Since this type is specific to the standard implementation, it works with Foundation `URLSession`
12+
/// network API.
713
public protocol APIError: Error {
14+
/// Standard implementation of `APIError`
815
typealias Standard = APIErrorStandard
916

17+
/// Creates instance if arguments do not represent a valid server response.
18+
///
19+
/// - Parameters:
20+
/// - data: The data returned from the server
21+
/// - response: The URL response returned from the server
22+
/// - error: Error returned by `URLSession` task execution
23+
/// - decoding: The decoder associated with this server, in case the `data` parameter is encoded
24+
///
25+
/// - Warning: Initializer can't return an instance if arguments contain a valid server response. The
26+
/// response would be discarded if it does, and the API call would be treated as a failure.
1027
init?(data: Data?, response: URLResponse?, error: Error?, decoding: Decoding)
1128

29+
/// If the initializer fails but the server response is not valid, this property is used as a fallback.
1230
static var unhandled: Self { get }
1331
}

Sources/FTAPIKit/Coding.swift

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,37 @@ import Foundation
44
import FoundationNetworking
55
#endif
66

7+
/// `Encoding` represents Swift encoders and provides network-specific features, such as configuring
8+
/// the request with correct headers.
9+
///
10+
/// - Note: A standard implementation is provided in the form of `JSONEncoding`
711
public protocol Encoding {
12+
13+
/// Encodes the argument
814
func encode<T: Encodable>(_ object: T) throws -> Data
15+
16+
/// Configures the request with proper headers etc., such as `Content-Type`.
917
func configure(request: inout URLRequest) throws
1018
}
1119

20+
/// Protocol which enables use of any decoder using type-erasure.
1221
public protocol Decoding {
1322
func decode<T: Decodable>(data: Data) throws -> T
1423
}
1524

25+
/// Type-erased JSON encoder for use with types conforming to `Server` protocol.
1626
public struct JSONEncoding: Encoding {
1727
private let encoder: JSONEncoder
1828

1929
public init(encoder: JSONEncoder = .init()) {
2030
self.encoder = encoder
2131
}
2232

23-
public init(configure: (JSONEncoder) -> Void) {
33+
/// Creates new encoder with ability to configure `JSONEncoder` in a compact manner
34+
/// using a closure.
35+
///
36+
/// - Parameter configure: Function with custom configuration of the encoder
37+
public init(configure: (_ encoder: JSONEncoder) -> Void) {
2438
let encoder = JSONEncoder()
2539
configure(encoder)
2640
self.encoder = encoder
@@ -35,14 +49,19 @@ public struct JSONEncoding: Encoding {
3549
}
3650
}
3751

52+
/// Type-erased JSON decoder for use with types conforming to `Server` protocol.
3853
public struct JSONDecoding: Decoding {
3954
private let decoder: JSONDecoder
4055

4156
public init(decoder: JSONDecoder = .init()) {
4257
self.decoder = decoder
4358
}
4459

45-
public init(configure: (JSONDecoder) -> Void) {
60+
/// Creates new decoder with ability to configure `JSONDecoder` in a compact manner
61+
/// using a closure.
62+
///
63+
/// - Parameter configure: Function with custom configuration of the decoder
64+
public init(configure: (_ decoder: JSONDecoder) -> Void) {
4665
let decoder = JSONDecoder()
4766
configure(decoder)
4867
self.decoder = decoder

Sources/FTAPIKit/Combine/URLServer+Combine.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,40 @@ import Combine
44

55
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
66
public extension URLServer {
7+
8+
/// Performs call to endpoint which does not return any data in the HTTP response.
9+
/// - Note: Canceling this chain will result in the abortion of the URLSessionTask.
10+
/// - Note: This call maps `func call(endpoint: Endpoint, completion: @escaping (Result<Void, ErrorType>) -> Void) -> URLSessionTask?` to the Combine API
11+
/// - Parameters:
12+
/// - endpoint: The endpoint
13+
/// - Returns: On success void, otherwise error.
714
func publisher(endpoint: Endpoint) -> AnyPublisher<Void, ErrorType> {
815
Publishers.Endpoint { completion in
916
self.call(endpoint: endpoint, completion: completion)
1017
}
1118
.eraseToAnyPublisher()
1219
}
1320

21+
/// Performs call to endpoint which returns an arbitrary data in the HTTP response, that won't be parsed by the decoder of the
22+
/// server.
23+
/// - Note: Canceling this chain will result in the abortion of the URLSessionTask.
24+
/// - Note: This call maps `func call(data endpoint: Endpoint, completion: @escaping (Result<Data, ErrorType>) -> Void) -> URLSessionTask?` to the Combine API
25+
/// - Parameters:
26+
/// - endpoint: The endpoint
27+
/// - Returns: On success plain data, otherwise error.
1428
func publisher(data endpoint: Endpoint) -> AnyPublisher<Data, ErrorType> {
1529
Publishers.Endpoint { completion in
1630
self.call(data: endpoint, completion: completion)
1731
}
1832
.eraseToAnyPublisher()
1933
}
2034

35+
/// Performs call to endpoint which returns data which will be parsed by the server decoder.
36+
/// - Note: Canceling this chain will result in the abortion of the URLSessionTask.
37+
/// - Note: This call maps `func call<EP: ResponseEndpoint>(response endpoint: EP, completion: @escaping (Result<EP.Response, ErrorType>) -> Void) -> URLSessionTask?` to the Combine API
38+
/// - Parameters:
39+
/// - endpoint: The endpoint
40+
/// - Returns: On success instance of the required type, otherwise error.
2141
func publisher<EP: ResponseEndpoint>(response endpoint: EP) -> AnyPublisher<EP.Response, ErrorType> {
2242
Publishers.Endpoint { completion in
2343
self.call(response: endpoint, completion: completion)

Sources/FTAPIKit/Endpoint.swift

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,16 @@ public protocol Endpoint {
1515
/// URL path component without base URI.
1616
var path: String { get }
1717

18+
/// HTTP headers.
19+
/// - Note: Provided default implementation.
1820
var headers: [String: String] { get }
1921

22+
/// Query of the request, expressible as a dictionary literal with non-unique keys.
23+
/// - Note: Provided default implementation.
2024
var query: URLQuery { get }
2125

2226
/// HTTP method/verb describing the action.
27+
/// - Note: Provided default implementation.
2328
var method: HTTPMethod { get }
2429
}
2530

@@ -29,25 +34,49 @@ public extension Endpoint {
2934
var method: HTTPMethod { .get }
3035
}
3136

37+
/// `DataEndpoint` transmits data provided in the `body` property without any further encoding.
3238
public protocol DataEndpoint: Endpoint {
3339
var body: Data { get }
3440
}
3541

3642
#if !os(Linux)
43+
/// `UploadEndpoint` will send the provided file to the API.
44+
///
45+
/// - Note: If the standard implementation is used, `URLSession.uploadTask( ... )` will be used.
3746
public protocol UploadEndpoint: Endpoint {
47+
48+
/// File which shell be sent.
3849
var file: URL { get }
3950
}
4051

52+
/// Endpoint which will be sent as a multipart HTTP request.
53+
///
54+
/// - Note: If the standard implementation is used, the body parts will be merged into a temporary file, which will
55+
/// then be transformed to an input stream and passed to the request as a httpBodyStream.
4156
public protocol MultipartEndpoint: Endpoint {
57+
58+
/// List of individual body parts.
4259
var parts: [MultipartBodyPart] { get }
4360
}
4461
#endif
4562

63+
/// The body of the endpoint with the URL query format.
4664
public protocol URLEncodedEndpoint: Endpoint {
4765
var body: URLQuery { get }
4866
}
4967

50-
/// Endpoint protocol extending `Endpoint` having decodable associated type, which is used
68+
/// An abstract representation of endpoint, body of which is represented by Swift encodable type. It serves as an
69+
/// abstraction between the `Server` protocol and more specific `Endpoint` conforming protocols.
70+
/// Do not use this protocol to represent an encodable endpoint, use `RequestEndpoint` instead.
71+
public protocol EncodableEndpoint: Endpoint {
72+
73+
/// Returns `data` which will be sent as the body of the endpoint. Note that only the encoder is passed to
74+
/// the function. The origin of the encodable data is not specified by this protocol.
75+
/// - Parameter encoding: Server provided encoder, which will also configure headers.
76+
func body(encoding: Encoding) throws -> Data
77+
}
78+
79+
/// Protocol extending `Endpoint` with decodable associated type, which is used
5180
/// for automatic deserialization.
5281
public protocol ResponseEndpoint: Endpoint {
5382
/// Associated type describing the return type conforming to `Decodable`
@@ -56,30 +85,26 @@ public protocol ResponseEndpoint: Endpoint {
5685
associatedtype Response: Decodable
5786
}
5887

59-
/// Endpoint protocol extending `Endpoint` encapsulating and improving sending JSON models to API.
88+
/// Protocol extending `Endpoint`, which supports sending `Encodable` data to the server.
89+
///
90+
/// - Note: Provides default implementation for `func body(encoding: Encoding) throws -> Data`
91+
/// and `var method: HTTPMethod`.
6092
public protocol RequestEndpoint: EncodableEndpoint {
61-
/// Associated type describing the encodable request model for
62-
/// JSON serialization. The associated type is derived from
63-
/// the body property.
93+
/// Associated type describing the encodable request model for serialization. The associated type is derived
94+
/// from the body property.
6495
associatedtype Request: Encodable
65-
/// Generic encodable model, which will be sent as JSON body.
96+
/// Generic encodable model, which will be sent in the body of the request.
6697
var request: Request { get }
6798
}
6899

69100
public extension RequestEndpoint {
101+
var method: HTTPMethod { .post }
102+
70103
func body(encoding: Encoding) throws -> Data {
71104
try encoding.encode(request)
72105
}
73106
}
74107

75-
public protocol EncodableEndpoint: Endpoint {
76-
func body(encoding: Encoding) throws -> Data
77-
}
78-
79-
public extension RequestEndpoint {
80-
var method: HTTPMethod { .post }
81-
}
82-
83-
/// Typealias combining request and response API endpoint. For describing JSON
84-
/// request which both sends and expects JSON model from the server.
108+
/// Typealias combining request and response API endpoint. For describing codable
109+
/// request which both sends and expects serialized model from the server.
85110
public typealias RequestResponseEndpoint = RequestEndpoint & ResponseEndpoint

Sources/FTAPIKit/HTTPMethod.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
//
2-
// APIAdapter+Types.swift
3-
// FTAPIKit
4-
//
5-
// Created by Matěj Kašpar Jirásek on 08/02/2018.
6-
// Copyright © 2018 FUNTASTY Digital s.r.o. All rights reserved.
7-
//
8-
91
/// HTTP method enum with all commonly used verbs.
102
public enum HTTPMethod: String, CustomStringConvertible {
113
/// `OPTIONS` HTTP method

Sources/FTAPIKit/Server.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,30 @@
1+
/// `Server` is an abstraction rather than a protocol-bound requirement.
2+
///
3+
/// The expectation of a `Server` conforming type is, that it provides a gateway to an API over HTTP. Conforming
4+
/// type should also have the ability to encode/decode data into requests and responses using the `Codable`
5+
/// conformances and strongly typed coding of the Swift language.
6+
///
7+
/// Conforming type must specify the type representing a request like `Foundation.URLRequest` or
8+
/// `Alamofire.Request`. However, conforming type is expected to have the ability to execute the request too.
9+
///
10+
/// The `FTAPIKit` provides a standard implementation tailored for `Foundation.URLSession` and
11+
/// `Foundation` JSON coders. The standard implementation is represented by `protocol URLServer`.
112
public protocol Server {
13+
/// The type representing a `Request` of the network library, like `Foundation.URLRequest` or
14+
/// `Alamofire.Request`.
215
associatedtype Request
316

17+
/// The instance providing strongly typed decoding.
418
var decoding: Decoding { get }
19+
20+
/// The instance providing strongly typed encoding.
521
var encoding: Encoding { get }
622

23+
/// Takes a Swift description of an endpoint call and transforms it into a valid request. The reason why
24+
/// the function returns the request to the user is so the user is able to modify the request before executing.
25+
/// This is useful in cases when the API uses OAuth or some other token-based authorization, where
26+
/// the request may be delayed before the valid tokens are received.
27+
/// - Parameter endpoint: An instance of an endpoint representing a call.
28+
/// - Returns: A valid request.
729
func buildRequest(endpoint: Endpoint) throws -> Request
830
}

Sources/FTAPIKit/URLQuery.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
import Foundation
22

3+
/// `URLQuery` is a helper type, that provides a bridge between Swift and URL queries. It provides a nice, dictionary
4+
/// based Swift API and returns a correct URL query items.
5+
///
6+
/// Notice, that the elements of the dictionary literal are not internally stored as a dictionary. Therefore, arrays are
7+
/// expressible (example follows). However, only type acceptable as `Key` and `Value` is `String`.
8+
///
9+
/// ```
10+
/// let query: URLQuery = [
11+
/// "name" : "John",
12+
/// "child[]" : "Eve",
13+
/// "child[]" : "John jr."
14+
/// "child[]" : "Maggie"
15+
/// ]
16+
/// ```
317
public struct URLQuery: ExpressibleByDictionaryLiteral {
18+
/// Array of query items.
419
public let items: [URLQueryItem]
520

621
init() {
@@ -11,16 +26,20 @@ public struct URLQuery: ExpressibleByDictionaryLiteral {
1126
self.items = items
1227
}
1328

29+
/// Dictionary literals may not be unique, same keys are allowed and can't be overridden.
1430
public init(dictionaryLiteral elements: (String, String)...) {
1531
self.init(items: elements.map(URLQueryItem.init))
1632
}
1733

34+
/// Returns the query item, which is percent encoded version of provided item. If an item is already percent
35+
/// encoded, it **will** be encoded again.
1836
private func encode(item: URLQueryItem) -> URLQueryItem {
1937
let encodedName = item.name.addingPercentEncoding(withAllowedCharacters: .urlQueryNameValueAllowed) ?? item.name
2038
let encodedValue = item.value?.addingPercentEncoding(withAllowedCharacters: .urlQueryNameValueAllowed)
2139
return URLQueryItem(name: encodedName, value: encodedValue)
2240
}
2341

42+
/// String of all query items, encoded by percent encoding and divided by `&` delimiter.
2443
public var percentEncoded: String? {
2544
guard !items.isEmpty else {
2645
return nil

0 commit comments

Comments
 (0)