22// WebStruct.swift
33// WebStruct
44//
5- // Created by Arakane Ikumi on 2016/08/24.
5+ // Created by iq3 on 2016/08/24.
66// Copyright © 2016年 addli.co.jp. All rights reserved.
77//
88
99import Foundation
1010import Dispatch
1111
12+ /**
13+ WebStruct error type
14+ */
1215public indirect enum Error : Swift . Error {
1316 case network( Swift . Error )
1417 case http( Swift . Error )
@@ -17,58 +20,81 @@ public indirect enum Error : Swift.Error{
1720 case application( WebSerializable )
1821}
1922
23+ /**
24+ Json serializeable protocol
25+ */
2026public protocol WebSerializable {
27+ // Must implement
2128 init ( fromJson json: Any ) throws
2229}
2330
31+ /**
32+ Json deserializeable protocol
33+ */
2434public protocol WebDeserializable {
35+ // Must implement
2536 func toJsonData( ) -> Any
2637}
2738
39+ /**
40+ Json initializable protocol
41+ */
2842public protocol WebInitializable : WebSerializable {
2943 associatedtype inputType : WebDeserializable
3044 associatedtype errorType : WebSerializable
3145
46+ // Must implement
3247 static var path : String { get }
48+
49+ // Optional
50+ static var method : String { get }
51+ static var headers : [ String : String ] { get }
3352 static var timeout : TimeInterval { get }
3453 static var configuration : URLSessionConfiguration { get }
54+ static var urlsessionDelegate : URLSessionDelegate ? { get }
3555}
3656
57+ /**
58+ Default implement for WebInitializable
59+ */
3760extension WebInitializable {
3861 public init ( _ param: Self . inputType ) throws {
3962 self = try WebStruct < Self , Self . errorType > ( ) . get ( param )
4063 }
4164
4265 // default values
66+ static public var method : String { return " POST " }
67+ static public var headers : [ String : String ] { return [ : ] }
4368 static public var timeout : TimeInterval { return 5.0 }
4469 static public var configuration : URLSessionConfiguration { return URLSessionConfiguration . default }
70+ static public var urlsessionDelegate : URLSessionDelegate ? { return nil }
4571}
4672
73+ /**
74+ Default implement for WebInitializable
75+ */
4776fileprivate struct WebStruct < T: WebInitializable , ERR: WebSerializable > {
4877
4978 fileprivate init ( ) { }
5079
5180 fileprivate func get< P: WebDeserializable > ( _ param: P ) throws -> T {
5281
53- guard let url = URL ( string: T . path )
54- else { fatalError ( ) }
55-
56- guard let body = try ? JSONSerialization . data ( withJSONObject: param. toJsonData ( ) , options: JSONSerialization . WritingOptions ( ) )
57- else { fatalError ( ) }
82+ // verify for request
83+ guard let url = URL ( string: T . path ) else { fatalError ( ) }
84+ guard let body = try ? JSONSerialization . data ( withJSONObject: param. toJsonData ( ) , options: JSONSerialization . WritingOptions ( ) ) else { fatalError ( ) }
5885
86+ // setup for request
5987 var request = URLRequest ( url: url, cachePolicy: . reloadIgnoringLocalCacheData, timeoutInterval: T . timeout)
60- request. httpMethod = " POST "
88+ request. httpMethod = T . method
6189 request. addValue ( " application/json " , forHTTPHeaderField: " Content-Type " )
90+ for (key, value) in T . headers {
91+ request. addValue ( value, forHTTPHeaderField: key )
92+ }
6293 request. httpBody = body
6394
64- #if os(macOS) || os(iOS)
65- let session = URLSession ( configuration: T . configuration, delegate: URLSessionDelegateClass ( ) , delegateQueue: nil )
66- #else
67- let session = URLSession ( configuration: T . configuration, delegate: nil , delegateQueue: nil )
68- #endif
69-
95+ // send request
96+ let session = URLSession ( configuration: T . configuration, delegate: T . urlsessionDelegate, delegateQueue: nil )
7097 let semaphore = DispatchSemaphore ( value: 0 )
71-
7298 var data : Data ? , response : URLResponse ? , error : Swift . Error ?
7399 let subtask = session. dataTask ( with: request) { ( d, r, e) in
74100 data = d; response = r; error = e;
@@ -77,16 +103,19 @@ fileprivate struct WebStruct <T:WebInitializable,ERR:WebSerializable>{
77103 subtask. resume ( )
78104 let _ = semaphore. wait ( timeout: DispatchTime . distantFuture)
79105
106+ // verify for response
80107 if let error = error {
81108 throw Error . network ( error)
82109 }
83110
84111 if case let httpResponse as HTTPURLResponse = response{
85112 switch httpResponse. statusCode{
86113 case 200 ... 299 : break
87- default : throw Error . http ( NSError ( domain: " HTTPError " , code: httpResponse. statusCode, userInfo: nil ) )
114+ default : throw Error . http ( NSError ( domain: " HTTPError " , code: httpResponse. statusCode, userInfo: [ " description " : HTTPURLResponse . localizedString ( forStatusCode : httpResponse . statusCode ) ] ) )
88115 }
89116 }
117+
118+ // parse
90119 guard let someData = data,
91120 let jsonDic = try ? JSONSerialization . jsonObject ( with: someData, options: JSONSerialization . ReadingOptions ( ) )
92121 else { throw Error . ignoreData }
@@ -102,45 +131,9 @@ fileprivate struct WebStruct <T:WebInitializable,ERR:WebSerializable>{
102131 throw Error . application ( err)
103132 }
104133
134+ // complete
105135 return gen
106136 }
107137}
108138
109139
110- // Passed self certificate
111- #if os(macOS) || os(iOS)
112- fileprivate class URLSessionDelegateClass : NSObject , URLSessionDelegate {
113- func urlSession( _ session: URLSession , didReceive challenge: URLAuthenticationChallenge , completionHandler: @escaping ( URLSession . AuthChallengeDisposition , URLCredential ? ) -> Void ) {
114-
115-
116- var disposition : Foundation . URLSession . AuthChallengeDisposition = . performDefaultHandling
117- var credential : URLCredential ?
118-
119- if challenge. protectionSpace. authenticationMethod == NSURLAuthenticationMethodServerTrust {
120- disposition = . useCredential
121- credential = URLCredential ( trust: challenge. protectionSpace. serverTrust!)
122- } else {
123- if challenge. previousFailureCount > 0 {
124- disposition = . cancelAuthenticationChallenge
125- } else {
126- credential = session. configuration. urlCredentialStorage? . defaultCredential ( for: challenge. protectionSpace)
127-
128- if credential != nil {
129- disposition = . useCredential
130- }
131- }
132- }
133- completionHandler ( disposition, credential)
134- }
135- }
136-
137- #else
138-
139- extension URLRequest {
140- static func allowsAnyHTTPSCertificateForHost( host: String ) -> Bool {
141- return true
142- }
143- }
144-
145- #endif
146-
0 commit comments