├── .gitignore ├── .travis.yml ├── AbstractionKit-macOS ├── AbstractionKit_macOS.h └── Info.plist ├── AbstractionKit.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── AbstractionKit-macOS.xcscheme │ ├── AbstractionKit.xcscheme │ └── AbstractionKitTests.xcscheme ├── AbstractionKit ├── AbstractionKit.h ├── EndpointDefinition.swift ├── Environment.swift ├── Errors.swift ├── HTTPMethod.swift ├── Info.plist ├── ResponseDefinition.swift └── ResponseElement.swift ├── AbstractionKitSample ├── APIKitBridgeRequest.swift ├── Abstraction.swift ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Endpoint.swift ├── Forecast.swift ├── Info.plist └── ViewController.swift ├── AbstractionKitTests ├── AbstractionKitTests.swift ├── Dictionary+decode.swift ├── Endpoints.swift ├── Info.plist └── Models.swift ├── Cartfile.private ├── Cartfile.resolved ├── Documentation └── How_to_define_response.md ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/xcode,carthage,swift,objective-c,osx 3 | 4 | ### Xcode ### 5 | # Xcode 6 | # 7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 8 | 9 | ## Build generated 10 | build/ 11 | DerivedData/ 12 | 13 | ## Various settings 14 | *.pbxuser 15 | !default.pbxuser 16 | *.mode1v3 17 | !default.mode1v3 18 | *.mode2v3 19 | !default.mode2v3 20 | *.perspectivev3 21 | !default.perspectivev3 22 | xcuserdata/ 23 | 24 | ## Other 25 | *.moved-aside 26 | *.xccheckout 27 | *.xcscmblueprint 28 | 29 | 30 | ### Carthage ### 31 | # Carthage - A simple, decentralized dependency manager for Cocoa 32 | Carthage/Checkouts 33 | Carthage/Build 34 | 35 | ### Swift ### 36 | # Xcode 37 | # 38 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 39 | 40 | ## Obj-C/Swift specific 41 | *.hmap 42 | *.ipa 43 | *.dSYM.zip 44 | *.dSYM 45 | 46 | ## Playgrounds 47 | timeline.xctimeline 48 | playground.xcworkspace 49 | 50 | # Swift Package Manager 51 | # 52 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 53 | # Packages/ 54 | .build/ 55 | 56 | # CocoaPods 57 | # 58 | # We recommend against adding the Pods directory to your .gitignore. However 59 | # you should judge for yourself, the pros and cons are mentioned at: 60 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 61 | # 62 | # Pods/ 63 | 64 | # fastlane 65 | # 66 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 67 | # screenshots whenever they are needed. 68 | # For more information about the recommended setup visit: 69 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 70 | 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | 76 | #Code Injection 77 | # 78 | # After new code Injection tools there's a generated folder /iOSInjectionProject 79 | # https://github.com/johnno1962/injectionforxcode 80 | 81 | iOSInjectionProject/ 82 | 83 | ### Objective-C Patch ### 84 | *.xcscmblueprint 85 | 86 | 87 | ### OSX ### 88 | *.DS_Store 89 | .AppleDouble 90 | .LSOverride 91 | 92 | # Icon must end with two \r 93 | Icon 94 | 95 | 96 | # Thumbnails 97 | ._* 98 | 99 | # Files that might appear in the root of a volume 100 | .DocumentRevisions-V100 101 | .fseventsd 102 | .Spotlight-V100 103 | .TemporaryItems 104 | .Trashes 105 | .VolumeIcon.icns 106 | .com.apple.timemachine.donotpresent 107 | 108 | # Directories potentially created on remote AFP share 109 | .AppleDB 110 | .AppleDesktop 111 | Network Trash Folder 112 | Temporary Items 113 | .apdisk 114 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | matrix: 2 | include: 3 | - os: osx 4 | language: objective-c 5 | osx_image: xcode8.3 6 | script: 7 | - set -o pipefail 8 | - xcodebuild -scheme AbstractionKitTests -configuration Debug test -destination 'name=iPhone 7' | xcpretty -c -------------------------------------------------------------------------------- /AbstractionKit-macOS/AbstractionKit_macOS.h: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractionKit_macOS.h 3 | // AbstractionKit-macOS 4 | // 5 | // Created by Yuya Hirayama on 2017/10/18. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for AbstractionKit_macOS. 12 | FOUNDATION_EXPORT double AbstractionKit_macOSVersionNumber; 13 | 14 | //! Project version string for AbstractionKit_macOS. 15 | FOUNDATION_EXPORT const unsigned char AbstractionKit_macOSVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /AbstractionKit-macOS/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 | NSHumanReadableCopyright 22 | Copyright © 2017年 Yuya Hirayama. All rights reserved. 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AbstractionKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6020A25F1F96FE5300D09209 /* AbstractionKit_macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 6020A25D1F96FE5300D09209 /* AbstractionKit_macOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 6020A2631F96FE7500D09209 /* EndpointDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D631F76B12900CC9991 /* EndpointDefinition.swift */; }; 12 | 6020A2641F96FE7500D09209 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D6B1F76B3A200CC9991 /* HTTPMethod.swift */; }; 13 | 6020A2651F96FE7500D09209 /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D691F76B37400CC9991 /* Environment.swift */; }; 14 | 6020A2661F96FE7500D09209 /* ResponseDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D651F76B21D00CC9991 /* ResponseDefinition.swift */; }; 15 | 6020A2671F96FE7500D09209 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D6D1F76B87000CC9991 /* Errors.swift */; }; 16 | 6020A2681F96FE7500D09209 /* ResponseElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D671F76B29900CC9991 /* ResponseElement.swift */; }; 17 | 60374D531F76AE7300CC9991 /* AbstractionKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60374D491F76AE7300CC9991 /* AbstractionKit.framework */; }; 18 | 60374D581F76AE7300CC9991 /* AbstractionKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D571F76AE7300CC9991 /* AbstractionKitTests.swift */; }; 19 | 60374D5A1F76AE7300CC9991 /* AbstractionKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 60374D4C1F76AE7300CC9991 /* AbstractionKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 20 | 60374D641F76B12900CC9991 /* EndpointDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D631F76B12900CC9991 /* EndpointDefinition.swift */; }; 21 | 60374D661F76B21D00CC9991 /* ResponseDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D651F76B21D00CC9991 /* ResponseDefinition.swift */; }; 22 | 60374D681F76B29900CC9991 /* ResponseElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D671F76B29900CC9991 /* ResponseElement.swift */; }; 23 | 60374D6A1F76B37400CC9991 /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D691F76B37400CC9991 /* Environment.swift */; }; 24 | 60374D6C1F76B3A200CC9991 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D6B1F76B3A200CC9991 /* HTTPMethod.swift */; }; 25 | 60374D6E1F76B87000CC9991 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D6D1F76B87000CC9991 /* Errors.swift */; }; 26 | 60374D761F76B9E400CC9991 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D751F76B9E400CC9991 /* AppDelegate.swift */; }; 27 | 60374D781F76B9E400CC9991 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D771F76B9E400CC9991 /* ViewController.swift */; }; 28 | 60374D7B1F76B9E400CC9991 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 60374D791F76B9E400CC9991 /* Main.storyboard */; }; 29 | 60374D7D1F76B9E400CC9991 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 60374D7C1F76B9E400CC9991 /* Assets.xcassets */; }; 30 | 60374D801F76B9E400CC9991 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 60374D7E1F76B9E400CC9991 /* LaunchScreen.storyboard */; }; 31 | 60374D861F76BA0C00CC9991 /* Abstraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D851F76BA0C00CC9991 /* Abstraction.swift */; }; 32 | 60374D891F76BA2A00CC9991 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D881F76BA2A00CC9991 /* Endpoint.swift */; }; 33 | 60374D911F76C3AD00CC9991 /* APIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60374D8C1F76C3AD00CC9991 /* APIKit.framework */; }; 34 | 60374D921F76C3AD00CC9991 /* Himotoki.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60374D8D1F76C3AD00CC9991 /* Himotoki.framework */; }; 35 | 60374D931F76C3AD00CC9991 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60374D8E1F76C3AD00CC9991 /* Result.framework */; }; 36 | 60374D941F76C3AD00CC9991 /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60374D8F1F76C3AD00CC9991 /* RxCocoa.framework */; }; 37 | 60374D951F76C3AD00CC9991 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60374D901F76C3AD00CC9991 /* RxSwift.framework */; }; 38 | 60374D9A1F76C4A000CC9991 /* APIKitBridgeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D991F76C4A000CC9991 /* APIKitBridgeRequest.swift */; }; 39 | 60374D9C1F76C67300CC9991 /* Forecast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60374D9B1F76C67300CC9991 /* Forecast.swift */; }; 40 | 60873F0E1F776DDD00489857 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60873F0D1F776DDD00489857 /* Models.swift */; }; 41 | 60873F121F776F5E00489857 /* Endpoints.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60873F111F776F5E00489857 /* Endpoints.swift */; }; 42 | 60873F151F77739300489857 /* Dictionary+decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60873F141F77739300489857 /* Dictionary+decode.swift */; }; 43 | /* End PBXBuildFile section */ 44 | 45 | /* Begin PBXContainerItemProxy section */ 46 | 60374D541F76AE7300CC9991 /* PBXContainerItemProxy */ = { 47 | isa = PBXContainerItemProxy; 48 | containerPortal = 60374D401F76AE7300CC9991 /* Project object */; 49 | proxyType = 1; 50 | remoteGlobalIDString = 60374D481F76AE7300CC9991; 51 | remoteInfo = AbstractionKit; 52 | }; 53 | 60374D8A1F76BCE000CC9991 /* PBXContainerItemProxy */ = { 54 | isa = PBXContainerItemProxy; 55 | containerPortal = 60374D401F76AE7300CC9991 /* Project object */; 56 | proxyType = 1; 57 | remoteGlobalIDString = 60374D481F76AE7300CC9991; 58 | remoteInfo = AbstractionKit; 59 | }; 60 | /* End PBXContainerItemProxy section */ 61 | 62 | /* Begin PBXFileReference section */ 63 | 6020A25B1F96FE5300D09209 /* AbstractionKit_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AbstractionKit_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | 6020A25D1F96FE5300D09209 /* AbstractionKit_macOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AbstractionKit_macOS.h; sourceTree = ""; }; 65 | 6020A25E1F96FE5300D09209 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 66 | 60374D491F76AE7300CC9991 /* AbstractionKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AbstractionKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 67 | 60374D4C1F76AE7300CC9991 /* AbstractionKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AbstractionKit.h; sourceTree = ""; }; 68 | 60374D4D1F76AE7300CC9991 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69 | 60374D521F76AE7300CC9991 /* AbstractionKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AbstractionKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | 60374D571F76AE7300CC9991 /* AbstractionKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbstractionKitTests.swift; sourceTree = ""; }; 71 | 60374D591F76AE7300CC9991 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 72 | 60374D631F76B12900CC9991 /* EndpointDefinition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EndpointDefinition.swift; sourceTree = ""; }; 73 | 60374D651F76B21D00CC9991 /* ResponseDefinition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponseDefinition.swift; sourceTree = ""; }; 74 | 60374D671F76B29900CC9991 /* ResponseElement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponseElement.swift; sourceTree = ""; }; 75 | 60374D691F76B37400CC9991 /* Environment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = ""; }; 76 | 60374D6B1F76B3A200CC9991 /* HTTPMethod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPMethod.swift; sourceTree = ""; }; 77 | 60374D6D1F76B87000CC9991 /* Errors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = ""; }; 78 | 60374D731F76B9E400CC9991 /* AbstractionKitSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AbstractionKitSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 79 | 60374D751F76B9E400CC9991 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 80 | 60374D771F76B9E400CC9991 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 81 | 60374D7A1F76B9E400CC9991 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 82 | 60374D7C1F76B9E400CC9991 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 83 | 60374D7F1F76B9E400CC9991 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 84 | 60374D811F76B9E400CC9991 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 85 | 60374D851F76BA0C00CC9991 /* Abstraction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Abstraction.swift; sourceTree = ""; }; 86 | 60374D881F76BA2A00CC9991 /* Endpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = ""; }; 87 | 60374D8C1F76C3AD00CC9991 /* APIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = APIKit.framework; path = Carthage/Build/iOS/APIKit.framework; sourceTree = SOURCE_ROOT; }; 88 | 60374D8D1F76C3AD00CC9991 /* Himotoki.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Himotoki.framework; path = Carthage/Build/iOS/Himotoki.framework; sourceTree = SOURCE_ROOT; }; 89 | 60374D8E1F76C3AD00CC9991 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = SOURCE_ROOT; }; 90 | 60374D8F1F76C3AD00CC9991 /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxCocoa.framework; path = Carthage/Build/iOS/RxCocoa.framework; sourceTree = SOURCE_ROOT; }; 91 | 60374D901F76C3AD00CC9991 /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/iOS/RxSwift.framework; sourceTree = SOURCE_ROOT; }; 92 | 60374D991F76C4A000CC9991 /* APIKitBridgeRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIKitBridgeRequest.swift; sourceTree = ""; }; 93 | 60374D9B1F76C67300CC9991 /* Forecast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Forecast.swift; sourceTree = ""; }; 94 | 60873F0D1F776DDD00489857 /* Models.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = ""; }; 95 | 60873F111F776F5E00489857 /* Endpoints.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Endpoints.swift; sourceTree = ""; }; 96 | 60873F141F77739300489857 /* Dictionary+decode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dictionary+decode.swift"; sourceTree = ""; }; 97 | /* End PBXFileReference section */ 98 | 99 | /* Begin PBXFrameworksBuildPhase section */ 100 | 6020A2571F96FE5300D09209 /* Frameworks */ = { 101 | isa = PBXFrameworksBuildPhase; 102 | buildActionMask = 2147483647; 103 | files = ( 104 | ); 105 | runOnlyForDeploymentPostprocessing = 0; 106 | }; 107 | 60374D451F76AE7300CC9991 /* Frameworks */ = { 108 | isa = PBXFrameworksBuildPhase; 109 | buildActionMask = 2147483647; 110 | files = ( 111 | ); 112 | runOnlyForDeploymentPostprocessing = 0; 113 | }; 114 | 60374D4F1F76AE7300CC9991 /* Frameworks */ = { 115 | isa = PBXFrameworksBuildPhase; 116 | buildActionMask = 2147483647; 117 | files = ( 118 | 60374D531F76AE7300CC9991 /* AbstractionKit.framework in Frameworks */, 119 | ); 120 | runOnlyForDeploymentPostprocessing = 0; 121 | }; 122 | 60374D701F76B9E400CC9991 /* Frameworks */ = { 123 | isa = PBXFrameworksBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | 60374D951F76C3AD00CC9991 /* RxSwift.framework in Frameworks */, 127 | 60374D941F76C3AD00CC9991 /* RxCocoa.framework in Frameworks */, 128 | 60374D931F76C3AD00CC9991 /* Result.framework in Frameworks */, 129 | 60374D921F76C3AD00CC9991 /* Himotoki.framework in Frameworks */, 130 | 60374D911F76C3AD00CC9991 /* APIKit.framework in Frameworks */, 131 | ); 132 | runOnlyForDeploymentPostprocessing = 0; 133 | }; 134 | /* End PBXFrameworksBuildPhase section */ 135 | 136 | /* Begin PBXGroup section */ 137 | 6020A25C1F96FE5300D09209 /* AbstractionKit-macOS */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 6020A25D1F96FE5300D09209 /* AbstractionKit_macOS.h */, 141 | 6020A25E1F96FE5300D09209 /* Info.plist */, 142 | ); 143 | path = "AbstractionKit-macOS"; 144 | sourceTree = ""; 145 | }; 146 | 60374D3F1F76AE7300CC9991 = { 147 | isa = PBXGroup; 148 | children = ( 149 | 60374D4B1F76AE7300CC9991 /* AbstractionKit */, 150 | 60374D561F76AE7300CC9991 /* AbstractionKitTests */, 151 | 60374D741F76B9E400CC9991 /* AbstractionKitSample */, 152 | 6020A25C1F96FE5300D09209 /* AbstractionKit-macOS */, 153 | 60374D4A1F76AE7300CC9991 /* Products */, 154 | 60873F0F1F776E2E00489857 /* PrivateDependencies */, 155 | ); 156 | sourceTree = ""; 157 | }; 158 | 60374D4A1F76AE7300CC9991 /* Products */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | 60374D491F76AE7300CC9991 /* AbstractionKit.framework */, 162 | 60374D521F76AE7300CC9991 /* AbstractionKitTests.xctest */, 163 | 60374D731F76B9E400CC9991 /* AbstractionKitSample.app */, 164 | 6020A25B1F96FE5300D09209 /* AbstractionKit_macOS.framework */, 165 | ); 166 | name = Products; 167 | sourceTree = ""; 168 | }; 169 | 60374D4B1F76AE7300CC9991 /* AbstractionKit */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | 60374D4C1F76AE7300CC9991 /* AbstractionKit.h */, 173 | 60374D631F76B12900CC9991 /* EndpointDefinition.swift */, 174 | 60374D6B1F76B3A200CC9991 /* HTTPMethod.swift */, 175 | 60374D691F76B37400CC9991 /* Environment.swift */, 176 | 60374D651F76B21D00CC9991 /* ResponseDefinition.swift */, 177 | 60374D6D1F76B87000CC9991 /* Errors.swift */, 178 | 60374D671F76B29900CC9991 /* ResponseElement.swift */, 179 | 60374D4D1F76AE7300CC9991 /* Info.plist */, 180 | ); 181 | path = AbstractionKit; 182 | sourceTree = ""; 183 | }; 184 | 60374D561F76AE7300CC9991 /* AbstractionKitTests */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | 60374D571F76AE7300CC9991 /* AbstractionKitTests.swift */, 188 | 60873F111F776F5E00489857 /* Endpoints.swift */, 189 | 60873F0D1F776DDD00489857 /* Models.swift */, 190 | 60873F141F77739300489857 /* Dictionary+decode.swift */, 191 | 60374D591F76AE7300CC9991 /* Info.plist */, 192 | ); 193 | path = AbstractionKitTests; 194 | sourceTree = ""; 195 | }; 196 | 60374D741F76B9E400CC9991 /* AbstractionKitSample */ = { 197 | isa = PBXGroup; 198 | children = ( 199 | 60374D871F76BA1300CC9991 /* Abstraction */, 200 | 60374D751F76B9E400CC9991 /* AppDelegate.swift */, 201 | 60374D771F76B9E400CC9991 /* ViewController.swift */, 202 | 60374D791F76B9E400CC9991 /* Main.storyboard */, 203 | 60374D7C1F76B9E400CC9991 /* Assets.xcassets */, 204 | 60374D7E1F76B9E400CC9991 /* LaunchScreen.storyboard */, 205 | 60374D811F76B9E400CC9991 /* Info.plist */, 206 | ); 207 | path = AbstractionKitSample; 208 | sourceTree = ""; 209 | }; 210 | 60374D871F76BA1300CC9991 /* Abstraction */ = { 211 | isa = PBXGroup; 212 | children = ( 213 | 60374D851F76BA0C00CC9991 /* Abstraction.swift */, 214 | 60374D9B1F76C67300CC9991 /* Forecast.swift */, 215 | 60374D991F76C4A000CC9991 /* APIKitBridgeRequest.swift */, 216 | 60374D881F76BA2A00CC9991 /* Endpoint.swift */, 217 | ); 218 | name = Abstraction; 219 | sourceTree = ""; 220 | }; 221 | 60873F0F1F776E2E00489857 /* PrivateDependencies */ = { 222 | isa = PBXGroup; 223 | children = ( 224 | 60374D8C1F76C3AD00CC9991 /* APIKit.framework */, 225 | 60374D8D1F76C3AD00CC9991 /* Himotoki.framework */, 226 | 60374D8E1F76C3AD00CC9991 /* Result.framework */, 227 | 60374D8F1F76C3AD00CC9991 /* RxCocoa.framework */, 228 | 60374D901F76C3AD00CC9991 /* RxSwift.framework */, 229 | ); 230 | name = PrivateDependencies; 231 | sourceTree = ""; 232 | }; 233 | /* End PBXGroup section */ 234 | 235 | /* Begin PBXHeadersBuildPhase section */ 236 | 6020A2581F96FE5300D09209 /* Headers */ = { 237 | isa = PBXHeadersBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | 6020A25F1F96FE5300D09209 /* AbstractionKit_macOS.h in Headers */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | 60374D461F76AE7300CC9991 /* Headers */ = { 245 | isa = PBXHeadersBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | 60374D5A1F76AE7300CC9991 /* AbstractionKit.h in Headers */, 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | }; 252 | /* End PBXHeadersBuildPhase section */ 253 | 254 | /* Begin PBXNativeTarget section */ 255 | 6020A25A1F96FE5300D09209 /* AbstractionKit-macOS */ = { 256 | isa = PBXNativeTarget; 257 | buildConfigurationList = 6020A2621F96FE5300D09209 /* Build configuration list for PBXNativeTarget "AbstractionKit-macOS" */; 258 | buildPhases = ( 259 | 6020A2561F96FE5300D09209 /* Sources */, 260 | 6020A2571F96FE5300D09209 /* Frameworks */, 261 | 6020A2581F96FE5300D09209 /* Headers */, 262 | 6020A2591F96FE5300D09209 /* Resources */, 263 | ); 264 | buildRules = ( 265 | ); 266 | dependencies = ( 267 | ); 268 | name = "AbstractionKit-macOS"; 269 | productName = "AbstractionKit-macOS"; 270 | productReference = 6020A25B1F96FE5300D09209 /* AbstractionKit_macOS.framework */; 271 | productType = "com.apple.product-type.framework"; 272 | }; 273 | 60374D481F76AE7300CC9991 /* AbstractionKit */ = { 274 | isa = PBXNativeTarget; 275 | buildConfigurationList = 60374D5D1F76AE7300CC9991 /* Build configuration list for PBXNativeTarget "AbstractionKit" */; 276 | buildPhases = ( 277 | 60374D441F76AE7300CC9991 /* Sources */, 278 | 60374D451F76AE7300CC9991 /* Frameworks */, 279 | 60374D461F76AE7300CC9991 /* Headers */, 280 | 60374D471F76AE7300CC9991 /* Resources */, 281 | ); 282 | buildRules = ( 283 | ); 284 | dependencies = ( 285 | ); 286 | name = AbstractionKit; 287 | productName = AbstractionKit; 288 | productReference = 60374D491F76AE7300CC9991 /* AbstractionKit.framework */; 289 | productType = "com.apple.product-type.framework"; 290 | }; 291 | 60374D511F76AE7300CC9991 /* AbstractionKitTests */ = { 292 | isa = PBXNativeTarget; 293 | buildConfigurationList = 60374D601F76AE7300CC9991 /* Build configuration list for PBXNativeTarget "AbstractionKitTests" */; 294 | buildPhases = ( 295 | 60374D4E1F76AE7300CC9991 /* Sources */, 296 | 60374D4F1F76AE7300CC9991 /* Frameworks */, 297 | 60374D501F76AE7300CC9991 /* Resources */, 298 | ); 299 | buildRules = ( 300 | ); 301 | dependencies = ( 302 | 60374D551F76AE7300CC9991 /* PBXTargetDependency */, 303 | ); 304 | name = AbstractionKitTests; 305 | productName = AbstractionKitTests; 306 | productReference = 60374D521F76AE7300CC9991 /* AbstractionKitTests.xctest */; 307 | productType = "com.apple.product-type.bundle.unit-test"; 308 | }; 309 | 60374D721F76B9E400CC9991 /* AbstractionKitSample */ = { 310 | isa = PBXNativeTarget; 311 | buildConfigurationList = 60374D821F76B9E400CC9991 /* Build configuration list for PBXNativeTarget "AbstractionKitSample" */; 312 | buildPhases = ( 313 | 60374D6F1F76B9E400CC9991 /* Sources */, 314 | 60374D701F76B9E400CC9991 /* Frameworks */, 315 | 60374D711F76B9E400CC9991 /* Resources */, 316 | 60374D961F76C3BC00CC9991 /* Carthage */, 317 | ); 318 | buildRules = ( 319 | ); 320 | dependencies = ( 321 | 60374D8B1F76BCE000CC9991 /* PBXTargetDependency */, 322 | ); 323 | name = AbstractionKitSample; 324 | productName = AbstractionKitSample; 325 | productReference = 60374D731F76B9E400CC9991 /* AbstractionKitSample.app */; 326 | productType = "com.apple.product-type.application"; 327 | }; 328 | /* End PBXNativeTarget section */ 329 | 330 | /* Begin PBXProject section */ 331 | 60374D401F76AE7300CC9991 /* Project object */ = { 332 | isa = PBXProject; 333 | attributes = { 334 | LastSwiftUpdateCheck = 0830; 335 | LastUpgradeCheck = 0830; 336 | ORGANIZATIONNAME = "Yuya Hirayama"; 337 | TargetAttributes = { 338 | 6020A25A1F96FE5300D09209 = { 339 | CreatedOnToolsVersion = 9.0; 340 | DevelopmentTeam = Q3N95Y73WF; 341 | ProvisioningStyle = Automatic; 342 | }; 343 | 60374D481F76AE7300CC9991 = { 344 | CreatedOnToolsVersion = 8.3.3; 345 | DevelopmentTeam = Q3N95Y73WF; 346 | LastSwiftMigration = 0830; 347 | ProvisioningStyle = Automatic; 348 | }; 349 | 60374D511F76AE7300CC9991 = { 350 | CreatedOnToolsVersion = 8.3.3; 351 | DevelopmentTeam = Q3N95Y73WF; 352 | ProvisioningStyle = Automatic; 353 | }; 354 | 60374D721F76B9E400CC9991 = { 355 | CreatedOnToolsVersion = 8.3.3; 356 | DevelopmentTeam = Q3N95Y73WF; 357 | ProvisioningStyle = Automatic; 358 | }; 359 | }; 360 | }; 361 | buildConfigurationList = 60374D431F76AE7300CC9991 /* Build configuration list for PBXProject "AbstractionKit" */; 362 | compatibilityVersion = "Xcode 3.2"; 363 | developmentRegion = English; 364 | hasScannedForEncodings = 0; 365 | knownRegions = ( 366 | en, 367 | Base, 368 | ); 369 | mainGroup = 60374D3F1F76AE7300CC9991; 370 | productRefGroup = 60374D4A1F76AE7300CC9991 /* Products */; 371 | projectDirPath = ""; 372 | projectRoot = ""; 373 | targets = ( 374 | 60374D481F76AE7300CC9991 /* AbstractionKit */, 375 | 60374D511F76AE7300CC9991 /* AbstractionKitTests */, 376 | 60374D721F76B9E400CC9991 /* AbstractionKitSample */, 377 | 6020A25A1F96FE5300D09209 /* AbstractionKit-macOS */, 378 | ); 379 | }; 380 | /* End PBXProject section */ 381 | 382 | /* Begin PBXResourcesBuildPhase section */ 383 | 6020A2591F96FE5300D09209 /* Resources */ = { 384 | isa = PBXResourcesBuildPhase; 385 | buildActionMask = 2147483647; 386 | files = ( 387 | ); 388 | runOnlyForDeploymentPostprocessing = 0; 389 | }; 390 | 60374D471F76AE7300CC9991 /* Resources */ = { 391 | isa = PBXResourcesBuildPhase; 392 | buildActionMask = 2147483647; 393 | files = ( 394 | ); 395 | runOnlyForDeploymentPostprocessing = 0; 396 | }; 397 | 60374D501F76AE7300CC9991 /* Resources */ = { 398 | isa = PBXResourcesBuildPhase; 399 | buildActionMask = 2147483647; 400 | files = ( 401 | ); 402 | runOnlyForDeploymentPostprocessing = 0; 403 | }; 404 | 60374D711F76B9E400CC9991 /* Resources */ = { 405 | isa = PBXResourcesBuildPhase; 406 | buildActionMask = 2147483647; 407 | files = ( 408 | 60374D801F76B9E400CC9991 /* LaunchScreen.storyboard in Resources */, 409 | 60374D7D1F76B9E400CC9991 /* Assets.xcassets in Resources */, 410 | 60374D7B1F76B9E400CC9991 /* Main.storyboard in Resources */, 411 | ); 412 | runOnlyForDeploymentPostprocessing = 0; 413 | }; 414 | /* End PBXResourcesBuildPhase section */ 415 | 416 | /* Begin PBXShellScriptBuildPhase section */ 417 | 60374D961F76C3BC00CC9991 /* Carthage */ = { 418 | isa = PBXShellScriptBuildPhase; 419 | buildActionMask = 2147483647; 420 | files = ( 421 | ); 422 | inputPaths = ( 423 | "$(SRCROOT)/Carthage/Build/iOS/RxSwift.framework", 424 | "$(SRCROOT)/Carthage/Build/iOS/RxCocoa.framework", 425 | "$(SRCROOT)/Carthage/Build/iOS/Himotoki.framework", 426 | "$(SRCROOT)/Carthage/Build/iOS/APIKit.framework", 427 | "$(SRCROOT)/Carthage/Build/iOS/Result.framework", 428 | ); 429 | name = Carthage; 430 | outputPaths = ( 431 | ); 432 | runOnlyForDeploymentPostprocessing = 0; 433 | shellPath = /bin/sh; 434 | shellScript = "carthage copy-frameworks\n"; 435 | }; 436 | /* End PBXShellScriptBuildPhase section */ 437 | 438 | /* Begin PBXSourcesBuildPhase section */ 439 | 6020A2561F96FE5300D09209 /* Sources */ = { 440 | isa = PBXSourcesBuildPhase; 441 | buildActionMask = 2147483647; 442 | files = ( 443 | 6020A2641F96FE7500D09209 /* HTTPMethod.swift in Sources */, 444 | 6020A2671F96FE7500D09209 /* Errors.swift in Sources */, 445 | 6020A2651F96FE7500D09209 /* Environment.swift in Sources */, 446 | 6020A2681F96FE7500D09209 /* ResponseElement.swift in Sources */, 447 | 6020A2631F96FE7500D09209 /* EndpointDefinition.swift in Sources */, 448 | 6020A2661F96FE7500D09209 /* ResponseDefinition.swift in Sources */, 449 | ); 450 | runOnlyForDeploymentPostprocessing = 0; 451 | }; 452 | 60374D441F76AE7300CC9991 /* Sources */ = { 453 | isa = PBXSourcesBuildPhase; 454 | buildActionMask = 2147483647; 455 | files = ( 456 | 60374D681F76B29900CC9991 /* ResponseElement.swift in Sources */, 457 | 60374D6A1F76B37400CC9991 /* Environment.swift in Sources */, 458 | 60374D641F76B12900CC9991 /* EndpointDefinition.swift in Sources */, 459 | 60374D6C1F76B3A200CC9991 /* HTTPMethod.swift in Sources */, 460 | 60374D6E1F76B87000CC9991 /* Errors.swift in Sources */, 461 | 60374D661F76B21D00CC9991 /* ResponseDefinition.swift in Sources */, 462 | ); 463 | runOnlyForDeploymentPostprocessing = 0; 464 | }; 465 | 60374D4E1F76AE7300CC9991 /* Sources */ = { 466 | isa = PBXSourcesBuildPhase; 467 | buildActionMask = 2147483647; 468 | files = ( 469 | 60374D581F76AE7300CC9991 /* AbstractionKitTests.swift in Sources */, 470 | 60873F121F776F5E00489857 /* Endpoints.swift in Sources */, 471 | 60873F0E1F776DDD00489857 /* Models.swift in Sources */, 472 | 60873F151F77739300489857 /* Dictionary+decode.swift in Sources */, 473 | ); 474 | runOnlyForDeploymentPostprocessing = 0; 475 | }; 476 | 60374D6F1F76B9E400CC9991 /* Sources */ = { 477 | isa = PBXSourcesBuildPhase; 478 | buildActionMask = 2147483647; 479 | files = ( 480 | 60374D9A1F76C4A000CC9991 /* APIKitBridgeRequest.swift in Sources */, 481 | 60374D781F76B9E400CC9991 /* ViewController.swift in Sources */, 482 | 60374D761F76B9E400CC9991 /* AppDelegate.swift in Sources */, 483 | 60374D891F76BA2A00CC9991 /* Endpoint.swift in Sources */, 484 | 60374D9C1F76C67300CC9991 /* Forecast.swift in Sources */, 485 | 60374D861F76BA0C00CC9991 /* Abstraction.swift in Sources */, 486 | ); 487 | runOnlyForDeploymentPostprocessing = 0; 488 | }; 489 | /* End PBXSourcesBuildPhase section */ 490 | 491 | /* Begin PBXTargetDependency section */ 492 | 60374D551F76AE7300CC9991 /* PBXTargetDependency */ = { 493 | isa = PBXTargetDependency; 494 | target = 60374D481F76AE7300CC9991 /* AbstractionKit */; 495 | targetProxy = 60374D541F76AE7300CC9991 /* PBXContainerItemProxy */; 496 | }; 497 | 60374D8B1F76BCE000CC9991 /* PBXTargetDependency */ = { 498 | isa = PBXTargetDependency; 499 | target = 60374D481F76AE7300CC9991 /* AbstractionKit */; 500 | targetProxy = 60374D8A1F76BCE000CC9991 /* PBXContainerItemProxy */; 501 | }; 502 | /* End PBXTargetDependency section */ 503 | 504 | /* Begin PBXVariantGroup section */ 505 | 60374D791F76B9E400CC9991 /* Main.storyboard */ = { 506 | isa = PBXVariantGroup; 507 | children = ( 508 | 60374D7A1F76B9E400CC9991 /* Base */, 509 | ); 510 | name = Main.storyboard; 511 | sourceTree = ""; 512 | }; 513 | 60374D7E1F76B9E400CC9991 /* LaunchScreen.storyboard */ = { 514 | isa = PBXVariantGroup; 515 | children = ( 516 | 60374D7F1F76B9E400CC9991 /* Base */, 517 | ); 518 | name = LaunchScreen.storyboard; 519 | sourceTree = ""; 520 | }; 521 | /* End PBXVariantGroup section */ 522 | 523 | /* Begin XCBuildConfiguration section */ 524 | 6020A2601F96FE5300D09209 /* Debug */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 528 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 529 | CLANG_WARN_COMMA = YES; 530 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 531 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 532 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 533 | CLANG_WARN_STRICT_PROTOTYPES = YES; 534 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 535 | CODE_SIGN_IDENTITY = "Mac Developer"; 536 | CODE_SIGN_STYLE = Automatic; 537 | COMBINE_HIDPI_IMAGES = YES; 538 | DEFINES_MODULE = YES; 539 | DEVELOPMENT_TEAM = Q3N95Y73WF; 540 | DYLIB_COMPATIBILITY_VERSION = 1; 541 | DYLIB_CURRENT_VERSION = 1; 542 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 543 | FRAMEWORK_VERSION = A; 544 | GCC_C_LANGUAGE_STANDARD = gnu11; 545 | INFOPLIST_FILE = "AbstractionKit-macOS/Info.plist"; 546 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 547 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 548 | MACOSX_DEPLOYMENT_TARGET = 10.12; 549 | PRODUCT_BUNDLE_IDENTIFIER = "me.yura.AbstractionKit-macOS"; 550 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 551 | SDKROOT = macosx; 552 | SKIP_INSTALL = YES; 553 | SWIFT_VERSION = 4.0; 554 | }; 555 | name = Debug; 556 | }; 557 | 6020A2611F96FE5300D09209 /* Release */ = { 558 | isa = XCBuildConfiguration; 559 | buildSettings = { 560 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 561 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 562 | CLANG_WARN_COMMA = YES; 563 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 564 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 565 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 566 | CLANG_WARN_STRICT_PROTOTYPES = YES; 567 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 568 | CODE_SIGN_IDENTITY = "Mac Developer"; 569 | CODE_SIGN_STYLE = Automatic; 570 | COMBINE_HIDPI_IMAGES = YES; 571 | DEFINES_MODULE = YES; 572 | DEVELOPMENT_TEAM = Q3N95Y73WF; 573 | DYLIB_COMPATIBILITY_VERSION = 1; 574 | DYLIB_CURRENT_VERSION = 1; 575 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 576 | FRAMEWORK_VERSION = A; 577 | GCC_C_LANGUAGE_STANDARD = gnu11; 578 | INFOPLIST_FILE = "AbstractionKit-macOS/Info.plist"; 579 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 580 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 581 | MACOSX_DEPLOYMENT_TARGET = 10.12; 582 | PRODUCT_BUNDLE_IDENTIFIER = "me.yura.AbstractionKit-macOS"; 583 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 584 | SDKROOT = macosx; 585 | SKIP_INSTALL = YES; 586 | SWIFT_VERSION = 4.0; 587 | }; 588 | name = Release; 589 | }; 590 | 60374D5B1F76AE7300CC9991 /* Debug */ = { 591 | isa = XCBuildConfiguration; 592 | buildSettings = { 593 | ALWAYS_SEARCH_USER_PATHS = NO; 594 | CLANG_ANALYZER_NONNULL = YES; 595 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 596 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 597 | CLANG_CXX_LIBRARY = "libc++"; 598 | CLANG_ENABLE_MODULES = YES; 599 | CLANG_ENABLE_OBJC_ARC = YES; 600 | CLANG_WARN_BOOL_CONVERSION = YES; 601 | CLANG_WARN_CONSTANT_CONVERSION = YES; 602 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 603 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 604 | CLANG_WARN_EMPTY_BODY = YES; 605 | CLANG_WARN_ENUM_CONVERSION = YES; 606 | CLANG_WARN_INFINITE_RECURSION = YES; 607 | CLANG_WARN_INT_CONVERSION = YES; 608 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 609 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 610 | CLANG_WARN_UNREACHABLE_CODE = YES; 611 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 612 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 613 | COPY_PHASE_STRIP = NO; 614 | CURRENT_PROJECT_VERSION = 1; 615 | DEBUG_INFORMATION_FORMAT = dwarf; 616 | ENABLE_STRICT_OBJC_MSGSEND = YES; 617 | ENABLE_TESTABILITY = YES; 618 | GCC_C_LANGUAGE_STANDARD = gnu99; 619 | GCC_DYNAMIC_NO_PIC = NO; 620 | GCC_NO_COMMON_BLOCKS = YES; 621 | GCC_OPTIMIZATION_LEVEL = 0; 622 | GCC_PREPROCESSOR_DEFINITIONS = ( 623 | "DEBUG=1", 624 | "$(inherited)", 625 | ); 626 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 627 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 628 | GCC_WARN_UNDECLARED_SELECTOR = YES; 629 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 630 | GCC_WARN_UNUSED_FUNCTION = YES; 631 | GCC_WARN_UNUSED_VARIABLE = YES; 632 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 633 | MTL_ENABLE_DEBUG_INFO = YES; 634 | ONLY_ACTIVE_ARCH = YES; 635 | SDKROOT = iphoneos; 636 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 637 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 638 | TARGETED_DEVICE_FAMILY = "1,2"; 639 | VERSIONING_SYSTEM = "apple-generic"; 640 | VERSION_INFO_PREFIX = ""; 641 | }; 642 | name = Debug; 643 | }; 644 | 60374D5C1F76AE7300CC9991 /* Release */ = { 645 | isa = XCBuildConfiguration; 646 | buildSettings = { 647 | ALWAYS_SEARCH_USER_PATHS = NO; 648 | CLANG_ANALYZER_NONNULL = YES; 649 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 650 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 651 | CLANG_CXX_LIBRARY = "libc++"; 652 | CLANG_ENABLE_MODULES = YES; 653 | CLANG_ENABLE_OBJC_ARC = YES; 654 | CLANG_WARN_BOOL_CONVERSION = YES; 655 | CLANG_WARN_CONSTANT_CONVERSION = YES; 656 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 657 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 658 | CLANG_WARN_EMPTY_BODY = YES; 659 | CLANG_WARN_ENUM_CONVERSION = YES; 660 | CLANG_WARN_INFINITE_RECURSION = YES; 661 | CLANG_WARN_INT_CONVERSION = YES; 662 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 663 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 664 | CLANG_WARN_UNREACHABLE_CODE = YES; 665 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 666 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 667 | COPY_PHASE_STRIP = NO; 668 | CURRENT_PROJECT_VERSION = 1; 669 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 670 | ENABLE_NS_ASSERTIONS = NO; 671 | ENABLE_STRICT_OBJC_MSGSEND = YES; 672 | GCC_C_LANGUAGE_STANDARD = gnu99; 673 | GCC_NO_COMMON_BLOCKS = YES; 674 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 675 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 676 | GCC_WARN_UNDECLARED_SELECTOR = YES; 677 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 678 | GCC_WARN_UNUSED_FUNCTION = YES; 679 | GCC_WARN_UNUSED_VARIABLE = YES; 680 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 681 | MTL_ENABLE_DEBUG_INFO = NO; 682 | SDKROOT = iphoneos; 683 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 684 | TARGETED_DEVICE_FAMILY = "1,2"; 685 | VALIDATE_PRODUCT = YES; 686 | VERSIONING_SYSTEM = "apple-generic"; 687 | VERSION_INFO_PREFIX = ""; 688 | }; 689 | name = Release; 690 | }; 691 | 60374D5E1F76AE7300CC9991 /* Debug */ = { 692 | isa = XCBuildConfiguration; 693 | buildSettings = { 694 | CLANG_ENABLE_MODULES = YES; 695 | CODE_SIGN_IDENTITY = ""; 696 | DEFINES_MODULE = YES; 697 | DEVELOPMENT_TEAM = Q3N95Y73WF; 698 | DYLIB_COMPATIBILITY_VERSION = 1; 699 | DYLIB_CURRENT_VERSION = 1; 700 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 701 | INFOPLIST_FILE = AbstractionKit/Info.plist; 702 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 703 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 704 | PRODUCT_BUNDLE_IDENTIFIER = me.yura.AbstractionKit; 705 | PRODUCT_NAME = "$(TARGET_NAME)"; 706 | SKIP_INSTALL = YES; 707 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 708 | SWIFT_VERSION = 3.0; 709 | }; 710 | name = Debug; 711 | }; 712 | 60374D5F1F76AE7300CC9991 /* Release */ = { 713 | isa = XCBuildConfiguration; 714 | buildSettings = { 715 | CLANG_ENABLE_MODULES = YES; 716 | CODE_SIGN_IDENTITY = ""; 717 | DEFINES_MODULE = YES; 718 | DEVELOPMENT_TEAM = Q3N95Y73WF; 719 | DYLIB_COMPATIBILITY_VERSION = 1; 720 | DYLIB_CURRENT_VERSION = 1; 721 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 722 | INFOPLIST_FILE = AbstractionKit/Info.plist; 723 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 724 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 725 | PRODUCT_BUNDLE_IDENTIFIER = me.yura.AbstractionKit; 726 | PRODUCT_NAME = "$(TARGET_NAME)"; 727 | SKIP_INSTALL = YES; 728 | SWIFT_VERSION = 3.0; 729 | }; 730 | name = Release; 731 | }; 732 | 60374D611F76AE7300CC9991 /* Debug */ = { 733 | isa = XCBuildConfiguration; 734 | buildSettings = { 735 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 736 | DEVELOPMENT_TEAM = Q3N95Y73WF; 737 | FRAMEWORK_SEARCH_PATHS = ( 738 | "$(inherited)", 739 | "$(PROJECT_DIR)/Carthage/Build/iOS", 740 | ); 741 | INFOPLIST_FILE = AbstractionKitTests/Info.plist; 742 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 743 | PRODUCT_BUNDLE_IDENTIFIER = me.yura.AbstractionKitTests; 744 | PRODUCT_NAME = "$(TARGET_NAME)"; 745 | SWIFT_VERSION = 3.0; 746 | }; 747 | name = Debug; 748 | }; 749 | 60374D621F76AE7300CC9991 /* Release */ = { 750 | isa = XCBuildConfiguration; 751 | buildSettings = { 752 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 753 | DEVELOPMENT_TEAM = Q3N95Y73WF; 754 | FRAMEWORK_SEARCH_PATHS = ( 755 | "$(inherited)", 756 | "$(PROJECT_DIR)/Carthage/Build/iOS", 757 | ); 758 | INFOPLIST_FILE = AbstractionKitTests/Info.plist; 759 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 760 | PRODUCT_BUNDLE_IDENTIFIER = me.yura.AbstractionKitTests; 761 | PRODUCT_NAME = "$(TARGET_NAME)"; 762 | SWIFT_VERSION = 3.0; 763 | }; 764 | name = Release; 765 | }; 766 | 60374D831F76B9E400CC9991 /* Debug */ = { 767 | isa = XCBuildConfiguration; 768 | buildSettings = { 769 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 770 | DEVELOPMENT_TEAM = Q3N95Y73WF; 771 | FRAMEWORK_SEARCH_PATHS = ( 772 | "$(inherited)", 773 | "$(PROJECT_DIR)/Carthage/Build/iOS", 774 | ); 775 | INFOPLIST_FILE = AbstractionKitSample/Info.plist; 776 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 777 | PRODUCT_BUNDLE_IDENTIFIER = me.yura.AbstractionKitSample; 778 | PRODUCT_NAME = "$(TARGET_NAME)"; 779 | SWIFT_VERSION = 3.0; 780 | }; 781 | name = Debug; 782 | }; 783 | 60374D841F76B9E400CC9991 /* Release */ = { 784 | isa = XCBuildConfiguration; 785 | buildSettings = { 786 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 787 | DEVELOPMENT_TEAM = Q3N95Y73WF; 788 | FRAMEWORK_SEARCH_PATHS = ( 789 | "$(inherited)", 790 | "$(PROJECT_DIR)/Carthage/Build/iOS", 791 | ); 792 | INFOPLIST_FILE = AbstractionKitSample/Info.plist; 793 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 794 | PRODUCT_BUNDLE_IDENTIFIER = me.yura.AbstractionKitSample; 795 | PRODUCT_NAME = "$(TARGET_NAME)"; 796 | SWIFT_VERSION = 3.0; 797 | }; 798 | name = Release; 799 | }; 800 | /* End XCBuildConfiguration section */ 801 | 802 | /* Begin XCConfigurationList section */ 803 | 6020A2621F96FE5300D09209 /* Build configuration list for PBXNativeTarget "AbstractionKit-macOS" */ = { 804 | isa = XCConfigurationList; 805 | buildConfigurations = ( 806 | 6020A2601F96FE5300D09209 /* Debug */, 807 | 6020A2611F96FE5300D09209 /* Release */, 808 | ); 809 | defaultConfigurationIsVisible = 0; 810 | defaultConfigurationName = Release; 811 | }; 812 | 60374D431F76AE7300CC9991 /* Build configuration list for PBXProject "AbstractionKit" */ = { 813 | isa = XCConfigurationList; 814 | buildConfigurations = ( 815 | 60374D5B1F76AE7300CC9991 /* Debug */, 816 | 60374D5C1F76AE7300CC9991 /* Release */, 817 | ); 818 | defaultConfigurationIsVisible = 0; 819 | defaultConfigurationName = Release; 820 | }; 821 | 60374D5D1F76AE7300CC9991 /* Build configuration list for PBXNativeTarget "AbstractionKit" */ = { 822 | isa = XCConfigurationList; 823 | buildConfigurations = ( 824 | 60374D5E1F76AE7300CC9991 /* Debug */, 825 | 60374D5F1F76AE7300CC9991 /* Release */, 826 | ); 827 | defaultConfigurationIsVisible = 0; 828 | defaultConfigurationName = Release; 829 | }; 830 | 60374D601F76AE7300CC9991 /* Build configuration list for PBXNativeTarget "AbstractionKitTests" */ = { 831 | isa = XCConfigurationList; 832 | buildConfigurations = ( 833 | 60374D611F76AE7300CC9991 /* Debug */, 834 | 60374D621F76AE7300CC9991 /* Release */, 835 | ); 836 | defaultConfigurationIsVisible = 0; 837 | defaultConfigurationName = Release; 838 | }; 839 | 60374D821F76B9E400CC9991 /* Build configuration list for PBXNativeTarget "AbstractionKitSample" */ = { 840 | isa = XCConfigurationList; 841 | buildConfigurations = ( 842 | 60374D831F76B9E400CC9991 /* Debug */, 843 | 60374D841F76B9E400CC9991 /* Release */, 844 | ); 845 | defaultConfigurationIsVisible = 0; 846 | defaultConfigurationName = Release; 847 | }; 848 | /* End XCConfigurationList section */ 849 | }; 850 | rootObject = 60374D401F76AE7300CC9991 /* Project object */; 851 | } 852 | -------------------------------------------------------------------------------- /AbstractionKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AbstractionKit.xcodeproj/xcshareddata/xcschemes/AbstractionKit-macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /AbstractionKit.xcodeproj/xcshareddata/xcschemes/AbstractionKit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /AbstractionKit.xcodeproj/xcshareddata/xcschemes/AbstractionKitTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | 48 | 49 | 51 | 52 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /AbstractionKit/AbstractionKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractionKit.h 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for AbstractionKit. 12 | FOUNDATION_EXPORT double AbstractionKitVersionNumber; 13 | 14 | //! Project version string for AbstractionKit. 15 | FOUNDATION_EXPORT const unsigned char AbstractionKitVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /AbstractionKit/EndpointDefinition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EndpointDefinition.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol EndpointDefinition { 12 | associatedtype Response: ResponseDefinition 13 | associatedtype Environment: EnvironmentDefinition 14 | 15 | var path: String { get } 16 | static var environment: Environment { get } 17 | 18 | var parameters: [String: Any] { get } 19 | var header: [String: String] { get } 20 | var method: HTTPMethod { get } 21 | } 22 | 23 | public extension EndpointDefinition { 24 | var header: [String: String] { 25 | return [:] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AbstractionKit/Environment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Environment.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol EnvironmentDefinition { 12 | var baseURLStr: String { get } 13 | var commonHeader: [String: String] { get } 14 | 15 | func url(forPath: String) -> URL 16 | } 17 | 18 | public extension EnvironmentDefinition { 19 | func url(forPath path: String) -> URL { 20 | return URL.init(string: baseURLStr + path)! 21 | } 22 | 23 | var commonHeader: [String: String] { 24 | return [:] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AbstractionKit/Errors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Errors.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum CombinedResponseError: Error { 12 | case keyNotFound(key: String) 13 | } 14 | -------------------------------------------------------------------------------- /AbstractionKit/HTTPMethod.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPMethod.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum HTTPMethod { 12 | case get 13 | case post 14 | case delete 15 | case patch 16 | } 17 | -------------------------------------------------------------------------------- /AbstractionKit/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /AbstractionKit/ResponseDefinition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResponseDefinition.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ResponseDefinition { 12 | associatedtype Result 13 | associatedtype JSON 14 | 15 | var result: Result { get } 16 | 17 | init(json: JSON) throws 18 | } 19 | 20 | public protocol DataResponseDefinition: ResponseDefinition { 21 | static var jsonKey: String { get } 22 | } 23 | 24 | public struct SingleResponse: DataResponseDefinition { 25 | public typealias Result = T 26 | public typealias JSON = [String: Any] 27 | 28 | public let result: Result 29 | 30 | public static var jsonKey: String { 31 | return T.singleKey 32 | } 33 | 34 | public init(json: JSON) throws { 35 | result = try T.decode(from: json) 36 | } 37 | } 38 | 39 | public struct ArrayResponse: DataResponseDefinition { 40 | public typealias Result = [T] 41 | public typealias JSON = [[String: Any]] 42 | 43 | public let result: Result 44 | 45 | public static var jsonKey: String { 46 | return T.pluralKey 47 | } 48 | 49 | public init(json: JSON) throws { 50 | result = try T.decode(from: json) 51 | } 52 | } 53 | 54 | public struct EmptyResponse: ResponseDefinition { 55 | public typealias Result = Void 56 | public typealias JSON = Any? 57 | 58 | public let result: Result 59 | 60 | public init(json: JSON) throws { 61 | result = () 62 | } 63 | } 64 | 65 | public struct CombinedResponse: ResponseDefinition { 66 | public typealias Result = (T1.Result, T2.Result) 67 | public typealias JSON = [String: Any] 68 | 69 | public let result: Result 70 | 71 | public init(json: [String : Any]) throws { 72 | guard let t1JSON = json[T1.jsonKey] as? T1.JSON else { 73 | throw CombinedResponseError.keyNotFound(key: T1.jsonKey) 74 | } 75 | let t1 = try T1.init(json: t1JSON) 76 | 77 | guard let t2JSON = json[T2.jsonKey] as? T2.JSON else { 78 | throw CombinedResponseError.keyNotFound(key: T2.jsonKey) 79 | } 80 | let t2 = try T2.init(json: t2JSON) 81 | 82 | result = (t1.result, t2.result) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /AbstractionKit/ResponseElement.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResponseElement.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ResponseElement { 12 | } 13 | 14 | public protocol SingleResponseElement: ResponseElement { 15 | static var singleKey: String { get } 16 | static func decode(from: Any) throws -> Self 17 | } 18 | 19 | public protocol ArrayResponseElement: ResponseElement { 20 | static var pluralKey: String { get } 21 | static func decode(from: Any) throws -> [Self] 22 | } 23 | -------------------------------------------------------------------------------- /AbstractionKitSample/APIKitBridgeRequest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // APIKitBridgeRequest.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import APIKit 11 | import AbstractionKit 12 | 13 | /// Bridges network process between AbstractionKit and APIKit. 14 | struct APIKitBridgeRequest: APIKit.Request { 15 | typealias Response = Endpoint.Response.Result 16 | var baseURL: URL = Endpoint.environment.url(forPath: "") 17 | 18 | var path: String { 19 | return endpoint.path 20 | } 21 | 22 | var parameters: Any? { 23 | return endpoint.parameters 24 | } 25 | 26 | var method: APIKit.HTTPMethod { 27 | return endpoint.method.apiKitMethod 28 | } 29 | 30 | var headerFields: [String: String] { 31 | return Endpoint.environment.commonHeader.merging(endpoint.header, uniquingKeysWith: { $1 }) 32 | } 33 | 34 | private let endpoint: Endpoint 35 | 36 | init(endpoint: Endpoint) { 37 | self.endpoint = endpoint 38 | } 39 | 40 | func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Endpoint.Response.Result { 41 | guard let jsonObj = object as? Endpoint.Response.JSON else { 42 | fatalError() 43 | } 44 | return try Endpoint.Response.init(json: jsonObj).result 45 | } 46 | } 47 | 48 | extension AbstractionKit.HTTPMethod { 49 | var apiKitMethod: APIKit.HTTPMethod { 50 | switch self { 51 | case .get: 52 | return .get 53 | case .post: 54 | return .post 55 | case .delete: 56 | return .delete 57 | case .patch: 58 | return .patch 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /AbstractionKitSample/Abstraction.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Abstraction.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AbstractionKit 11 | import APIKit 12 | import RxSwift 13 | 14 | /// Abstraction layer for forecast API 15 | struct Abstraction { 16 | 17 | // - MARK: Internal methods 18 | 19 | /// Creates observable that emits objects API returned. 20 | /// 21 | /// - Parameter endpoint: Endpoint to perform request. 22 | /// - Returns: Single observable that emits objects API returned. 23 | fileprivate static func request(_ endpoint: Endpoint) -> Single { 24 | return Single.create(subscribe: { (observer) -> Disposable in 25 | let request = APIKitBridgeRequest.init(endpoint: endpoint) 26 | let task = Session.send(request, callbackQueue: nil, handler: { (result) in 27 | switch result { 28 | case .success(let response): 29 | observer(.success(response)) 30 | case .failure(let error): 31 | observer(.error(error)) 32 | } 33 | }) 34 | 35 | return Disposables.create { 36 | task?.cancel() 37 | } 38 | }) 39 | } 40 | } 41 | 42 | // - MARK: Public methods for higher layers. 43 | 44 | extension Abstraction { 45 | /// Get forecast information for city. 46 | /// 47 | /// - Parameters: 48 | /// - cityName: The name of city 49 | /// - countryCode: Country code 50 | /// - Returns: Single observable that emits Forecast object list. 51 | static func forecast(cityName: String, countryCode: String) -> Single<[Forecast]> { 52 | let endpoint = Endpoint.GetForecast.init(cityName: cityName, countryCode: countryCode) 53 | return request(endpoint) 54 | } 55 | } 56 | 57 | // - MARK: Server environment definition. 58 | 59 | struct Environment: EnvironmentDefinition { 60 | var baseURLStr: String = "http://samples.openweathermap.org/data/2.5" 61 | 62 | var commonHeader: [String : String] { 63 | return ["Custom-Common-Header": "CommonValue"] 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /AbstractionKitSample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AbstractionKitSample 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /AbstractionKitSample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /AbstractionKitSample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /AbstractionKitSample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /AbstractionKitSample/Endpoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Endpoint.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AbstractionKit 11 | 12 | struct Endpoint { 13 | struct GetForecast: EndpointDefinition { 14 | typealias Response = ListKeyResponse> 15 | var path: String = "/forecast" 16 | static var environment: Environment = .init() 17 | let parameters: [String: Any] 18 | var method: HTTPMethod = .get 19 | 20 | var header: [String : String] { 21 | return ["Endpoint-Specific-Header": "Hello"] 22 | } 23 | 24 | init(cityName: String, countryCode: String) { 25 | parameters = [ 26 | "q": "\(cityName),\(countryCode)", 27 | "appid": "_" 28 | ] 29 | } 30 | } 31 | } 32 | 33 | struct ListKeyResponse: DataResponseDefinition { 34 | typealias Result = T.Result 35 | typealias JSON = [String: Any] 36 | 37 | var result: Result 38 | 39 | static var jsonKey: String { 40 | return "list" 41 | } 42 | 43 | init(json: JSON) throws { 44 | guard let tJSON = json[ListKeyResponse.jsonKey] as? T.JSON else { 45 | throw CombinedResponseError.keyNotFound(key: ListKeyResponse.jsonKey) 46 | } 47 | result = try T.init(json: tJSON).result 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AbstractionKitSample/Forecast.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Forecast.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AbstractionKit 11 | import Himotoki 12 | 13 | struct Forecast: ArrayResponseElement, Himotoki.Decodable { 14 | static var pluralKey = "forecasts" 15 | 16 | var date: Date 17 | var temperature: Double // Kelvin 18 | 19 | static func decode(_ e: Extractor) throws -> Forecast { 20 | 21 | return try Forecast.init( 22 | date: Date.init(timeIntervalSince1970: e <| "dt"), 23 | temperature: e <| ["main", "temp"] 24 | ) 25 | } 26 | 27 | static func decode(from json: Any) throws -> [Forecast] { 28 | return try decodeArray(json) 29 | } 30 | } 31 | 32 | extension Forecast { 33 | var dateStr: String { 34 | let formatter = DateFormatter.init() 35 | formatter.dateStyle = .short 36 | formatter.timeStyle = .short 37 | 38 | return formatter.string(from: date) 39 | } 40 | 41 | var temperatureInFahrenheit: Double { 42 | return temperature * 9 / 5 - 459.67 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AbstractionKitSample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppTransportSecurity 6 | 7 | NSAllowsArbitraryLoads 8 | 9 | 10 | CFBundleDevelopmentRegion 11 | en 12 | CFBundleExecutable 13 | $(EXECUTABLE_NAME) 14 | CFBundleIdentifier 15 | $(PRODUCT_BUNDLE_IDENTIFIER) 16 | CFBundleInfoDictionaryVersion 17 | 6.0 18 | CFBundleName 19 | $(PRODUCT_NAME) 20 | CFBundlePackageType 21 | APPL 22 | CFBundleShortVersionString 23 | 1.0 24 | CFBundleVersion 25 | 1 26 | LSRequiresIPhoneOS 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIMainStoryboardFile 31 | Main 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /AbstractionKitSample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // AbstractionKitSample 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RxSwift 11 | import RxCocoa 12 | import AbstractionKit 13 | 14 | class ViewController: UIViewController { 15 | 16 | @IBOutlet private weak var tableView: UITableView! { 17 | didSet { 18 | let identifier = "cell" 19 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: identifier) 20 | forecasts.asObservable() 21 | .flatMap { Observable.from(optional: $0) } 22 | .bind(to: tableView.rx.items(cellIdentifier: identifier, cellType: UITableViewCell.self)) { row, element, cell in 23 | cell.textLabel?.text = "\(element.dateStr): \(Int(element.temperatureInFahrenheit))°F" 24 | } 25 | .disposed(by: bag) 26 | } 27 | } 28 | 29 | private let forecasts = Variable<[Forecast]?>.init(nil) 30 | 31 | private let bag = DisposeBag.init() 32 | 33 | override func viewDidLoad() { 34 | super.viewDidLoad() 35 | 36 | Abstraction.forecast(cityName: "München", countryCode: "DE") 37 | .asObservable() 38 | .bind(to: forecasts) 39 | .disposed(by: bag) 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /AbstractionKitTests/AbstractionKitTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractionKitTests.swift 3 | // AbstractionKitTests 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AbstractionKit 11 | 12 | class AbstractionKitTests: XCTestCase { 13 | func test_SingleResponse_success() { 14 | let dict: [String: Any] = [ 15 | "id": 100, 16 | "name": "George", 17 | ] 18 | 19 | do { 20 | _ = try GetUser.Response.init(json: dict).result 21 | } catch let error { 22 | XCTFail("Unexpected error was thrown. \(error)") 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AbstractionKitTests/Dictionary+decode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Dictionary+decode.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Dictionary where Key == String { 12 | func getValue(forKey key: Key) throws -> T { 13 | guard let value = self[key] else { 14 | throw DictionaryExtractionError.keyNotFound(key) 15 | } 16 | guard let castedValue = value as? T else { 17 | throw DictionaryExtractionError.castFailed(key: key, expectedType: T.self, actualValue: value) 18 | } 19 | 20 | return castedValue 21 | } 22 | 23 | func getArray(forKey key: Key) throws -> [T] { 24 | guard let value = self[key] else { 25 | throw DictionaryExtractionError.keyNotFound(key) 26 | } 27 | guard let array = value as? [T] else { 28 | throw DictionaryExtractionError.castFailed(key: key, expectedType: [T].self, actualValue: value) 29 | } 30 | 31 | return array 32 | } 33 | 34 | func getURL(forKey key: Key) throws -> URL? { 35 | guard let value = self[key] else { 36 | return nil 37 | } 38 | guard let urlStr = value as? String else { 39 | throw DictionaryExtractionError.castFailed(key: key, expectedType: String.self, actualValue: value) 40 | } 41 | return URL.init(string: urlStr) 42 | } 43 | 44 | func getURL(forKey key: Key) throws -> URL { 45 | guard let url = try getURL(forKey: key) as URL? else { 46 | throw DictionaryExtractionError.convertToURLFailed(key: key, actualValue: self[key] as Any) 47 | } 48 | return url 49 | } 50 | } 51 | 52 | enum DictionaryExtractionError: Error { 53 | case keyNotFound(String) 54 | case castFailed(key: String, expectedType: Any.Type, actualValue: Any) 55 | case convertToURLFailed(key: String, actualValue: Any) 56 | } 57 | -------------------------------------------------------------------------------- /AbstractionKitTests/Endpoints.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Endpoints.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AbstractionKit 11 | 12 | struct GetUser: EndpointDefinition { 13 | typealias Response = SingleResponse 14 | 15 | var path = "/user" 16 | 17 | static var environment: Environment = .init() 18 | 19 | var parameters: [String : Any] = [:] 20 | 21 | var method: HTTPMethod = .get 22 | } 23 | 24 | struct Environment: EnvironmentDefinition { 25 | var baseURLStr: String = "https://example.com" 26 | } 27 | -------------------------------------------------------------------------------- /AbstractionKitTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /AbstractionKitTests/Models.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Models.swift 3 | // AbstractionKit 4 | // 5 | // Created by Yuya Hirayama on 2017/09/24. 6 | // Copyright © 2017年 Yuya Hirayama. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AbstractionKit 11 | 12 | struct User { 13 | var id: Int 14 | var name: String 15 | } 16 | 17 | extension User: SingleResponseElement { 18 | static var singleKey = "user" 19 | 20 | static func decode(from obj: Any) throws -> User { 21 | guard let json = obj as? [String: Any] else { 22 | throw DecodeError.castToJSONStructureFailed 23 | } 24 | 25 | return try User.init( 26 | id: json.getValue(forKey: "id"), 27 | name: json.getValue(forKey: "name") 28 | ) 29 | } 30 | } 31 | 32 | extension User: ArrayResponseElement { 33 | static var pluralKey = "users" 34 | 35 | static func decode(from obj: Any) throws -> [User] { 36 | guard let json = obj as? [[String: Any]] else { 37 | throw DecodeError.castToJSONStructureFailed 38 | } 39 | 40 | return try json.map { try User.decode(from: $0) } 41 | } 42 | } 43 | 44 | enum DecodeError: Error { 45 | case castToJSONStructureFailed 46 | } 47 | -------------------------------------------------------------------------------- /Cartfile.private: -------------------------------------------------------------------------------- 1 | github "ReactiveX/RxSwift" ~> 3.0.0 2 | github "ishkawa/APIKit" ~> 3.0.0 3 | github "ikesyo/Himotoki" ~> 3.0.0 4 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "ReactiveX/RxSwift" "3.6.1" 2 | github "antitypical/Result" "3.2.3" 3 | github "ikesyo/Himotoki" "3.1.0" 4 | github "ishkawa/APIKit" "3.1.2" 5 | -------------------------------------------------------------------------------- /Documentation/How_to_define_response.md: -------------------------------------------------------------------------------- 1 | # How to define response 2 | 3 | Let's consider the case of fetching information about user. 4 | 5 | ```swift 6 | struct GetUser: EndpointDefinition { 7 | typealias Response = ❓🤔 8 | 9 | static var environment: Environment = .init() 10 | static var path: String = "/user" 11 | 12 | var parameters: [String : Any] = [:] 13 | 14 | var method: HTTPMethod = .get 15 | } 16 | ``` 17 | 18 | AbstractionKit provides some structs that models JSON object. 19 | 20 | ### SingleResponse 21 | 22 | You can use `SingleResponse` if API returns single `User` object. 23 | 24 | ```json 25 | { 26 | "id": 100, 27 | "name": "George" 28 | } 29 | ``` 30 | 31 | ```swift 32 | // `user` will be User(id: 100, name: "George") 33 | let user = try GetUser.Response.init(json: json).result 34 | ``` 35 | 36 | ### ArrayResponse 37 | 38 | You can use `ArrayResponse` if API returns some `User` objects. 39 | 40 | ```json 41 | [ 42 | { 43 | "id": 100, 44 | "name": "George" 45 | }, 46 | { 47 | "id": 101, 48 | "name": "Mary" 49 | }, 50 | { 51 | "id": 102, 52 | "name": "Tom" 53 | } 54 | ] 55 | ``` 56 | 57 | ```swift 58 | // `users` will be [User(id: 100, name: "George"), User(id: 101, name: "Mary"), User(id: 102, name: "Tom")] 59 | let users = try GetUser.Response.init(json: json).result 60 | ``` 61 | 62 | ### EmptyResponse 63 | 64 | You can use `EmptyResponse` if you do not need to parse response JSON. (I assume to use this like when POST request does not return the new object.) 65 | 66 | ```json 67 | { 68 | "success": true, 69 | "message": "Successfully updated." 70 | } 71 | ``` 72 | 73 | ```swift 74 | // Returned value is `()`. 75 | try GetUser.Response.init(json: json).result 76 | ``` 77 | 78 | ### CombinedResponse 79 | 80 | You can use `CombinedResponse` when returned API is more complex. 81 | 82 | For example, when JSON contains array of `User` and single `School` object as follows, you can use `CombinedResponse, SingleResponse>`. 83 | 84 | ```json 85 | { 86 | "users": [ 87 | { 88 | "id": 100, 89 | "name": "George" 90 | }, 91 | { 92 | "id": 101, 93 | "name": "Mary" 94 | }, 95 | { 96 | "id": 102, 97 | "name": "Tom" 98 | } 99 | ], 100 | "school": { 101 | "id": 10000, 102 | "name": "Tokyo school", 103 | "number_of_students": 3 104 | } 105 | } 106 | ``` 107 | 108 | ```swift 109 | // Type of `result` will be `([User], School)`. 110 | let result = try GetUser.Response.init(json: json).result 111 | let users = result.0 // `[User]` 112 | let school = result.1 // `School` 113 | ``` 114 | 115 | In this case, `singleKey` in `SingleResponseElement` and `pluralKey` in `ArrayResponseElement` will be used as the JSON key. 116 | 117 | ### Defining custom structure 118 | 119 | I know that you cannot always correspond with your API on structs above. In such a case, you can define custom structure of JSON using AbstractionKit's protocols. 120 | 121 | For example, I assume that API returns JSON as follows, 122 | 123 | ```json 124 | { 125 | "info": { 126 | "success": true, 127 | "message": "Server is fine!", 128 | "timestamp": 1506195673 129 | }, 130 | "results": [ 131 | { 132 | "id": 100, 133 | "name": "George" 134 | }, 135 | { 136 | "id": 101, 137 | "name": "Mary" 138 | }, 139 | { 140 | "id": 102, 141 | "name": "Tom" 142 | } 143 | ] 144 | } 145 | ``` 146 | 147 | This case means, 148 | 149 | - You do not have to parse `"info"` object 150 | - You want to extract `User` objects but key is different from `User`'s `pluralKey`. 151 | 152 | You can define JSON structure as follows, 153 | 154 | ```swift 155 | struct ResultKeyResponse: DataResponseDefinition { 156 | typealias Result = T.Result 157 | typealias JSON = [String: Any] 158 | 159 | var result: Result 160 | 161 | static var jsonKey: String { 162 | return "results" 163 | } 164 | 165 | init(json: JSON) throws { 166 | guard let tJSON = json[ListKeyResponse.jsonKey] as? T.JSON else { 167 | throw CombinedResponseError.keyNotFound(key: ListKeyResponse.jsonKey) 168 | } 169 | result = try T.init(json: tJSON).result 170 | } 171 | } 172 | ``` 173 | 174 | Then you can extract `User` objects like this. 175 | 176 | ```swift 177 | // `users` will be [User(id: 100, name: "George"), User(id: 101, name: "Mary"), User(id: 102, name: "Tom")] 178 | let users = try GetUser.Response.init(json: json).result 179 | ``` 180 | 181 | `CombinedResponse` supports combination of two types, but if your API returns combination of three or more types, you can create `ThreeCombinedResponse` in the same way. -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2017 Yuya Hirayama 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AbstractionKit 2 | 3 | [![Build Status](https://travis-ci.org/hiragram/AbstractionKit.svg?branch=master)](https://travis-ci.org/hiragram/AbstractionKit) 4 | 5 | AbstractionKit provides various protocols and structs that make it easier to abstract json APIs. 6 | 7 | AbstractionKit does not depend on any other networking and mapping frameworks. So you can bridge between AbstractionKit and any frameworks you usually use. 8 | 9 | ## Overview 10 | 11 | Define your API endpoint as follows: 12 | 13 | ```swift 14 | struct GetUser: EndpointDefinition { 15 | /// Means this endpoint returns single User object. 16 | typealias Response = SingleResponse 17 | 18 | /// Path for resource. 19 | static var path: String = "/user" 20 | 21 | /// You can switch server for each endpoint. 22 | /// (You can use .staging or .mock if you defined.) 23 | static var environment: Environment = .production 24 | 25 | /// Parameters to contain in request. 26 | let parameters: [String: Any] 27 | 28 | /// HTTP method 29 | var method: HTTPMethod = .get 30 | 31 | init(userID: Int) { 32 | parameters = [ 33 | "id": userID 34 | ] 35 | } 36 | } 37 | ``` 38 | 39 | then simply extract objects from JSON like so: 40 | 41 | ```swift 42 | // `json` is a dictionary that API returned 43 | let user = try GetUser.Response.init(json: json).result 44 | ``` 45 | 46 | ## Sample app 47 | 48 | A sample that uses [APIKit](https://github.com/ishkawa/APIKit), [Himotoki](https://github.com/ikesyo/Himotoki), and [RxSwift](https://github.com/ReactiveX/RxSwift) is available. Clone and run `$ carthage update` then run `AbstractionKitSample`. 49 | 50 | ## Installation 51 | 52 | ### Requirements 53 | 54 | - Swift 4.0 55 | - Xcode 9.x 56 | 57 | ### Carthage 58 | 59 | - Add `github "hiragram/AbstractionKit" ~> 0.1` to your `Cartfile`. 60 | - Run `$ carthage update`. 61 | - Add built framework in `Carthage/Build/iOS/` to your project. 62 | - Append `AbstractionKit.framework` to arguments of `$ carthage copy-frameworks`. 63 | 64 | ## How to define response 65 | 66 | See: [How to define response](Documentation/How_to_define_response.md) 67 | 68 | ## How to bridge between AbstractionKit and networking frameworks 69 | 70 | Create a wrapper for the network framework. The wrapper transforms AbstractionKit's endpoint instance to network framework's request object and generate object from response JSON. 71 | 72 | For example, wrapper for APIKit is as follows, 73 | 74 | ```swift 75 | struct APIKitBridgeRequest: APIKit.Request { 76 | typealias Response = Endpoint.Response.Result 77 | var baseURL: URL = Endpoint.environment.url(forPath: "") 78 | 79 | var path = Endpoint.path 80 | 81 | var parameters: Any? { 82 | return endpoint.parameters 83 | } 84 | 85 | var method: APIKit.HTTPMethod { 86 | return endpoint.method.apiKitMethod 87 | } 88 | 89 | private let endpoint: Endpoint 90 | 91 | init(endpoint: Endpoint) { 92 | self.endpoint = endpoint 93 | } 94 | 95 | func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Endpoint.Response.Result { 96 | guard let jsonObj = object as? Endpoint.Response.JSON else { 97 | fatalError() 98 | } 99 | return try Endpoint.Response.init(json: jsonObj).result 100 | } 101 | } 102 | ``` 103 | 104 | This wrapper has AbstractionKit's endpoint definition as a generic type parameter, and conforms to `APIKit.Request` protocol. 105 | 106 | Then you create an instance of `APIKitBridgeRequest` and execute request. 107 | 108 | ```swift 109 | // `GetUser.Response` is `SingleResponse` 110 | let endpoint = GetUser.init(userID: 100) 111 | let request = APIKitBridgeRequest.init(endpoint: endpoint) 112 | Session.send(request, callbackQueue: nil, handler: { (result) in 113 | switch result { 114 | case .success(let user): 115 | print(user) 116 | case .failure(let error): 117 | print(error) 118 | } 119 | }) 120 | ``` 121 | 122 | ## How to bridge between AbstractionKit and mapping frameworks 123 | 124 | `SingleResponseElement` and `ArrayResponseElement` are available to define model object types. Each protocol constraints to implement `decode` method. You can use any mapping framework in the method as follows, 125 | 126 | ```swift 127 | struct User: SingleResponseElement, Himotoki.Decodable { 128 | static var singleKey = "user" 129 | 130 | var id: Int 131 | var name: String 132 | 133 | /// Implementation for Himotoki.Decodable 134 | static func decode(_ e: Extractor) throws -> User { 135 | return try User.init( 136 | id: e <| "id", 137 | name: e <| "name" 138 | ) 139 | } 140 | 141 | /// Implementation for AbstractionKit.SingleResponseElement 142 | static func decode(from json: Any) throws -> User { 143 | // Using Himotoki internally. 144 | return try decodeValue(json) 145 | } 146 | } 147 | ``` 148 | 149 | AbstractionKit does not depend on any mapping framework, so you can also map JSON to object manually. (Of course I will never recommend it.) 150 | 151 | ```swift 152 | struct User: SingleResponseElement { 153 | static var singleKey = "user" 154 | 155 | var id: Int 156 | var name: String 157 | 158 | /// Implementation for AbstractionKit.SingleResponseElement 159 | static func decode(from obj: Any) throws -> User { 160 | let json = obj as! [String: Any] 161 | 162 | return User.init( 163 | id: json["id"] as! Int, 164 | name: json["name"] as! String 165 | ) 166 | } 167 | } 168 | ``` 169 | 170 | ## How to create cool abstraction layer using AbstractionKit 171 | 172 | _work in progress_ 173 | --------------------------------------------------------------------------------