Use https to access courses.json


#1

Since OS X 10.11+ enforces the use of secure connection with App Transport Security accessing the json file using a http url will fail.

One could add an exception to the applications info.plist file, but as bignerdranch luckily has an SSL certificate it would be best to change the url to https://… in your code.


#3

It’s me again. Sorry this post will be a little long with the code included.

I can access the BNR data using Safari with: http://bookapi.bignerdranch.com/courses.json and all the data shows up.

Trying through the RanchForecast app I was getting the App Transport security warning. I tried the above suggestion, which I know was from 2015 and things change, but that didn’t work. It also doesn’t work using https:// in Safari.

I researched online and found what would need to be added to the info.plist file to allow an exception. I added the following code to the info.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-    1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2018 JETApps. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSAppTransportSecurity</key>
<dict>
	<key>NSExceptionDomains</key>
	<dict>
			<key>bookapi.bignerdranch.com</key>
			<dict>
 				 <!--Include to allow subdomains-->
 				 <key>NSIncludesSubdomains</key>
 				 <true/>
 				 <!--Include to allow HTTP requests-->
 				 <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
 				 <true/>
 				 <!--Include to specify minimum TLS version-->
 				 <key>NSTemporaryExceptionMinimumTLSVersion</key>
 				 <string>TLSv1.1</string>
			</dict>
	</dict>
</dict>
</dict>
</plist>

The portion I added starts with “NSAppTransportSecurity” and that allowed me to get past the security warning.

Now, however, when I run the app I get this warning after it tries to connect a few times:

“A server with the specified hostname could not be found.”

I am using the recommend “http://bookapi.bignerdranch.com/courses.json” that works in Safari.

Here is my MainWindowController.swift:

import Cocoa

class MainWindowController: NSWindowController {

let fetcher = ScheduleFetcher()
@objc dynamic var courses: [Course] = []

override var windowNibName: NSNib.Name? {
	return NSNib.Name(rawValue: "MainWindowController")
}

override func windowDidLoad() {
	super.windowDidLoad()
	
	fetcher.fetchCoursesUsing { (result) in
		switch result {
		case .Success(let courses):
			print("Got courses: \(courses)")
			self.courses = courses
		case .Failure(let error):
			print("Got error: \(error)")
			NSAlert(error: error).runModal()
			self.courses = []
		}
	}
}

}

and here is my ScheduleFetcher.swift:

import Foundation

class ScheduleFetcher {

enum FetchCoursesResult {
	case Success([Course])
	case Failure(NSError)
}

let session: URLSession

init() {
	let config = URLSessionConfiguration.default
	session = URLSession(configuration: config)
}

//------------------------------------------------------------------------

func fetchCoursesUsing(completionHandler: @escaping(FetchCoursesResult) -> (Void)) {
	let url = NSURL(string: "http://bookapi.bignerdranch.com/courses.json")!
	let request = URLRequest(url: url as URL)
	
	let task = session.dataTask(with: request, completionHandler: {
		(data, response, error) -> Void in
		var result: FetchCoursesResult
		
		if data == nil {
			result = .Failure(error! as NSError)
		} else {
			print("Received \(String(describing: data?.count)) bytes.")
			result = .Success([])	// Empty array until parsing is added
		}
		OperationQueue.main.addOperation({
			completionHandler(result)
		})
		
	})
	task.resume()
}
}

Any ideas? I know I must be missing something again…


#4

Once again, all I have to do is post the problem on here and I find the solution shortly after. I had to activate Outgoing Connections in the sandbox! Duh.

it now connects and downloads the data. Onward!