Skip to content

Commit 697208a

Browse files
author
Todd Appleton
committed
Merge branch 'release/1.0.0'
2 parents c0987c6 + b6738ac commit 697208a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+10611
-1
lines changed

README.md

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,57 @@
1-
# ios-swift-sdk
1+
Address Book for iOS Swift
2+
==========================
3+
4+
This repo contains a sample address book application for iOS Swift that demonstrates how to use the DreamFactory REST API. It includes new user registration, user login, and CRUD for related tables.
5+
6+
#Getting DreamFactory on your local machine
7+
8+
To download and install DreamFactory, follow the instructions [here](http://wiki.dreamfactory.com/DreamFactory/Installation). Alternatively, you can create a [free hosted developer account](http://www.dreamfactory.com) at www.dreamfactory.com if you don't want to install DreamFactory locally.
9+
10+
#Configuring your DreamFactory instance to run the app
11+
12+
- Enable [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) for development purposes.
13+
- In the admin console, navigate to the Config tab and click on CORS in the left sidebar.
14+
- Click Add.
15+
- Set Origin, Paths, and Headers to *.
16+
- Set Max Age to 0.
17+
- Allow all HTTP verbs and check the Enabled box.
18+
- Click update when you are done.
19+
- More info on setting up CORS is available [here](http://wiki.dreamfactory.com/DreamFactory/Tutorials/Enabling_CORS_Access).
20+
21+
- Create a default role for new users and enable open registration
22+
- In the admin console, click the Roles tab then click Create in the left sidebar.
23+
- Enter a name for the role and check the Active box.
24+
- Go to the Access tab.
25+
- Add a new entry under Service Access (you can make it more restrictive later).
26+
- set Service = All
27+
- set Component = *
28+
- check all HTTP verbs under Access
29+
- set Requester = API
30+
- Click Create Role.
31+
- Click the Services tab, then edit the user service. Go to Config and enable Allow Open Registration.
32+
- Set the Open Reg Role Id to the name of the role you just created.
33+
- Make sure Open Reg Email Service Id is blank, so that new users can register without email confirmation.
34+
- Save changes.
35+
36+
- Import the package file for the app.
37+
- From the Apps tab in the admin console, click Import and click 'Address Book for iOS Swift' in the list of sample apps. The Address Book package contains the application description, schemas, and sample data.
38+
- Leave storage service and folder blank. This is a native iOS app so it requires no file storage on the server.
39+
- Click the Import button. If successful, your app will appear on the Apps tab. You may have to refresh the page to see your new app in the list.
40+
41+
- Make sure you have a SQL database service named 'db'. Depending on how you installed DreamFactory you may or may not have a 'db' service already available on your instance. You can add one by going to the Services tab in the admin console and creating a new SQL service. Make sure you set the name to 'db'.
42+
43+
#Running the Address Book app
44+
45+
Almost there! Clone this repo to your local machine then open and run the project with Xcode.
46+
47+
Before running the project you need to edit API_KEY in the file Network/RESTEngine.swift to match the key for your new app. This key can be found by selecting your app from the list on the Apps tab in the admin console.
48+
49+
The default instance URL is localhost:8080. If your instance is not at that path, you can change the default path in Network/RESTEngine.swift.
50+
51+
When the app starts up you can register a new user, or log in as an existing user. Currently the app does not support registering and logging in admin users.
52+
53+
#Additional Resources
54+
55+
More detailed information on the DreamFactory REST API is available [here](http://wiki.dreamfactory.com/DreamFactory/API).
56+
57+
The live API documentation included in the admin console is a great way to learn how the DreamFactory REST API works.
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
//
2+
// NIKApiInvoker.swift
3+
// SampleAppSwift
4+
//
5+
// Created by Timur Umayev on 1/4/16.
6+
// Copyright © 2016 dreamfactory. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
final class NIKApiInvoker {
12+
13+
let queue = NSOperationQueue()
14+
let cachePolicy = NSURLRequestCachePolicy.UseProtocolCachePolicy
15+
16+
/**
17+
get the shared singleton
18+
*/
19+
static let sharedInstance = NIKApiInvoker()
20+
static var __LoadingObjectsCount = 0
21+
private init() {
22+
}
23+
24+
private func updateLoadCountWithDelta(countDelta: Int) {
25+
objc_sync_enter(self)
26+
NIKApiInvoker.__LoadingObjectsCount += countDelta
27+
NIKApiInvoker.__LoadingObjectsCount = max(0, NIKApiInvoker.__LoadingObjectsCount)
28+
29+
UIApplication.sharedApplication().networkActivityIndicatorVisible = NIKApiInvoker.__LoadingObjectsCount > 0
30+
31+
objc_sync_exit(self)
32+
}
33+
34+
private func startLoad() {
35+
updateLoadCountWithDelta(1)
36+
}
37+
38+
private func stopLoad() {
39+
updateLoadCountWithDelta(-1)
40+
}
41+
42+
/**
43+
primary way to access and use the API
44+
builds and sends an async NSUrl request
45+
46+
- Parameter path: url to service, general form is <base instance url>/api/v2/<service>/<path>
47+
- Parameter method: http verb
48+
- Parameter queryParams: varies by call, can be put into path instead of here
49+
- Parameter body: request body, varies by call
50+
- Parameter headerParams: user should pass in the app api key and a session token
51+
- Parameter contentType: json or xml
52+
- Parameter completionBlock: block to be executed once call is done
53+
*/
54+
func restPath(path: String, method: String, queryParams: [String: AnyObject]?, body: AnyObject?, headerParams: [String: String]?, contentType: String?, completionBlock: ([String: AnyObject]?, NSError?) -> Void) {
55+
let request = NIKRequestBuilder.restPath(path, method: method, queryParams: queryParams, body: body, headerParams: headerParams, contentType: contentType)
56+
57+
/*******************************************************************
58+
*
59+
* NOTE: apple added App Transport Security in iOS 9.0+ to improve
60+
* security. As of this writing (7/15) all plain text http
61+
* connections fail by default. For more info about App
62+
* Transport Security and how to handle this issue here:
63+
* https://developer.apple.com/library/prerelease/ios/technotes/App-Transport-Security-Technote/index.html
64+
*
65+
*******************************************************************/
66+
67+
// Handle caching on GET requests
68+
69+
if (cachePolicy == .ReturnCacheDataElseLoad || cachePolicy == .ReturnCacheDataDontLoad) && method == "GET" {
70+
let cacheResponse = NSURLCache.sharedURLCache().cachedResponseForRequest(request)
71+
let data = cacheResponse?.data
72+
if let data = data {
73+
let results = try? NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: AnyObject]
74+
completionBlock(results!, nil)
75+
}
76+
}
77+
78+
if cachePolicy == .ReturnCacheDataDontLoad {
79+
return
80+
}
81+
startLoad() // for network activity indicator
82+
83+
let date = NSDate()
84+
NSURLConnection.sendAsynchronousRequest(request, queue: queue) {(response, response_data, var response_error) -> Void in
85+
self.stopLoad()
86+
if let response_error = response_error {
87+
if let response_data = response_data {
88+
let results = try? NSJSONSerialization.JSONObjectWithData(response_data, options: [])
89+
if let results = results as? [String: AnyObject] {
90+
completionBlock(nil, NSError(domain: response_error.domain, code: response_error.code, userInfo: results))
91+
} else {
92+
completionBlock(nil, response_error)
93+
}
94+
} else {
95+
completionBlock(nil, response_error)
96+
}
97+
return
98+
} else {
99+
let statusCode = (response as! NSHTTPURLResponse).statusCode
100+
if !NSLocationInRange(statusCode, NSMakeRange(200, 99)) {
101+
response_error = NSError(domain: "swagger", code: statusCode, userInfo: try! NSJSONSerialization.JSONObjectWithData(response_data!, options: []) as? [NSObject: AnyObject])
102+
completionBlock(nil, response_error)
103+
return
104+
} else {
105+
let results = try! NSJSONSerialization.JSONObjectWithData(response_data!, options: []) as! [String: AnyObject]
106+
if NSUserDefaults.standardUserDefaults().boolForKey("RVBLogging") {
107+
NSLog("fetched results (\(NSDate().timeIntervalSinceDate(date)) seconds): \(results)")
108+
}
109+
completionBlock(results, nil)
110+
}
111+
}
112+
}
113+
}
114+
}
115+
116+
final class NIKRequestBuilder {
117+
118+
/**
119+
Builds NSURLRequests with the format for the DreamFactory Rest API
120+
121+
This will play nice if you want to roll your own set up or use a
122+
third party library like AFNetworking to send the REST requests
123+
124+
- Parameter path: url to service, general form is <base instance url>/api/v2/<service>/<path>
125+
- Parameter method: http verb
126+
- Parameter queryParams: varies by call, can be put into path instead of here
127+
- Parameter body: request body, varies by call
128+
- Parameter headerParams: user should pass in the app api key and a session token
129+
- Parameter contentType: json or xml
130+
*/
131+
static func restPath(path: String, method: String, queryParams: [String: AnyObject]?, body: AnyObject?, headerParams: [String: String]?, contentType: String?) -> NSURLRequest {
132+
let request = NSMutableURLRequest()
133+
var requestUrl = path
134+
if let queryParams = queryParams {
135+
// build the query params into the URL
136+
// ie @"filter" = "id=5" becomes "<url>?filter=id=5
137+
let parameterString = queryParams.stringFromHttpParameters()
138+
requestUrl = "\(path)?\(parameterString)"
139+
}
140+
141+
if NSUserDefaults.standardUserDefaults().boolForKey("RVBLogging") {
142+
NSLog("request url: \(requestUrl)")
143+
}
144+
145+
let URL = NSURL(string: requestUrl)!
146+
request.URL = URL
147+
// The cache settings get set by the ApiInvoker
148+
request.timeoutInterval = 30
149+
150+
if let headerParams = headerParams {
151+
for (key, value) in headerParams {
152+
request.setValue(value, forHTTPHeaderField: key)
153+
}
154+
}
155+
156+
request.HTTPMethod = method
157+
if let body = body {
158+
// build the body into JSON
159+
var data: NSData!
160+
if body is [String: AnyObject] || body is [AnyObject] {
161+
data = try? NSJSONSerialization.dataWithJSONObject(body, options: [])
162+
} else if let body = body as? NIKFile {
163+
data = body.data
164+
} else {
165+
data = body.dataUsingEncoding(NSUTF8StringEncoding)
166+
}
167+
let postLength = "\(data.length)"
168+
request.setValue(postLength, forHTTPHeaderField: "Content-Length")
169+
request.HTTPBody = data
170+
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
171+
}
172+
173+
return request
174+
}
175+
}
176+
177+
extension String {
178+
179+
/** Percent escape value to be added to a URL query value as specified in RFC 3986
180+
- Returns: Percent escaped string.
181+
*/
182+
183+
func stringByAddingPercentEncodingForURLQueryValue() -> String? {
184+
let characterSet = NSMutableCharacterSet.alphanumericCharacterSet()
185+
characterSet.addCharactersInString("-._~")
186+
187+
return self.stringByAddingPercentEncodingWithAllowedCharacters(characterSet)
188+
}
189+
}
190+
191+
extension Dictionary {
192+
193+
/** Build string representation of HTTP parameter dictionary of keys and objects
194+
This percent escapes in compliance with RFC 3986
195+
- Returns: String representation in the form of key1=value1&key2=value2 where the keys and values are percent escaped
196+
*/
197+
198+
func stringFromHttpParameters() -> String {
199+
let parameterArray = self.map { (key, value) -> String in
200+
let percentEscapedKey = (key as! String).stringByAddingPercentEncodingForURLQueryValue()!
201+
let percentEscapedValue = (value as! String).stringByAddingPercentEncodingForURLQueryValue()!
202+
return "\(percentEscapedKey)=\(percentEscapedValue)"
203+
}
204+
205+
return parameterArray.joinWithSeparator("&")
206+
}
207+
}

SampleAppSwift/API/NIKFile.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// NIKFile.swift
3+
// SampleAppSwift
4+
//
5+
// Created by Timur Umayev on 1/4/16.
6+
// Copyright © 2016 dreamfactory. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
/**
12+
Use this object when building a request with a file. Pass it
13+
in as the body of the request to ensure that the file is built
14+
and sent up properly, especially with images.
15+
*/
16+
class NIKFile {
17+
let name: String
18+
let mimeType: String
19+
let data: NSData
20+
21+
init(name: String, mimeType: String, data: NSData) {
22+
self.name = name
23+
self.mimeType = mimeType
24+
self.data = data
25+
}
26+
}

0 commit comments

Comments
 (0)