Skip to content

Instantly share code, notes, and snippets.

@rnapier
Last active February 3, 2018 22:59
Show Gist options
  • Save rnapier/8afbf9d549180423919f to your computer and use it in GitHub Desktop.
Save rnapier/8afbf9d549180423919f to your computer and use it in GitHub Desktop.
Yeah, @krzyzanowskim is probably right. What problem were we solving?
import Foundation
// All the complexity needed to avoid this code probably isn't worth it in the majority of cases.
// Particularly note that the data model doesn't 100% line up with the JSON (some keys have
// slightly different names for instance). A system flexible enough to handle that (say, something
// like Go's json.Marshal) would be nice, but this code, while slightly tedious, isn't really bad.
// Basically I'm saying that a richer JSON<->Swift system built into stdlib would be nice, but the
// bar is pretty high to go pulling in a helper library.
//
// That said, compare the Go code below, and I think it really is much simpler, and scales much better
// to non-trivial cases. So something like this in Swift stdlib would I think have a lot of value.
typealias JSONObject = [String:AnyObject]
enum Error: ErrorType {
case InvalidJSON(AnyObject)
}
struct Revision {
let contentFormat: String
let contentModel: String
let content: String
}
extension Revision {
init(json: JSONObject) throws {
guard
let contentFormat = json["contentformat"] as? String,
let contentModel = json["contentmodel"] as? String,
let content = json["*"] as? String
else { throw Error.InvalidJSON(json) }
self.init(
contentFormat: contentFormat,
contentModel: contentModel,
content: content)
}
}
struct Page {
let pageid: Int
let ns: Int
let title: String
let revisions: [Revision]
}
extension Page {
init(json: JSONObject) throws {
guard
let pageid = json["pageid"] as? Int,
let ns = json["ns"] as? Int,
let title = json["title"] as? String,
let revisions = json["revisions"] as? [JSONObject]
else { throw Error.InvalidJSON(json) }
self.init(
pageid: pageid,
ns: ns,
title: title,
revisions: try revisions.map(Revision.init)
)
}
}
func parse(json: AnyObject) throws -> [Page] {
guard
let dict = json as? JSONObject,
let query = dict["query"] as? JSONObject,
let pages = query["pages"] as? [String: JSONObject]
else { throw Error.InvalidJSON(json) }
return try pages.values.map(Page.init)
}
func searchURLForString(text: String) -> NSURL {
let encodedText = text.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
return NSURL(string: "https://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvprop=content&format=json&titles=\(encodedText)")!
}
let searchString = "Main Page"
let url = searchURLForString(searchString)
let req = NSURLRequest(URL: searchURLForString(searchString))
let data = NSData(contentsOfURL: url)!
let json = try NSJSONSerialization.JSONObjectWithData(data, options: [])
print(try parse(json))
// That said, here it is in Go, and it really is much simpler (if not actually much shorter)
package main
import (
"net/url"
"net/http"
"log"
"encoding/json"
"io"
"fmt"
)
type Revision struct {
ContentFormat string `json:"contentformat"`
ContentModel string `json:"contentmodel"`
Content string `json:"*"`
}
type Page struct {
PageID int `json:"pageid"`
NS int `json:"ns"`
Title string `json:"title"`
Revisions []Revision `json:"revisions"`
}
type query struct {
Pages map[string]Page `json:"pages"`
}
type message struct {
Query query `json:"query"`
}
func searchURLForString(text string) string {
encodedText := url.QueryEscape(text)
return "https://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvprop=content&format=json&titles=" + encodedText
}
func main() {
searchString := "Main Page"
url := searchURLForString(searchString)
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
dec := json.NewDecoder(resp.Body)
var m message
if err := dec.Decode(&m); err != nil {
log.Fatal(err)
}
for _, page := range m.Query.Pages {
fmt.Printf("%#v\n", page)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment