├── Tests
├── ServiceManagerTests
│ ├── ServiceManagerTests.swift
│ └── XCTestManifests.swift
└── LinuxMain.swift
├── README.md
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── ServiceManager.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── project.pbxproj
├── Sources
└── ServiceManager
│ ├── Service
│ ├── Info.plist
│ ├── BBServiceKit.swift
│ ├── ServiceManager.h
│ └── Service.swift
│ ├── Encoding
│ ├── AnyEncoder.swift
│ ├── EncodableExtensions.swift
│ ├── PropertyListEncoding.swift
│ ├── HTTPEncoding.swift
│ ├── JSONEncoding.swift
│ ├── URLEncoding.swift
│ └── FormDataEncoding.swift
│ ├── Route
│ ├── ResponseComponent.swift
│ ├── Route.swift
│ ├── RequestComponent.swift
│ └── URLComponent.swift
│ ├── HTTP
│ ├── HTTPScheme.swift
│ ├── HTTPMethod.swift
│ ├── HTTPError.swift
│ └── HTTPHeader.swift
│ ├── Protocols
│ ├── URLRequestConvertible.swift
│ ├── DataConvertible.swift
│ └── URLConvertible.swift
│ └── Decoding
│ └── AnyDecoder.swift
├── ServiceManager.podspec
├── LICENSE
├── Package.swift
└── .gitignore
/Tests/ServiceManagerTests/ServiceManagerTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import ServiceManager
3 |
4 | final class ServiceManagerTests: XCTestCase { }
5 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | import ServiceManagerTests
4 |
5 | var tests = [XCTestCaseEntry]()
6 | tests += ServiceManagerTests.allTests()
7 | XCTMain(tests)
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ServiceManager
2 |
3 | Lightweight, Enumerated and Protocol Oriented Networking Module written in swift 5.0. ServiceManager helps reduce networking code in view controllers and presenters.
4 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ServiceManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
--------------------------------------------------------------------------------
/Tests/ServiceManagerTests/XCTestManifests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | #if !canImport(ObjectiveC)
4 | public func allTests() -> [XCTestCaseEntry] {
5 | return [
6 | testCase(ServiceManagerTests.allTests),
7 | ]
8 | }
9 | #endif
10 |
--------------------------------------------------------------------------------
/ServiceManager.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Service/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ServiceManager.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 |
3 | spec.name = "ServiceManager"
4 | spec.version = "1.1.0"
5 | spec.summary = "Lightweight, Enumerated and Protocol Oriented Networking Module written in swift 5.0."
6 |
7 | spec.description = "Lightweight, Enumerated and Protocol Oriented Networking Module written in swift 5.0. ServiceManager helps reduce networking code in view controllers and presenters."
8 |
9 | spec.homepage = "https://github.com/bibinjacobpulickal/ServiceManager"
10 |
11 | spec.license = "MIT"
12 |
13 | spec.author = { "Bibin Jacob Pulickal" => "bibinjacob123@gmail.com" }
14 | spec.social_media_url = "https://github.com/bibinjacobpulickal"
15 |
16 | spec.ios.deployment_target = '9.0'
17 | spec.osx.deployment_target = '10.11'
18 |
19 | spec.source = { :git => "https://github.com/bibinjacobpulickal/ServiceManager.git", :tag => "1.1.0" }
20 |
21 | spec.source_files = "ServiceManager/**/*.{h,m,swift}"
22 |
23 | spec.swift_version = ['3.0', '4.0', '4.2', '5.0']
24 |
25 | end
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 bibinjacobpulickal
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "ServiceManager",
8 | products: [
9 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
10 | .library(
11 | name: "ServiceManager",
12 | targets: ["ServiceManager"]),
13 | ],
14 | dependencies: [
15 | // Dependencies declare other packages that this package depends on.
16 | // .package(url: /* package url */, from: "1.0.0"),
17 | ],
18 | targets: [
19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
20 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
21 | .target(
22 | name: "ServiceManager",
23 | dependencies: []),
24 | .testTarget(
25 | name: "ServiceManagerTests",
26 | dependencies: ["ServiceManager"]),
27 | ]
28 | )
29 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Encoding/AnyEncoder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnyEncoder.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public protocol AnyEncoder {
28 | func encode(_ value: T) throws -> Data
29 | }
30 |
31 | extension JSONEncoder: AnyEncoder { }
32 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Service/BBServiceKit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBServiceKit.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | /// Reference to `Service.shared` for quick bootstrapping and examples.
28 | public let BB = Service.shared
29 |
30 | /// Current BBServiceKit version. Necessary since SPM doesn't use dynamic libraries. Plus this will be more accurate.
31 | let version = "1.2.0"
32 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Route/ResponseComponent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseComponent.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public protocol ResponseComponent {
28 |
29 | // URLSession response object decoder, defaults to JSONDecoder().
30 | var decoder: AnyDecoder { get }
31 | }
32 |
33 | public extension ResponseComponent {
34 |
35 | var decoder: AnyDecoder { JSONDecoder() }
36 | }
37 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/HTTP/HTTPScheme.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HTTPScheme.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public struct HTTPScheme {
28 | /// `HTTPS` scheme.
29 | public static let https = HTTPScheme(rawValue: "https")
30 | /// `HTTP` scheme.
31 | public static let http = HTTPScheme(rawValue: "http")
32 | /// `FTP` scheme.
33 | public static let ftp = HTTPScheme(rawValue: "ftp")
34 |
35 | public let rawValue: String
36 | }
37 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Route/Route.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Route.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public protocol Route: URLComponent, RequestComponent, ResponseComponent { }
28 |
29 | public extension Route {
30 |
31 | func asURLRequest() throws -> URLRequest {
32 | let url = try asURL()
33 | let request = try URLRequest(url: url, method: method, body: body, headers: headers)
34 | return try encoding.encode(request, with: object, using: encoder)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Service/ServiceManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // ServiceManager.h
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 |
27 | //! Project version number for ServiceManager.
28 | FOUNDATION_EXPORT double ServiceManagerVersionNumber;
29 |
30 | //! Project version string for ServiceManager.
31 | FOUNDATION_EXPORT const unsigned char ServiceManagerVersionString[];
32 |
33 | // In this header, you should import all the public headers of your framework using statements like #import
34 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Encoding/EncodableExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EncodableExtensions.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public extension Encodable {
28 |
29 | func encoded(using encoder: AnyEncoder = JSONEncoder()) throws -> Data {
30 | try encoder.encode(self)
31 | }
32 |
33 | func jsonObject(using encoder: AnyEncoder = JSONEncoder()) throws -> Any {
34 | try JSONSerialization.jsonObject(with: try encoder.encode(self),
35 | options: .mutableLeaves)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Protocols/URLRequestConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLRequestConvertible.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | /// Types adopting the `URLRequestConvertible` protocol can be used to safely construct `URLRequest`s.
28 | public protocol URLRequestConvertible {
29 | /// Returns a `URLRequest` or throws if an `Error` was encountered.
30 | ///
31 | /// - Returns: A `URLRequest`.
32 | /// - Throws: Any error thrown while constructing the `URLRequest`.
33 | func asURLRequest() throws -> URLRequest
34 | }
35 |
36 | extension URLRequestConvertible {
37 | /// The `URLRequest` returned by discarding any `Error` encountered.
38 | public var urlRequest: URLRequest? { try? asURLRequest() }
39 | }
40 |
41 | extension URLRequest: URLRequestConvertible {
42 | /// Returns `self`.
43 | public func asURLRequest() throws -> URLRequest { self }
44 | }
45 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Protocols/DataConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataConvertible.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public protocol DataConvertible {
28 | func asData() throws -> Data
29 | }
30 |
31 | extension Data: DataConvertible {
32 | public func asData() -> Data { self }
33 | }
34 |
35 | extension String: DataConvertible {
36 | public func asData() -> Data { Data(self.utf8) }
37 | }
38 |
39 | extension Dictionary: DataConvertible where Key: Any, Value: Any {
40 | public func asData() throws -> Data {
41 | try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
42 | }
43 | }
44 |
45 | extension Array: DataConvertible where Element: Any {
46 | public func asData() throws -> Data {
47 | try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
48 | }
49 | }
50 |
51 | extension Encodable where Self: DataConvertible {
52 | public func asData() throws -> Data { try encoded() }
53 | }
54 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Route/RequestComponent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestComponent.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public protocol RequestComponent: URLRequestConvertible {
28 |
29 | // URLRequest method eg: GET, POST etc. Defaults to get.
30 | var method: HTTPMethod { get }
31 |
32 | // URLRequest httpBody of type DataConvertible. Defaults to nil.
33 | var body: DataConvertible? { get }
34 |
35 | // URLRequest headers eg: ["Authorization": "Bearer..."]. Defaults to nil.
36 | var headers: HTTPHeaders? { get }
37 |
38 | // URLRequest object. Defaults to nil
39 | var object: Encodable? { get }
40 |
41 | // URLRequest object encoder. Defaults to JSONEncoder().
42 | var encoder: AnyEncoder { get }
43 |
44 | // URLRequest object encoding. Defaults to URLEncoding.default.
45 | var encoding: HTTPEncoding { get }
46 | }
47 |
48 | public extension RequestComponent {
49 |
50 | var method: HTTPMethod { .get }
51 |
52 | var body: DataConvertible? { nil }
53 |
54 | var headers: HTTPHeaders? { nil }
55 |
56 | var object: Encodable? { nil }
57 |
58 | var encoder: AnyEncoder { JSONEncoder() }
59 |
60 | var encoding: HTTPEncoding { URLEncoding.default }
61 | }
62 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | Packages/
41 | Package.pins
42 | Package.resolved
43 | *.xcodeproj
44 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | # Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | # Carthage/Checkouts
66 |
67 | Carthage/Build/
68 |
69 | # Accio dependency management
70 | Dependencies/
71 | .accio/
72 |
73 | # fastlane
74 | #
75 | # It is recommended to not store the screenshots in the git repo.
76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
77 | # For more information about the recommended setup visit:
78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
79 |
80 | fastlane/report.xml
81 | fastlane/Preview.html
82 | fastlane/screenshots/**/*.png
83 | fastlane/test_output
84 |
85 | # Code Injection
86 | #
87 | # After new code Injection tools there's a generated folder /iOSInjectionProject
88 | # https://github.com/johnno1962/injectionforxcode
89 |
90 | iOSInjectionProject/
91 |
92 | .DS_Store
--------------------------------------------------------------------------------
/Sources/ServiceManager/Decoding/AnyDecoder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnyDecoder.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public protocol AnyDecoder {
28 | func decode(_ type: T.Type, from data: Data) throws -> T
29 | }
30 |
31 | extension JSONDecoder: AnyDecoder { }
32 |
33 | public extension Data {
34 |
35 | func decoded(using decoder: AnyDecoder = JSONDecoder()) throws -> T {
36 | try decoder.decode(T.self, from: self)
37 | }
38 |
39 | var prettyPrintedString: String {
40 | if let object = try? JSONSerialization.jsonObject(with: self, options: .mutableLeaves),
41 | JSONSerialization.isValidJSONObject(object),
42 | let data = try? JSONSerialization.data(withJSONObject: object, options: .prettyPrinted) {
43 | return String(decoding: data, as: UTF8.self)
44 | } else {
45 | return String(decoding: self, as: UTF8.self)
46 | }
47 | }
48 | }
49 |
50 | public extension KeyedDecodingContainerProtocol {
51 |
52 | func decode(forKey key: Key) throws -> T {
53 | try decode(T.self, forKey: key)
54 | }
55 |
56 | func decode(forKey key: Key, default defaultExpression: @autoclosure () -> T) throws -> T {
57 | try decodeIfPresent(T.self, forKey: key) ?? defaultExpression()
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/HTTP/HTTPMethod.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HTTPMethod.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | /// Type representing HTTP methods. Raw `String` value is stored and compared case-sensitively, so
28 | /// `HTTPMethod.get != HTTPMethod(rawValue: "get")`.
29 | ///
30 | /// See https://tools.ietf.org/html/rfc7231#section-4.3
31 | public struct HTTPMethod: RawRepresentable, Equatable, Hashable {
32 | /// `CONNECT` method.
33 | public static let connect = HTTPMethod(rawValue: "CONNECT")
34 | /// `DELETE` method.
35 | public static let delete = HTTPMethod(rawValue: "DELETE")
36 | /// `GET` method.
37 | public static let get = HTTPMethod(rawValue: "GET")
38 | /// `HEAD` method.
39 | public static let head = HTTPMethod(rawValue: "HEAD")
40 | /// `OPTIONS` method.
41 | public static let options = HTTPMethod(rawValue: "OPTIONS")
42 | /// `PATCH` method.
43 | public static let patch = HTTPMethod(rawValue: "PATCH")
44 | /// `POST` method.
45 | public static let post = HTTPMethod(rawValue: "POST")
46 | /// `PUT` method.
47 | public static let put = HTTPMethod(rawValue: "PUT")
48 | /// `TRACE` method.
49 | public static let trace = HTTPMethod(rawValue: "TRACE")
50 |
51 | public let rawValue: String
52 |
53 | public init(rawValue: String) {
54 | self.rawValue = rawValue
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Route/URLComponent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLComponent.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public protocol URLComponent: URLConvertible {
28 |
29 | // http, https etc, defaults to https.
30 | var scheme: HTTPScheme { get }
31 |
32 | // eg: www.google.com
33 | var host: String { get }
34 |
35 | // eg: 8080
36 | var port: Int? { get }
37 |
38 | // eg: /search
39 | var path: String { get }
40 |
41 | // eg: ["key": "item"], defaults to nil.
42 | var queries: Encodable? { get }
43 | }
44 |
45 | public extension URLComponent {
46 |
47 | var scheme: HTTPScheme { .https }
48 |
49 | var port: Int? { nil }
50 |
51 | var queries: Encodable? { nil }
52 | }
53 |
54 | public extension URLComponent {
55 |
56 | func asURL() throws -> URL {
57 | var components = URLComponents()
58 | components.scheme = scheme.rawValue
59 | components.host = host
60 | components.port = port
61 | components.path = path
62 | if let queries = try queries?.jsonObject() as? Parameters {
63 | for (key, value) in queries {
64 | let query = URLQueryItem(name: key, value: "\(value)")
65 | if components.queryItems?.append(query) == nil {
66 | components.queryItems = [query]
67 | }
68 | }
69 | }
70 | return try components.asURL()
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Protocols/URLConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLConvertible.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | /// Types adopting the `URLConvertible` protocol can be used to construct `URL`s, which can then be used to construct
28 | /// `URLRequests`.
29 | public protocol URLConvertible {
30 | /// Returns a `URL` from the conforming instance or throws.
31 | ///
32 | /// - Returns: The `URL` created from the instance.
33 | /// - Throws: Any error thrown while creating the `URL`.
34 | func asURL() throws -> URL
35 | }
36 |
37 | extension String: URLConvertible {
38 | /// Returns a `URL` if `self` can be used to initialize a `URL` instance, otherwise throws.
39 | ///
40 | /// - Returns: The `URL` initialized with `self`.
41 | /// - Throws: An `HTTPError.invalidURL` instance.
42 | public func asURL() throws -> URL {
43 | guard let url = URL(string: self) else { throw HTTPError.invalidURL(url: self) }
44 |
45 | return url
46 | }
47 | }
48 |
49 | extension URL: URLConvertible {
50 | /// Returns `self`.
51 | public func asURL() throws -> URL { self }
52 | }
53 |
54 | extension URLComponents: URLConvertible {
55 | /// Returns a `URL` if the `self`'s `url` is not nil, otherwise throws.
56 | ///
57 | /// - Returns: The `URL` from the `url` property.
58 | /// - Throws: An `HTTPError.invalidURL` instance.
59 | public func asURL() throws -> URL {
60 | guard let url = url else { throw HTTPError.invalidURL(url: self) }
61 |
62 | return url
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Encoding/PropertyListEncoding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PropertyListEncoding.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public struct PropertyListEncoding: ParameterEncoding {
28 |
29 | public static var `default`: PropertyListEncoding { PropertyListEncoding() }
30 |
31 | public static var xml: PropertyListEncoding { PropertyListEncoding(format: .xml) }
32 |
33 | public static var binary: PropertyListEncoding { PropertyListEncoding(format: .binary) }
34 |
35 | public static var openStep: PropertyListEncoding { PropertyListEncoding(format: .openStep) }
36 |
37 | public let format: PropertyListSerialization.PropertyListFormat
38 |
39 | public let options: PropertyListSerialization.WriteOptions
40 |
41 | public init(
42 | format: PropertyListSerialization.PropertyListFormat = .xml,
43 | options: PropertyListSerialization.WriteOptions = 0)
44 | {
45 | self.format = format
46 | self.options = options
47 | }
48 |
49 | public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
50 | var urlRequest = try urlRequest.asURLRequest()
51 |
52 | guard let parameters = parameters else { return urlRequest }
53 |
54 | do {
55 | let data = try PropertyListSerialization.data(
56 | fromPropertyList: parameters,
57 | format: format,
58 | options: options
59 | )
60 |
61 | if urlRequest.headers["Content-Type"] == nil {
62 | urlRequest.headers.update(.contentType("application/x-plist"))
63 | }
64 |
65 | urlRequest.httpBody = data
66 | } catch {
67 | throw HTTPError.parameterEncodingFailed(reason: .propertyListEncodingFailed(error: error))
68 | }
69 |
70 | return urlRequest
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Encoding/HTTPEncoding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HTTPEncoding.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | /// A dictionary of parameters to apply to a `URLRequest`.
28 | public typealias Parameters = [String: Any]
29 |
30 | /// A type used to define how a set of parameters are applied to a `URLRequest`.
31 | public protocol HTTPEncoding {
32 | /// Creates a `URLRequest` by encoding parameters and applying them on the passed request.
33 | ///
34 | /// - Parameters:
35 | /// - urlRequest: `URLRequestConvertible` value onto which parameters will be encoded.
36 | /// - object: `object` to encode onto the request.
37 | /// - encoder: `encoder` to be used for encoding.
38 | ///
39 | /// - Returns: The encoded `URLRequest`.
40 | /// - Throws: Any `Error` produced during parameter encoding.
41 | func encode(_ urlRequest: URLRequestConvertible, with object: Encodable?, using encoder: AnyEncoder) throws -> URLRequest
42 | }
43 |
44 | /// A type used to define how a set of parameters are applied to a `URLRequest`.
45 | public protocol ParameterEncoding: HTTPEncoding {
46 | /// Creates a `URLRequest` by encoding parameters and applying them on the passed request.
47 | ///
48 | /// - Parameters:
49 | /// - urlRequest: `URLRequestConvertible` value onto which parameters will be encoded.
50 | /// - parameters: `Parameters` to encode onto the request.
51 | ///
52 | /// - Returns: The encoded `URLRequest`.
53 | /// - Throws: Any `Error` produced during parameter encoding.
54 | func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest
55 | }
56 |
57 | extension ParameterEncoding {
58 |
59 | public func encode(_ urlRequest: URLRequestConvertible, with object: Encodable?, using encoder: AnyEncoder) throws -> URLRequest {
60 | try encode(urlRequest, with: try object?.jsonObject(using: encoder) as? Parameters)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Encoding/JSONEncoding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JSONEncoding.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public struct JSONEncoding: HTTPEncoding {
28 |
29 | public static var `default`: JSONEncoding { JSONEncoding() }
30 |
31 | public static var empty: JSONEncoding { JSONEncoding(options: []) }
32 |
33 | public static var prettyPrinted: JSONEncoding { JSONEncoding(options: .prettyPrinted) }
34 |
35 | public static var fragmentsAllowed: JSONEncoding { JSONEncoding(options: .fragmentsAllowed) }
36 |
37 | @available(iOS 11.0, *)
38 | @available(OSX 10.13, *)
39 | public static var sortedKeys: JSONEncoding { JSONEncoding(options: .sortedKeys) }
40 |
41 | @available(iOS 13.0, *)
42 | @available(OSX 10.15, *)
43 | public static var withoutEscapingSlashes: JSONEncoding { JSONEncoding(options: .withoutEscapingSlashes) }
44 |
45 | public let options: JSONSerialization.WritingOptions?
46 |
47 | public init(options: JSONSerialization.WritingOptions? = nil) {
48 | self.options = options
49 | }
50 |
51 | public func encode(_ urlRequest: URLRequestConvertible, with object: Encodable?, using encoder: AnyEncoder) throws -> URLRequest {
52 | var urlRequest = try urlRequest.asURLRequest()
53 |
54 | guard let object = object else { return urlRequest }
55 |
56 | do {
57 | if let options = options {
58 |
59 | let jsonObject = try object.jsonObject(using: encoder)
60 |
61 | urlRequest.httpBody = try JSONSerialization.data(withJSONObject: jsonObject, options: options)
62 | } else {
63 |
64 | urlRequest.httpBody = try object.encoded(using: encoder)
65 | }
66 | } catch {
67 | throw HTTPError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
68 | }
69 | if urlRequest.headers["Content-Type"] == nil {
70 | urlRequest.headers.update(.contentType("application/json"))
71 | }
72 |
73 | return urlRequest
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Encoding/URLEncoding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLEncoding.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public struct URLEncoding: ParameterEncoding {
28 |
29 | public enum Destination {
30 | case methodDependent, queryString, httpBody
31 | }
32 |
33 | public enum ArrayEncoding {
34 | case brackets, noBrackets
35 |
36 | func encode(key: String) -> String {
37 | switch self {
38 | case .brackets:
39 | return "\(key)[]"
40 | case .noBrackets:
41 | return key
42 | }
43 | }
44 | }
45 |
46 | public enum BoolEncoding {
47 | case numeric, literal
48 |
49 | func encode(value: Bool) -> String {
50 | switch self {
51 | case .numeric:
52 | return value ? "1" : "0"
53 | case .literal:
54 | return value ? "true" : "false"
55 | }
56 | }
57 | }
58 |
59 | public static var `default`: URLEncoding { URLEncoding() }
60 |
61 | public static var methodDependent: URLEncoding { URLEncoding() }
62 |
63 | public static var queryString: URLEncoding { URLEncoding(destination: .queryString) }
64 |
65 | public static var httpBody: URLEncoding { URLEncoding(destination: .httpBody) }
66 |
67 | public let destination: Destination
68 |
69 | public let arrayEncoding: ArrayEncoding
70 |
71 | public let boolEncoding: BoolEncoding
72 |
73 | public init(destination: Destination = .methodDependent, arrayEncoding: ArrayEncoding = .brackets, boolEncoding: BoolEncoding = .numeric) {
74 | self.destination = destination
75 | self.arrayEncoding = arrayEncoding
76 | self.boolEncoding = boolEncoding
77 | }
78 |
79 | public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
80 | var urlRequest = try urlRequest.asURLRequest()
81 |
82 | guard let parameters = parameters else { return urlRequest }
83 |
84 | let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET")
85 | if encodesParametersInURL(with: method) {
86 | guard let url = urlRequest.url else {
87 | throw HTTPError.parameterEncodingFailed(reason: .missingURL)
88 | }
89 |
90 | if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty {
91 | let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters)
92 | urlComponents.percentEncodedQuery = percentEncodedQuery
93 | urlRequest.url = urlComponents.url
94 | }
95 | } else {
96 | if urlRequest.headers["Content-Type"] == nil {
97 | urlRequest.headers.update(.contentType("application/x-www-form-urlencoded; charset=utf-8"))
98 | }
99 |
100 | urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)
101 | }
102 |
103 | return urlRequest
104 | }
105 |
106 | public func queryComponents(fromKey key: String, value: Any) -> [(String, String)] {
107 | var components: [(String, String)] = []
108 |
109 | if let dictionary = value as? [String: Any] {
110 | for (nestedKey, value) in dictionary {
111 | components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value)
112 | }
113 | } else if let array = value as? [Any] {
114 | for value in array {
115 | components += queryComponents(fromKey: arrayEncoding.encode(key: key), value: value)
116 | }
117 | } else if let value = value as? NSNumber {
118 | if value.isBool {
119 | components.append((escape(key), escape(boolEncoding.encode(value: value.boolValue))))
120 | } else {
121 | components.append((escape(key), escape("\(value)")))
122 | }
123 | } else if let bool = value as? Bool {
124 | components.append((escape(key), escape(boolEncoding.encode(value: bool))))
125 | } else {
126 | components.append((escape(key), escape("\(value)")))
127 | }
128 |
129 | return components
130 | }
131 |
132 | public func escape(_ string: String) -> String {
133 | let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
134 | let subDelimitersToEncode = "!$&'()*+,;="
135 |
136 | var allowedCharacterSet = CharacterSet.urlQueryAllowed
137 | allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
138 |
139 | var escaped = ""
140 |
141 | if #available(iOS 8.3, *) {
142 | escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string
143 | } else {
144 | let batchSize = 50
145 | var index = string.startIndex
146 |
147 | while index != string.endIndex {
148 | let startIndex = index
149 | let endIndex = string.index(index, offsetBy: batchSize, limitedBy: string.endIndex) ?? string.endIndex
150 | let range = startIndex.. String {
164 | var components: [(String, String)] = []
165 |
166 | for key in parameters.keys.sorted(by: <) {
167 | let value = parameters[key]!
168 | components += queryComponents(fromKey: key, value: value)
169 | }
170 | return components.map { "\($0)=\($1)" }.joined(separator: "&")
171 | }
172 |
173 | private func encodesParametersInURL(with method: HTTPMethod) -> Bool {
174 | switch destination {
175 | case .queryString:
176 | return true
177 | case .httpBody:
178 | return false
179 | default:
180 | break
181 | }
182 |
183 | switch method {
184 | case .get, .head, .delete:
185 | return true
186 | default:
187 | return false
188 | }
189 | }
190 | }
191 |
192 | extension NSNumber {
193 | fileprivate var isBool: Bool { CFBooleanGetTypeID() == CFGetTypeID(self) }
194 | }
195 |
--------------------------------------------------------------------------------
/Sources/ServiceManager/Service/Service.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Service.swift
3 | //
4 | // Copyright © 2020 Bibin Jacob Pulickal (https://github.com/bibinjacobpulickal)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public typealias ServiceResult