Merge pull request #1 from shial4/Release-0.1.0

Release 0.1.0
This commit is contained in:
Shial 2017-12-27 14:51:20 +11:00 committed by GitHub
commit a3f000a541
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 314 additions and 114 deletions

View File

@ -15,7 +15,7 @@
</a> </a>
</p> </p>
SLazeKit is an easy to use Swift restfull collection of extensions and classes. Don't spend hours writing your code to map your rest api request into models and coredata serialization. Stop wasting your time! SLazeKit is an easy to use Swift restful collection of extensions and classes. Don't spend hours writing your code to map your rest api request into models and coredata serialization. Stop wasting your time!
**SLazeKit allows you:** **SLazeKit allows you:**
- map your models by `Codable` protocol - map your models by `Codable` protocol
@ -47,10 +47,19 @@ This project demonstrates a working method for using Swift Package Manager (SPM)
## 💊 Usage ## 💊 Usage
For positive experience, you should configure `SLazeKit` at first. This step is optional. You may leave it as it is default. For positive experience, you should configure `SLazeKit` at first. This step is REQUIRED!
```swift ```swift
import SLazeKit import SLazeKit
/// Required override of this method which will provide Context for bacground execution.
///
/// - Returns: NSManagedObjectContext
open class func newBackgroundContext() -> NSManagedObjectContext? { return nil }
```
This step is optional. You may leave it as it is default.
```swift
import SLazeKit
extension SLazeKit { extension SLazeKit {
//Provide base path for your API requests. //Provide base path for your API requests.
open class var basePath?: String { return "www.yourdomain.com" } open class var basePath?: String { return "www.yourdomain.com" }
@ -78,6 +87,9 @@ extension SLazeKit {
``` ```
**Model example** **Model example**
Simple
[Object.swift](Tests/SLazeKitTests/Models/Object.swift)
Advance
[Model.swift](Tests/SLazeKitTests/Models/Model.swift) [Model.swift](Tests/SLazeKitTests/Models/Model.swift)
## ⭐ Contributing ## ⭐ Contributing

View File

@ -21,6 +21,7 @@
/* End PBXAggregateTarget section */ /* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
625B23AD1FF3462B001976C3 /* Object.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625B23AB1FF34625001976C3 /* Object.swift */; };
OBJ_32 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; OBJ_32 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; };
OBJ_38 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* Model.swift */; }; OBJ_38 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* Model.swift */; };
OBJ_39 /* SLazeKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* SLazeKitTests.swift */; }; OBJ_39 /* SLazeKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* SLazeKitTests.swift */; };
@ -53,6 +54,7 @@
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
625B23AB1FF34625001976C3 /* Object.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Object.swift; sourceTree = "<group>"; };
OBJ_10 /* Decodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Decodable.swift; sourceTree = "<group>"; }; OBJ_10 /* Decodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Decodable.swift; sourceTree = "<group>"; };
OBJ_11 /* NSManagedObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSManagedObject.swift; sourceTree = "<group>"; }; OBJ_11 /* NSManagedObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSManagedObject.swift; sourceTree = "<group>"; };
OBJ_12 /* NSManagedObjectContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSManagedObjectContext.swift; sourceTree = "<group>"; }; OBJ_12 /* NSManagedObjectContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSManagedObjectContext.swift; sourceTree = "<group>"; };
@ -119,6 +121,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
OBJ_21 /* Model.swift */, OBJ_21 /* Model.swift */,
625B23AB1FF34625001976C3 /* Object.swift */,
); );
path = Models; path = Models;
sourceTree = "<group>"; sourceTree = "<group>";
@ -132,7 +135,7 @@
name = Products; name = Products;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
OBJ_5 /* */ = { OBJ_5 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
OBJ_6 /* Package.swift */, OBJ_6 /* Package.swift */,
@ -140,7 +143,6 @@
OBJ_18 /* Tests */, OBJ_18 /* Tests */,
OBJ_24 /* Products */, OBJ_24 /* Products */,
); );
name = "";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
OBJ_7 /* Sources */ = { OBJ_7 /* Sources */ = {
@ -238,7 +240,7 @@
knownRegions = ( knownRegions = (
en, en,
); );
mainGroup = OBJ_5 /* */; mainGroup = OBJ_5;
productRefGroup = OBJ_24 /* Products */; productRefGroup = OBJ_24 /* Products */;
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
@ -266,6 +268,7 @@
files = ( files = (
OBJ_38 /* Model.swift in Sources */, OBJ_38 /* Model.swift in Sources */,
OBJ_39 /* SLazeKitTests.swift in Sources */, OBJ_39 /* SLazeKitTests.swift in Sources */,
625B23AD1FF3462B001976C3 /* Object.swift in Sources */,
OBJ_40 /* StringInitializableTests.swift in Sources */, OBJ_40 /* StringInitializableTests.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;

View File

@ -1,63 +1,99 @@
import Foundation import Foundation
extension Decodable { extension Decodable {
public static func request<T: Encodable>(path: String, method: HTTPMethod, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func request(path: String, method: HTTPMethod, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, body: body, handler: handler)
} }
public static func request<T: Encodable>(path: String, method: HTTPMethod, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func request<T: Encodable>(path: String, method: HTTPMethod, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, body: body, handler: handler)
} }
public static func request(path: String, method: HTTPMethod, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func request<T: Encodable>(path: String, method: HTTPMethod, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, body: body, handler: handler)
}
public static func request(path: String, method: HTTPMethod, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, handler: handler) return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, handler: handler)
} }
public static func get<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func get(path: String, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, queryItems: queryItems, body: body, handler: handler)
} }
public static func get<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func get<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, queryItems: queryItems, body: body, handler: handler)
} }
public static func get(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func get<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, queryItems: queryItems, body: body, handler: handler)
}
public static func get(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, queryItems: queryItems, handler: handler) return SLazeKit.networkTask(path: path, queryItems: queryItems, handler: handler)
} }
public static func post<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func post(path: String, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, body: body, handler: handler)
} }
public static func post<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func post<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, body: body, handler: handler)
} }
public static func post(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func post<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, body: body, handler: handler)
}
public static func post(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, handler: handler) return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, handler: handler)
} }
public static func put<T: Encodable>(path: String, queryItems: [URLQueryItem]? = nil, body: T, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func put(path: String, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, body: body, handler: handler)
} }
public static func put<T: Encodable>(path: String, queryItems: [URLQueryItem]? = nil, body: [T], handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func put<T: Encodable>(path: String, queryItems: [URLQueryItem]? = nil, body: T, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, body: body, handler: handler)
} }
public static func put(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func put<T: Encodable>(path: String, queryItems: [URLQueryItem]? = nil, body: [T], handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, body: body, handler: handler)
}
public static func put(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, handler: handler) return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, handler: handler)
} }
public static func delete<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func patch(path: String, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PATCH, queryItems: queryItems, body: body, handler: handler)
}
public static func patch<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PATCH, queryItems: queryItems, body: body, handler: handler)
}
public static func patch<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PATCH, queryItems: queryItems, body: body, handler: handler)
}
public static func patch(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PATCH, queryItems: queryItems, handler: handler)
}
public static func delete(path: String, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, body: body, handler: handler)
} }
public static func delete<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func delete<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, body: body, handler: handler)
} }
public static func delete(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? { public static func delete<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, body: body, handler: handler)
}
public static func delete(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: Self?, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, handler: handler) return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, handler: handler)
} }
} }

View File

@ -2,10 +2,16 @@ import Foundation
import CoreData import CoreData
extension NSManagedObject { extension NSManagedObject {
/// String entity name
public class var entityName: String? { public class var entityName: String? {
return NSStringFromClass(self).components(separatedBy: ".").last return NSStringFromClass(self).components(separatedBy: ".").last
} }
/// Finds `NSManagedObject` by EntityAttribute parameters.
///
/// - Parameters:
/// - context: Context on which fetch should be executed
/// - attributes: Entity attribute mapped by key - value
/// - Returns: Returns first object that meet the criteria specified by a given fetch request.
public class func find(_ context: NSManagedObjectContext?, by attributes: EntityAttribute...) throws -> NSManagedObject? { public class func find(_ context: NSManagedObjectContext?, by attributes: EntityAttribute...) throws -> NSManagedObject? {
guard let name = entityName else { return nil } guard let name = entityName else { return nil }
let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest<NSManagedObject>(entityName: name) let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest<NSManagedObject>(entityName: name)
@ -16,6 +22,12 @@ extension NSManagedObject {
return try context?.fetch(fetchRequest).first return try context?.fetch(fetchRequest).first
} }
/// Finds `NSManagedObject` by EntityAttribute parameters.
///
/// - Parameters:
/// - context: Context on which fetch should be executed
/// - attributes: Entity attribute mapped by key - value
/// - Returns: Returns first object that meet the criteria specified by a given fetch request.
public class func find(_ context: NSManagedObjectContext?, by attributes: [EntityAttribute]) throws -> NSManagedObject? { public class func find(_ context: NSManagedObjectContext?, by attributes: [EntityAttribute]) throws -> NSManagedObject? {
guard let name = entityName else { return nil } guard let name = entityName else { return nil }
let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest<NSManagedObject>(entityName: name) let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest<NSManagedObject>(entityName: name)

View File

@ -2,6 +2,7 @@ import Foundation
import CoreData import CoreData
extension NSManagedObjectContext { extension NSManagedObjectContext {
/// Ifthe context has uncommitted changes, attempts to commit unsaved changes to registered objects to the contexts parent store.
func commit() { func commit() {
if hasChanges { if hasChanges {
do { do {

View File

@ -1,6 +1,14 @@
import Foundation import Foundation
extension String { extension String {
/// Replace string patter keys with values. For example:
///
/// in pattern `"/api/path/:id"`
///
/// `[":id":"\(123-XYZ-321)"]` `:id` key would be replaced with `"\(123-XYZ-321)"` value.
///
/// - Parameter arguments: Dictionary with key & value to replace.
/// - Returns: Path with values instead of keys.
public func patternToPath(with arguments: [String : String] = [:]) -> String { public func patternToPath(with arguments: [String : String] = [:]) -> String {
var path = self var path = self
for (key, value) in arguments { for (key, value) in arguments {

View File

@ -1,18 +1,19 @@
import Foundation import Foundation
import CoreData import CoreData
/// Entity attribute alias for key, value tuple.
public typealias EntityAttribute = (key: String, value: Any) public typealias EntityAttribute = (key: String, value: Any)
/// Mapping protocol. Required for request object serialization.
public protocol EntityMapping { public protocol EntityMapping {
static var entityType: NSManagedObject.Type { get } static var entityType: NSManagedObject.Type { get }
var idAttributes: [EntityAttribute]? { get } var idAttributes: [EntityAttribute]? { get }
func fillObject(with model: NSManagedObject) func fillObject(with model: NSManagedObject)
} }
@available(iOS 10.0, *)
extension EntityMapping { extension EntityMapping {
func map() throws -> NSManagedObject? { func map() throws -> NSManagedObject? {
guard let context = Self.persistentContainer?.newBackgroundContext() else { return nil } guard let context = SLazeKit.newBackgroundContext() else { return nil }
let model: NSManagedObject let model: NSManagedObject
if let attribiutes = idAttributes { if let attribiutes = idAttributes {
model = try Self.entityType.find(context, by: attribiutes) ?? Self.entityType.init(context: context) model = try Self.entityType.find(context, by: attribiutes) ?? Self.entityType.init(context: context)
@ -23,20 +24,27 @@ extension EntityMapping {
context.performAndWait { context.commit() } context.performAndWait { context.commit() }
return model return model
} }
private func findObject(_ context: NSManagedObjectContext?) throws -> NSManagedObject? { private func findObject(_ context: NSManagedObjectContext?) throws -> NSManagedObject? {
return try Self.entityType.find(context, by: idAttributes ?? []) return try Self.entityType.find(context, by: idAttributes ?? [])
} }
}
/// Serialized managed object from datastore by given attribiutes. To be more specific. If request is returning JSON with `EntityMapping` and given Encodable object conform to this protocol. It will be automaticaly updated in DataStore. This method featch this object.
extension EntityMapping { ///
/// - Parameter context: Context on which fetch should be executed
/// - Returns: Serialized object from EntityMapping model
public func serialized<T: NSManagedObject>(_ context: NSManagedObjectContext?) throws -> T? { public func serialized<T: NSManagedObject>(_ context: NSManagedObjectContext?) throws -> T? {
return (try Self.entityType.find(context, by: idAttributes ?? [])) as? T return (try Self.entityType.find(context, by: idAttributes ?? [])) as? T
} }
} }
extension Array where Element: EntityMapping { extension Array where Element: EntityMapping {
/// Serialized managed objects from datastore by given attribiutes. To be more specific. If request is returning JSON with `EntityMapping` and given Encodable object conform to this protocol. It will be automaticaly updated in DataStore. This method featch this objects.
///
/// - Parameter context: Context on which fetch should be executed
/// - Returns: Array of serialized object from EntityMapping response type.
public func serialized<T: NSManagedObject>(_ context: NSManagedObjectContext?) throws -> [T] { public func serialized<T: NSManagedObject>(_ context: NSManagedObjectContext?) throws -> [T] {
return try flatMap({ try $0.serialized(context) }) return try flatMap({ try $0.serialized(context) })
} }
} }

View File

@ -5,6 +5,12 @@ public protocol StringInitializable {
} }
extension KeyedDecodingContainerProtocol { extension KeyedDecodingContainerProtocol {
/// If you API have unstable JSON responses for number types. You can use this helper method to decode string as a number. However, first you need extend your desired number type with `StringInitializable` protocol.
///
/// - Parameters:
/// - type: Type to decode
/// - key: JSON key under given type should be stored
/// - Returns: Desired type value
public func decodeUnstable<T: Decodable & StringInitializable>(_ type: T.Type = T.self, forKey key: Key) throws -> T? { public func decodeUnstable<T: Decodable & StringInitializable>(_ type: T.Type = T.self, forKey key: Key) throws -> T? {
guard contains(key) else { return nil } guard contains(key) else { return nil }
guard !(try decodeNil(forKey: key)) else { return nil } guard !(try decodeNil(forKey: key)) else { return nil }
@ -19,6 +25,12 @@ extension KeyedDecodingContainerProtocol {
} }
return try decode(T.self, forKey: key) return try decode(T.self, forKey: key)
} }
/// If you API have unstable JSON responses for number types. You can use this helper method to decode string as a number. However, first you need extend your desired number type with `StringInitializable` protocol.
///
/// - Parameters:
/// - type: Type to decode
/// - key: JSON key under given type should be stored
/// - Returns: Desired type value
public func decodeUnstable<T: Decodable & StringInitializable>(_ type: T.Type = T.self, forKey key: Key) throws -> T { public func decodeUnstable<T: Decodable & StringInitializable>(_ type: T.Type = T.self, forKey key: Key) throws -> T {
if let string = try? decode(String.self, forKey: key) { if let string = try? decode(String.self, forKey: key) {
guard let value = T.init(rawValue: string) else { guard let value = T.init(rawValue: string) else {

View File

@ -4,60 +4,79 @@ import CoreData
public typealias EntityMappingCodable = EntityMapping & Codable public typealias EntityMappingCodable = EntityMapping & Codable
public typealias EntityMappingDecodable = EntityMapping & Decodable public typealias EntityMappingDecodable = EntityMapping & Decodable
/// NetworkResponse tuple holding response `Data` and `HTTPURLResponse`
public typealias NetworkResponse = (data: Data?, urlResponse: HTTPURLResponse?)
/// HTTPMethod types
public enum HTTPMethod { public enum HTTPMethod {
case GET, POST, PUT, PATCH, DELETE, COPY, HEAD, OPTIONS, LINK, UNLINK, PURGE, LOCK, UNLOCK, PROPFIND, VIEW case GET, POST, PUT, PATCH, DELETE, COPY, HEAD, OPTIONS, LINK, UNLINK, PURGE, LOCK, UNLOCK, PROPFIND, VIEW
} }
@available(iOS 10.0, *) /// SLazeKit is an easy to use restful collection of extensions and classes. Maps your rest api request into models and provides coredata serialization.
extension EntityMapping {
public static var persistentContainer: NSPersistentContainer? { return nil }
}
public class SLazeKit { public class SLazeKit {
/// Provide base path for your API requests.
open class var basePath: String? { return nil } open class var basePath: String? { return nil }
/// Additional you can set port for your requests.
open class var basePort: Int? { return nil } open class var basePort: Int? { return nil }
/// Optional provider for JSONDecoder instance.
open class var decoder: JSONDecoder { return JSONDecoder() } open class var decoder: JSONDecoder { return JSONDecoder() }
/// Optional provider for JSONDecoder instance.
open class var urlSession: URLSession { return URLSession.shared } open class var urlSession: URLSession { return URLSession.shared }
/// Global outgoing `URLRequest` customization. Called everytime request is created before executed.
///
/// - Parameter request: `URLRequest` object to setup
/// - Returns: already setup and customize URLRequest object
open class func setup(_ request: URLRequest) -> URLRequest { return request } open class func setup(_ request: URLRequest) -> URLRequest { return request }
open class func handle(_ response: HTTPURLResponse?) {} open class func handle(_ response: HTTPURLResponse?) {}
}
/// Required override of this method which will provide Context for bacground execution.
//MARK: network tasks implementation ///
extension SLazeKit { /// - Returns: NSManagedObjectContext
class func networkTask(request: URLRequest, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { open class func newBackgroundContext() -> NSManagedObjectContext? { return nil }
class func networkTask(request: URLRequest, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
let task = urlSession.dataTask(with: setup(request)) { (data, response, error) in let task = urlSession.dataTask(with: setup(request)) { (data, response, error) in
handle(response as? HTTPURLResponse) handle(response as? HTTPURLResponse)
handler(response as? HTTPURLResponse, error) handler((data, response as? HTTPURLResponse), error)
} }
task.resume() task.resume()
return task return task
} }
class func networkTask<T: Decodable>(request: URLRequest, handler: @escaping (_ response: HTTPURLResponse?, _ result: T?, _ error: Error?) -> ()) -> URLSessionDataTask? { class func networkTask<T: Decodable>(request: URLRequest, handler: @escaping (_ response: NetworkResponse, _ result: T?, _ error: Error?) -> ()) -> URLSessionDataTask? {
let task = urlSession.dataTask(with: setup(request)) { (data, response, error) in let task = urlSession.dataTask(with: setup(request)) { (data, response, error) in
handle(response as? HTTPURLResponse) handle(response as? HTTPURLResponse)
if let data = data, error == nil { if let data = data, error == nil {
do { do {
let object = try decoder.decode(T.self, from: data) let object = try decoder.decode(T.self, from: data)
if #available(iOS 10.0, *) { try synchronize(object)
try synchronize(object) handler((data, response as? HTTPURLResponse), object, nil)
}
handler(response as? HTTPURLResponse, object, nil)
} catch { } catch {
handler(response as? HTTPURLResponse, nil, error) handler((data, response as? HTTPURLResponse), nil, error)
} }
} else { } else {
handler(response as? HTTPURLResponse, nil, error) handler((data, response as? HTTPURLResponse), nil, error)
} }
} }
task.resume() task.resume()
return task return task
} }
class func networkTask<B: Encodable>(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, body: B, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { class func networkTask(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, body: String, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
guard let url = components(for: path, queryItems: queryItems)?.url else { guard let url = components(for: path, queryItems: queryItems)?.url else {
handler(nil, NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil)) handler((nil,nil), NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil))
return nil
}
var request = urlRequest(url, method: method)
request.httpBody = body.data(using: .utf8)
return networkTask(request: request, handler: handler)
}
class func networkTask<B: Encodable>(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, body: B, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
guard let url = components(for: path, queryItems: queryItems)?.url else {
handler((nil,nil), NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil))
return nil return nil
} }
@ -65,16 +84,28 @@ extension SLazeKit {
do { do {
request.httpBody = try JSONEncoder().encode(body) request.httpBody = try JSONEncoder().encode(body)
} catch { } catch {
handler(nil, error) handler((nil,nil), error)
return nil return nil
} }
return networkTask(request: request, handler: handler) return networkTask(request: request, handler: handler)
} }
class func networkTask<T: Decodable, B: Encodable>(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, body: B, handler: @escaping (_ response: HTTPURLResponse?, _ result: T?, _ error: Error?) -> ()) -> URLSessionDataTask? { class func networkTask<T: Decodable>(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, body: String, handler: @escaping (_ response: NetworkResponse, _ result: T?, _ error: Error?) -> ()) -> URLSessionDataTask? {
guard let url = components(for: path, queryItems: queryItems)?.url else { guard let url = components(for: path, queryItems: queryItems)?.url else {
handler(nil, nil, NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil)) handler((nil,nil), nil, NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil))
return nil
}
var request = urlRequest(url, method: method)
request.httpBody = body.data(using: .utf8)
return networkTask(request: request, handler: handler)
}
class func networkTask<T: Decodable, B: Encodable>(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, body: B, handler: @escaping (_ response: NetworkResponse, _ result: T?, _ error: Error?) -> ()) -> URLSessionDataTask? {
guard let url = components(for: path, queryItems: queryItems)?.url else {
handler((nil,nil), nil, NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil))
return nil return nil
} }
@ -82,16 +113,16 @@ extension SLazeKit {
do { do {
request.httpBody = try JSONEncoder().encode(body) request.httpBody = try JSONEncoder().encode(body)
} catch { } catch {
handler(nil, nil, error) handler((nil,nil), nil, error)
return nil return nil
} }
return networkTask(request: request, handler: handler) return networkTask(request: request, handler: handler)
} }
class func networkTask<B: Encodable>(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, body: [B], handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { class func networkTask<B: Encodable>(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, body: [B], handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
guard let url = components(for: path, queryItems: queryItems)?.url else { guard let url = components(for: path, queryItems: queryItems)?.url else {
handler(nil, NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil)) handler((nil,nil), NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil))
return nil return nil
} }
@ -99,16 +130,16 @@ extension SLazeKit {
do { do {
request.httpBody = try JSONEncoder().encode(body) request.httpBody = try JSONEncoder().encode(body)
} catch { } catch {
handler(nil, error) handler((nil,nil), error)
return nil return nil
} }
return networkTask(request: request, handler: handler) return networkTask(request: request, handler: handler)
} }
class func networkTask<T: Decodable, B: Encodable>(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, body: [B], handler: @escaping (_ response: HTTPURLResponse?, _ result: T?, _ error: Error?) -> ()) -> URLSessionDataTask? { class func networkTask<T: Decodable, B: Encodable>(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, body: [B], handler: @escaping (_ response: NetworkResponse, _ result: T?, _ error: Error?) -> ()) -> URLSessionDataTask? {
guard let url = components(for: path, queryItems: queryItems)?.url else { guard let url = components(for: path, queryItems: queryItems)?.url else {
handler(nil, nil, NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil)) handler((nil,nil), nil, NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil))
return nil return nil
} }
@ -116,24 +147,24 @@ extension SLazeKit {
do { do {
request.httpBody = try JSONEncoder().encode(body) request.httpBody = try JSONEncoder().encode(body)
} catch { } catch {
handler(nil, nil, error) handler((nil,nil), nil, error)
return nil return nil
} }
return networkTask(request: request, handler: handler) return networkTask(request: request, handler: handler)
} }
class func networkTask(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { class func networkTask(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
guard let url = components(for: path, queryItems: queryItems)?.url else { guard let url = components(for: path, queryItems: queryItems)?.url else {
handler(nil, NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil)) handler((nil,nil), NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil))
return nil return nil
} }
return networkTask(request: urlRequest(url, method: method), handler: handler) return networkTask(request: urlRequest(url, method: method), handler: handler)
} }
class func networkTask<T: Decodable>(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ result: T?, _ error: Error?) -> ()) -> URLSessionDataTask? { class func networkTask<T: Decodable>(path: String, method: HTTPMethod? = nil, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ result: T?, _ error: Error?) -> ()) -> URLSessionDataTask? {
guard let url = components(for: path, queryItems: queryItems)?.url else { guard let url = components(for: path, queryItems: queryItems)?.url else {
handler(nil, nil, NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil)) handler((nil,nil), nil, NSError(domain: "Unable to get url from components", code: NSURLErrorBadURL, userInfo: nil))
return nil return nil
} }
return networkTask(request: urlRequest(url, method: method), handler: handler) return networkTask(request: urlRequest(url, method: method), handler: handler)
@ -153,12 +184,8 @@ extension SLazeKit {
urlComponents?.queryItems = queryItems urlComponents?.queryItems = queryItems
return urlComponents return urlComponents
} }
}
private class func synchronize(_ obj: Any) throws {
//MARK: CoreData mapping support
extension SLazeKit {
@available(iOS 10.0, *)
fileprivate class func synchronize(_ obj: Any) throws {
if let array = obj as? [EntityMapping] { if let array = obj as? [EntityMapping] {
array.forEach({_ = try? $0.map()}) array.forEach({_ = try? $0.map()})
} else { } else {
@ -169,63 +196,99 @@ extension SLazeKit {
} }
extension SLazeKit { extension SLazeKit {
public class func request<T: Encodable>(path: String, method: HTTPMethod, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func request(path: String, method: HTTPMethod, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, body: body, handler: handler)
} }
public class func request<T: Encodable>(path: String, method: HTTPMethod, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func request<T: Encodable>(path: String, method: HTTPMethod, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, body: body, handler: handler)
} }
public class func request(path: String, method: HTTPMethod, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func request<T: Encodable>(path: String, method: HTTPMethod, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, body: body, handler: handler)
}
public class func request(path: String, method: HTTPMethod, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, handler: handler) return SLazeKit.networkTask(path: path, method: method, queryItems: queryItems, handler: handler)
} }
public class func get<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func get(path: String, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, queryItems: queryItems, body: body, handler: handler)
} }
public class func get<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func get<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, queryItems: queryItems, body: body, handler: handler)
} }
public class func get(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func get<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, queryItems: queryItems, body: body, handler: handler)
}
public class func get(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, queryItems: queryItems, handler: handler) return SLazeKit.networkTask(path: path, queryItems: queryItems, handler: handler)
} }
public class func post<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func post(path: String, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, body: body, handler: handler)
} }
public class func post<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func post<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, body: body, handler: handler)
} }
public class func post(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func post<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, body: body, handler: handler)
}
public class func post(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, handler: handler) return SLazeKit.networkTask(path: path, method: .POST, queryItems: queryItems, handler: handler)
} }
public class func put<T: Encodable>(path: String, queryItems: [URLQueryItem]? = nil, body: T, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func put(path: String, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, body: body, handler: handler)
} }
public class func put<T: Encodable>(path: String, queryItems: [URLQueryItem]? = nil, body: [T], handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func put<T: Encodable>(path: String, queryItems: [URLQueryItem]? = nil, body: T, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, body: body, handler: handler)
} }
public class func put(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func put<T: Encodable>(path: String, queryItems: [URLQueryItem]? = nil, body: [T], handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, body: body, handler: handler)
}
public class func put(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, handler: handler) return SLazeKit.networkTask(path: path, method: .PUT, queryItems: queryItems, handler: handler)
} }
public class func delete<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func patch(path: String, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PATCH, queryItems: queryItems, body: body, handler: handler)
}
public class func patch<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PATCH, queryItems: queryItems, body: body, handler: handler)
}
public class func patch<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PATCH, queryItems: queryItems, body: body, handler: handler)
}
public class func patch(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .PATCH, queryItems: queryItems, handler: handler)
}
public class func delete(path: String, body: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, body: body, handler: handler)
} }
public class func delete<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func delete<T: Encodable>(path: String, body: T, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, body: body, handler: handler) return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, body: body, handler: handler)
} }
public class func delete(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: HTTPURLResponse?, _ error: Error?) -> ()) -> URLSessionDataTask? { public class func delete<T: Encodable>(path: String, body: [T], queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, body: body, handler: handler)
}
public class func delete(path: String, queryItems: [URLQueryItem]? = nil, handler: @escaping (_ response: NetworkResponse, _ error: Error?) -> ()) -> URLSessionDataTask? {
return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, handler: handler) return SLazeKit.networkTask(path: path, method: .DELETE, queryItems: queryItems, handler: handler)
} }
} }

View File

@ -2,13 +2,7 @@ import Foundation
import SLazeKit import SLazeKit
import CoreData import CoreData
//First we gonna create NSManagedObject object on which we will work. class Model: NSManagedObject {
/// We assume you have Model as an NSManagedObject
class Model: NSManagedObject {}
// MARK: - Simulate extension for CoreData
extension Model {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Model> { @nonobjc public class func fetchRequest() -> NSFetchRequest<Model> {
return NSFetchRequest<Model>(entityName: "Model") return NSFetchRequest<Model>(entityName: "Model")
} }
@ -16,11 +10,7 @@ extension Model {
@NSManaged public var id: String @NSManaged public var id: String
@NSManaged public var value: Double @NSManaged public var value: Double
@NSManaged public var name: String? @NSManaged public var name: String?
}
// MARK: - SLazeKit extension
extension Model {
/// Path pattern for our model API requests /// Path pattern for our model API requests
public struct PathPattern { public struct PathPattern {
static var model: String { return "/api/Models/:modelId" } static var model: String { return "/api/Models/:modelId" }
@ -53,7 +43,6 @@ extension Model {
object.name = name object.name = name
} }
} }
/// We could skip that and add `Encodable` to our ModelResponse. But to highlight it. We will create separate one for request purpose /// We could skip that and add `Encodable` to our ModelResponse. But to highlight it. We will create separate one for request purpose
public struct ModelRequest: Encodable { public struct ModelRequest: Encodable {
var id: String var id: String
@ -66,9 +55,6 @@ extension Model {
self.name = model.name self.name = model.name
} }
} }
}
extension Model {
/// Create request. Called from SLazeKit. Response is not maped or serialized. /// Create request. Called from SLazeKit. Response is not maped or serialized.
/// ///
/// - Parameters: /// - Parameters:
@ -77,7 +63,7 @@ extension Model {
/// SLazeKit request are done i background. To handle response on main thread we need to dispatch it. /// SLazeKit request are done i background. To handle response on main thread we need to dispatch it.
let _ = SLazeKit.post(path: PathPattern.create.patternToPath(with: ["modelId":model.id]), body: ModelRequest(with: model)) { (response, error) in let _ = SLazeKit.post(path: PathPattern.create.patternToPath(with: ["modelId":model.id]), body: ModelRequest(with: model)) { (response, error) in
guard error == nil else { guard error == nil else {
DispatchQueue.main.async { failure?(response?.statusCode ?? -1,error) } DispatchQueue.main.async { failure?(response.urlResponse?.statusCode ?? -1,error) }
return return
} }
DispatchQueue.main.async { success() } DispatchQueue.main.async { success() }
@ -87,19 +73,24 @@ extension Model {
/// ///
/// - Parameters: /// - Parameters:
/// - modelId: model id used to replace key string in path pattern. /// - modelId: model id used to replace key string in path pattern.
///
/// SLazeKit request are done i background. To handle response on main thread we need to dispatch it.
class func remove(for modelId: String, success: @escaping (() ->()), failure: ((_ statusCode: Int, _ error: Error?) ->())? = nil) { class func remove(for modelId: String, success: @escaping (() ->()), failure: ((_ statusCode: Int, _ error: Error?) ->())? = nil) {
/// SLazeKit request are done i background. To handle response on main thread we need to dispatch it.
let _ = SLazeKit.delete(path: PathPattern.delete.patternToPath(with: ["modelId":modelId])) { (response, error) in let _ = SLazeKit.delete(path: PathPattern.delete.patternToPath(with: ["modelId":modelId])) { (response, error) in
guard error == nil else { guard error == nil else {
DispatchQueue.main.async { failure?(response?.statusCode ?? -1,error) } DispatchQueue.main.async { failure?(response.urlResponse?.statusCode ?? -1,error) }
return return
} }
DispatchQueue.main.async { success() } DispatchQueue.main.async { success() }
} }
} }
/// `[ModelResponse]` Stands as a result type. Decodable provides generic requests. if Response model beside `Decodable` comforms to `EntityMapping` as well it will be serialized. /// `[ModelResponse]` Stands as a result type. Decodable provides generic requests. if Response model beside `Decodable` comforms to `EntityMapping` as well it will be serialized.
///
/// [ModelResponse] Decodable type used to generate result type.
///
///Result is type of `[ModelResponse]` to return array of our CoreData models we need to serialize it.
///`result?.serialized` will return `[Model]`
class func getFromServer(success: @escaping (([Model]?) ->()), failure: (() ->())? = nil) { class func getFromServer(success: @escaping (([Model]?) ->()), failure: (() ->())? = nil) {
/// [ModelResponse] Decodable type used to generate result type.
let _ = [ModelResponse].get(path: PathPattern.models.patternToPath()) { (response, result, error) in let _ = [ModelResponse].get(path: PathPattern.models.patternToPath()) { (response, result, error) in
guard error == nil else { guard error == nil else {
failure?() failure?()
@ -107,18 +98,19 @@ extension Model {
} }
var models: [Model]? = nil var models: [Model]? = nil
do { do {
//Result is type of `[ModelResponse]` to return array of our CoreData models we need to serialize it. models = try result?.serialized(SLazeKit.newBackgroundContext())
//result?.serialized will return `[Model]`
models = try result?.serialized(ModelResponse.persistentContainer?.newBackgroundContext())
} catch { } catch {
print(error) print(error)
} }
success(models) success(models)
} }
} }
/// In this example API request will decode single object of type ModelResponse instead of an array.
///
///Result of type `ModelResponse` to return CoreData model we need to serialize it.
///
///`result?.serialized` will return `Model`
class func getFromServer(for modelId: String, success: @escaping ((Model?) ->()), failure: (() ->())? = nil) { class func getFromServer(for modelId: String, success: @escaping ((Model?) ->()), failure: (() ->())? = nil) {
/// in this example API request will decode single object of type ModelResponse instead of an array.
let _ = ModelResponse.get(path: PathPattern.model.patternToPath(with: ["modelId":modelId])) { (response, result, error) in let _ = ModelResponse.get(path: PathPattern.model.patternToPath(with: ["modelId":modelId])) { (response, result, error) in
guard error == nil else { guard error == nil else {
failure?() failure?()
@ -126,9 +118,7 @@ extension Model {
} }
var models: Model? = nil var models: Model? = nil
do { do {
//Result of type `ModelResponse` to return CoreData model we need to serialize it. models = try result?.serialized(SLazeKit.newBackgroundContext())
//result?.serialized will return `Model`
models = try result?.serialized(ModelResponse.persistentContainer?.newBackgroundContext())
} catch { } catch {
print(error) print(error)
} }

View File

@ -0,0 +1,55 @@
import Foundation
import SLazeKit
import CoreData
class Object: NSManagedObject {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Object> {
return NSFetchRequest<Object>(entityName: "Object")
}
@NSManaged public var id: String
@NSManaged public var value: Double
@NSManaged public var name: String?
/// Path pattern for our model API requests
public struct PathPattern {
static var model: String { return "/api/Objects/:modelId" }
static var models: String { return "/api/Objects" }
static var create: String { return "/api/Objects/:modelId/create" }
static var delete: String { return "/api/Objects/:modelId/delete" }
}
/// We are creating struct which represents Codable object of our API request
/// `EntityMappingCodable` is required
public struct ObjectRestful: EntityMappingCodable {
var id: String
var value: Double
var name: String?
/// We need provide NSManagedObject type for our serialization.
public static var entityType: NSManagedObject.Type {
return Object.self
}
/// By providing id attributes our model are updated/created/serialized
public var idAttributes: [EntityAttribute]? {
return [
("id",id)
]
}
/// init ObjectRestful with our Object clss
///
/// - Parameter model: model of our Object class
init(with model: Object) {
self.id = model.id
self.value = model.value
self.name = model.name
}
/// Fill CoreData object with our model response
public func fillObject(with model: NSManagedObject) {
guard let object = model as? Object else { return }
object.id = id
object.value = value
object.name = name
}
}
}