How can I access the original response json data without using object mapping. I have the followingresponse data. it contains a nextSyncToken which used to execute the query and a collection of items (within the items session).
I created a object mapping of the Item object which represent the contents in items. However, I also need the nextSyncToken field. How can I access it without object mapping. Since the syncToken has no relationship with object mapping. How can i deal with this.
{
"kind": "calendar#events",
"nextSyncToken": "COib8eSw78gCEOib8eSw78gCGAU=",
"items": [
{
"id": "_74rk4cpg84o42b9k8or3gb9k74s34b9p8ks34b9m851kac9m64rk4ci36g",
"created": "2010-04-16T11:09:31.000Z",
"updated": "2010-04-16T11:10:27.487Z",
"summary": "iCal test 1",
"start": {
"dateTime": "2010-03-16T21:00:00+08:00"
},
"end": {
"dateTime": "2010-03-16T22:00:00+08:00"
}
},
{
"id": "_752j2h1j6cq4cba68csjeb9k8p33eba1692k4ba284qj8ea688rj2chh6c",
"status": "confirmed",
"created": "2011-10-18T09:36:02.000Z",
"updated": "2011-10-18T09:36:02.000Z",
"summary": "New Event",
"start": {
"dateTime": "2011-10-18T03:45:00+08:00"
},
"end": {
"dateTime": "2011-10-18T08:15:00+08:00"
}
}
]
}
My code of mapping:
let eventMapping = RKEntityMapping(forEntityForName: "SGEvent", inManagedObjectStore: managedObjectStore)
eventMapping.addAttributeMappingsFromDictionary([
"id": "identifier",
"summary": "summary",
"created": "createdAt",
"updated": "updatedAt",
"location": "location",
"description": "notes",
"start.date": "allDayStart",
"end.date": "allDayEnd"
])
let startTimeMapping = RKAttributeMapping(fromKeyPath: "start.dateTime", toKeyPath: "startTime")
startTimeMapping.valueTransformer = self.googleDateTransformer
eventMapping.addPropertyMapping(startTimeMapping)
let endTimeMapping = RKAttributeMapping(fromKeyPath: "end.dateTime", toKeyPath: "endTime")
endTimeMapping.valueTransformer = self.googleDateTransformer
eventMapping.addPropertyMapping(endTimeMapping)
eventMapping.identificationAttributes = ["identifier"]
let responseDescriptor = RKResponseDescriptor(mapping: eventMapping, method: .GET,
pathPattern: "calendars/:calendarId/events", keyPath: "items",
statusCodes: RKStatusCodeIndexSetForClass(RKStatusCodeClass.Successful))
objectManager.addResponseDescriptor(responseDescriptor)
My request operation:
objectManager.getObjectsAtPath("calendars/\(identifier)/events",
parameters: [self.ACCESS_TOKEN: accessToken], success: { (operation, results) -> Void in
callback?(results: nil, error: nil)
}) { (_, error) -> Void in
print(error)
}
Generally you would add other response descriptors with appropriate mappings to deal with this issue.
When using objectManager.getObjectsAtPath you can get the raw data, assuming that you have some other response descriptor which will result in the success block being called, by navigating to the response data in the HTTP operation (which you can then unpack however you see fit):
operation.HTTPRequestOperation.responseData
(or use responseString instead of responseData).
if let dict = try? NSJSONSerialization.JSONObjectWithData(operation.HTTPRequestOperation.responseData, options: .AllowFragments) as? [String: AnyObject],
let nextSyncToken = dict?["nextSyncToken"] as? String{
print(nextSyncToken)//get the nextSyncToken
}
Related
I'm having this bizarre problem in which I cannot do a simple POST request to a REST service I do not control based on GraphQL.
The problem is that no matter what I set in the httpMethod property of the URLRequest class, it always uses GET instead.
I have done a few tests to discard some problems. For example, I set up a header in the Request and I can verify that the header is being sent to the server (verified with Charles Proxy).
This is the code you can paste and run in a Playground:
import PlaygroundSupport
import Foundation
PlaygroundPage.current.needsIndefiniteExecution = true
let url = URL(string: "http://graphql.anilist.co/")!
let internalSession = URLSession(configuration: .default)
var request = URLRequest(url: url)
request.httpMethod = "POST"
let headers = ["content-type": "application/json"]
request.allHTTPHeaderFields = headers
request.httpBody =
"""
{"query":"query (\n\t$season: MediaSeason,\n\t$year: Int,\n\t$format: MediaFormat,\n\t$excludeFormat: MediaFormat,\n\t$status: MediaStatus,\n\t$minEpisodes: Int,\n\t$page: Int,\n){\n\tPage(page: $page) {\n\t\tpageInfo {\n\t\t\thasNextPage\n\t\t\ttotal\n\t\t}\n\t\tmedia(\n\t\t\tseason: $season\n\t\t\tseasonYear: $year\n\t\t\tformat: $format,\n\t\t\tformat_not: $excludeFormat,\n\t\t\tstatus: $status,\n\t\t\tepisodes_greater: $minEpisodes,\n\t\t\tisAdult: false,\n\t\t\ttype: ANIME,\n\t\t\tsort: TITLE_ROMAJI,\n\t\t) {\n\t\t\t\nid\nidMal\ntitle {\n\tromaji\n\tnative\n\tenglish\n}\nstartDate {\n\tyear\n\tmonth\n\tday\n}\nendDate {\n\tyear\n\tmonth\n\tday\n}\nstatus\nseason\nformat\ngenres\nsynonyms\nduration\npopularity\nepisodes\nsource(version: 2)\ncountryOfOrigin\nhashtag\naverageScore\nsiteUrl\ndescription\nbannerImage\ncoverImage {\n\textraLarge\n\tcolor\n}\ntrailer {\n\tid\n\tsite\n\tthumbnail\n}\nexternalLinks {\n\tsite\n\turl\n}\nrankings {\n\trank\n\ttype\n\tseason\n\tallTime\n}\nstudios(isMain: true) {\n\tnodes {\n\t\tid\n\t\tname\n\t\tsiteUrl\n\t}\n}\nrelations {\n\tedges {\n\t\trelationType(version: 2)\n\t\tnode {\n\t\t\tid\n\t\t\ttitle {\n\t\t\t\tromaji\n\t\t\t\tnative\n\t\t\t\tenglish\n\t\t\t}\n\t\t\tsiteUrl\n\t\t}\n\t}\n}\n\nairingSchedule(\n\tnotYetAired: true\n\tperPage: 2\n) {\n\tnodes {\n\t\tepisode\n\t\tairingAt\n\t}\n}\n\n\t\t}\n\t}\n}","variables":{"season": WINTER,"year": 2019,"page": 1, "perPage": 100}}
""".data(using: .utf8)
print("THE REQUEST \(String(describing: request.httpMethod))")
let task = internalSession.dataTask(with: request, completionHandler: { (data, response, error) in
if let e = error {
print("ERROR: \(e)")
} else if let response = response as? HTTPURLResponse {
print("THE RESPONSE: \(response)")
let json = try! JSONSerialization.jsonObject(with: data!, options: [])
print(json)
}
})
task.resume()
(Please ignore all the forced unwrap optionals and forced try!, this is test code).
Expected Result
I expect the web service to return a JSON similar to this (simplified):
{
"data": {
"Page": {
"pageInfo": {
"hasNextPage": true,
"total": 81
},
"media": [
{
"id": 102882,
"idMal": 37956,
"title": {
"romaji": "3D Kanojo: Real Girl 2",
"native": "3D彼女 リアルガール 2",
"english": "Real Girl 2"
},
"startDate": {
"year": 2019,
"month": 1,
"day": 9
},
"endDate": {
"year": null,
"month": null,
"day": null
},
"status": "RELEASING",
"season": "WINTER",
"format": "TV",
"genres": [
"Romance",
"Slice of Life",
"Comedy"
],
"synonyms": [],
"duration": 23,
"popularity": 3298,
"episodes": 12,
"source": "MANGA",
"countryOfOrigin": "JP",
"hashtag": "#3D彼女リアルガール #3D彼女",
"averageScore": 61,
"siteUrl": "https://anilist.co/anime/102882",
"description": "The second season of <i>3D Kanojo</i>.",
"bannerImage": null,
"coverImage": {
"extraLarge": "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/nx102882-lKp3ExWNzoE6.jpg",
"color": "#e4bb93"
},
"trailer": {
"id": "x6yokzp",
"site": "dailymotion",
"thumbnail": "https://www.dailymotion.com/thumbnail/video/x6yokzp"
},
"externalLinks": [
{
"site": "Official Site",
"url": "http://www.3dkanojo-anime.com/"
},
{
"site": "Twitter",
"url": "https://twitter.com/3Dkanojo_anime"
}
],
"rankings": [
{
"rank": 16,
"type": "RATED",
"season": null,
"allTime": false
},
{
"rank": 19,
"type": "POPULAR",
"season": null,
"allTime": false
},
{
"rank": 16,
"type": "RATED",
"season": "WINTER",
"allTime": false
},
{
"rank": 15,
"type": "POPULAR",
"season": "WINTER",
"allTime": false
}
],
"studios": {
"nodes": [
{
"id": 346,
"name": "Hoods Entertainment",
"siteUrl": "https://anilist.co/studio/346"
}
]
},
"relations": {
"edges": [
{
"relationType": "PREQUEL",
"node": {
"id": 100526,
"title": {
"romaji": "3D Kanojo: Real Girl",
"native": "3D彼女 リアルガール",
"english": "Real Girl"
},
"siteUrl": "https://anilist.co/anime/100526"
}
},
{
"relationType": "SOURCE",
"node": {
"id": 80767,
"title": {
"romaji": "3D Kanojo: Real Girl",
"native": "3D彼女 〈リアルガール〉",
"english": "Real Girl"
},
"siteUrl": "https://anilist.co/manga/80767"
}
}
]
},
"airingSchedule": {
"nodes": [
{
"episode": 7,
"airingAt": 1550595540
},
{
"episode": 8,
"airingAt": 1551200340
}
]
}
}
]
}
}
}
Obtained Result
Instead, I get this:
{
"data": null,
"errors": [
{
"message": "Not Found.",
"hint": "Use POST request to access graphql subdomain.",
"status": 404
}
]
}
The service complains that the request is a GET request and should be POST, and I am explicitly telling URLRequest to use POST instead. If you look at the request in Charles or another proxy, you will indeed see that the request is being done as a GET request, and the httpBody property is being discarded. If you edit the headers and add another header, like so:
let headers = ["content-type": "application/json", "foo": "bar"]
You will see in your proxy that the header is being properly sent.
The only conclusion I can arrive is that there is an internal problem with URLSessionDataTask that forces to do GET requests only. I tried changing it to to a download task, but the same problem is happening. So there must be a problem with my code, but I cannot find it.
EDIT:
Per request, this is the request Postman uses. I have exported the request to CURL to make it easily importable.
curl -X POST \
https://graphql.anilist.co/ \
-H 'Content-Type: application/json' \
-H 'Postman-Token: 49d7e55e-35c2-4a3c-82f0-4eccb1250fc0' \
-H 'cache-control: no-cache' \
-d '{"query":"query (\n\t$season: MediaSeason,\n\t$year: Int,\n\t$format: MediaFormat,\n\t$excludeFormat: MediaFormat,\n\t$status: MediaStatus,\n\t$minEpisodes: Int,\n\t$page: Int,\n){\n\tPage(page: $page) {\n\t\tpageInfo {\n\t\t\thasNextPage\n\t\t\ttotal\n\t\t}\n\t\tmedia(\n\t\t\tseason: $season\n\t\t\tseasonYear: $year\n\t\t\tformat: $format,\n\t\t\tformat_not: $excludeFormat,\n\t\t\tstatus: $status,\n\t\t\tepisodes_greater: $minEpisodes,\n\t\t\tisAdult: false,\n\t\t\ttype: ANIME,\n\t\t\tsort: TITLE_ROMAJI,\n\t\t) {\n\t\t\t\nid\nidMal\ntitle {\n\tromaji\n\tnative\n\tenglish\n}\nstartDate {\n\tyear\n\tmonth\n\tday\n}\nendDate {\n\tyear\n\tmonth\n\tday\n}\nstatus\nseason\nformat\ngenres\nsynonyms\nduration\npopularity\nepisodes\nsource(version: 2)\ncountryOfOrigin\nhashtag\naverageScore\nsiteUrl\ndescription\nbannerImage\ncoverImage {\n\textraLarge\n\tcolor\n}\ntrailer {\n\tid\n\tsite\n\tthumbnail\n}\nexternalLinks {\n\tsite\n\turl\n}\nrankings {\n\trank\n\ttype\n\tseason\n\tallTime\n}\nstudios(isMain: true) {\n\tnodes {\n\t\tid\n\t\tname\n\t\tsiteUrl\n\t}\n}\nrelations {\n\tedges {\n\t\trelationType(version: 2)\n\t\tnode {\n\t\t\tid\n\t\t\ttitle {\n\t\t\t\tromaji\n\t\t\t\tnative\n\t\t\t\tenglish\n\t\t\t}\n\t\t\tsiteUrl\n\t\t}\n\t}\n}\n\nairingSchedule(\n\tnotYetAired: true\n\tperPage: 2\n) {\n\tnodes {\n\t\tepisode\n\t\tairingAt\n\t}\n}\n\n\t\t}\n\t}\n}","variables":{"year":2019,"season":"WINTER","page":1, "limit": 12}}'
Only difference I am seeing here is http:// in your Playground and https:// in your Postman.
So just replace http:// with https:// in your Playground.
My JSON format:
{
"results": [
{
"objectId": "1a8SJaCo2P",
"Name": "Banyan Tree",
"Amount": 300,
"Area": "Nizampura",
"Cuisins": [
"Asian",
"Italian",
"Chaat",
"Awadhi"
],
"Facility": [
"Music",
"Smoking Area",
"Take Away",
"Home Delivery"
],
"Restaurant_Images": {
"__type": "File",
"name": "a138194bc773ffa570a27a640d66f89f_5.jpg",
}
},
]
}
I know how to parse basic json format but it has a {"results":[{user1},{user2},....]} data. So how to parse it?
This is the back4app(parse.com) api requested format
I don't know if you are getting serialized data or rawData. But I'll assume you are getting rawData. So, you may try the following
let serializedJson = try JSONSerialization.jsonObject(with: responseData, options: .mutableContainers)
if let expectedResults = serializedJson as? [String:Any] {
if let users = expectedResults["results"] as? [Any] {
for user in users {
//you will get the values
// now if it is parseable to PFUser
//Then you can have
if let user = user as? PFUser {
//you will have individual user
}
//If not parseable to PFUSer then you can parse it manually
}
}
}
First lets see the json data.
[
{
"id": "244",
"name": "PIZZAS",
"image": "",
"coupon": "1",
"icon": "",
"order": "1",
"aname": "",
"options": "2",
"subcategory": [
{
"id": "515",
"name": "MARGARITA",
"description": "Cheese and Tomato",
"image": "",
"icon": "",
"coupon": "1",
"order": "1",
"aname": "",
"options": "2",
"item": [
{
"id": "1749",
"name": "9 Inch Thin & Crispy Margarita",
"description": "",
"price": "3.40",
"coupon": "1",
"image": "",
"options": "2",
"order": "1",
"addon": "495",
"aname": "",
"icon": ""
}]
}]
}]
I have used Alamofire and getting response through this code below:
Alamofire.request(.GET, myUrl, parameters:nil , encoding: .JSON)
.validate()
.responseString { response in
print("Response String: \(response.result.value)")
}
.responseJSON { response in
print("Response JSON: \(response.result.value)")
if let jsonResult = response as? Array<Dictionary<String,String>> {
let Name = jsonResult[0]["name"]
let ID = jsonResult[0]["id"]
let Order = jsonResult[0]["order"]
print("JSON: Name: \(Name)")
print("JSON: ID: \(ID)")
print("JSON: Order: \(Order)")
}
}
But after getting response data I am not able to get any value. Here I want to fetch all data like name,id and subcategory - how to implement this?
You have more than one problem there.
First response is of type Response<Anyobject, NSError>, it's not the parsed object you're looking for, instead you should use response.result.value as you did for the log.
Second even if you tried to cast response.result.value to Array<Dictionary<String,String>> it will not pass because in your json data you have ann inner array subcategory which cannot be casted to Dictionary<String, String>
This code should work for you:
Alamofire.request(.GET, myUrl, parameters:nil , encoding: .JSON)
.validate()
.responseString { response in
print("Response String: \(response.result.value)")
}
.responseJSON { response in
print("Response JSON: \(response.result.value)")
let array = response.result.value as! Array<NSDictionary>
for item in array
{
let Name = item["name"]
let ID = item["id"]
let Order = item["order"]
let Subcategories = item["subcategory"] as! Array<NSDictionary>
for subCategory in Subcategories
{
let subId = subCategory["id"]
}
}
}
And here is the results in the playground:
Cheers.
I am trying to incorporate Wunderground into my current project. I have looked at several api tutorials, but I can't seem to figure out how to access a certain part of the API. For example, this is sort of what the API looks like:
{
"response": {
"version":"0.1",
"termsofService":"http://www.wunderground.com/weather/api/d/terms.html",
"features": {
"history": 1
}
}
,
"history": {
"date": {
"pretty": "August 9, 2015",
"year": "2015",
"mon": "08",
"mday": "09",
"hour": "12",
"min": "00",
"tzname": "America/Los_Angeles"
},
Let's say I wanted to return only the hour from the API. How would I do that?
A way to parse JSON without frameworks:
typealias JSONdic = [String: AnyObject]
NSURLConnection.sendAsynchronousRequest(NSURLRequest(URL: nsUrl), queue: NSOperationQueue.mainQueue(), completionHandler: { (_, data, _) -> Void in
if let data = data, json = data as? JSONdic, history = json["history"] as? JSONdic, hour = history["hour"] as? String {
println(hour)
}
Problem: Attempting to consume a JSON payload which contains a dynamic Object name. Since the names of these objects are not sequential or derived from a pattern, I'm unable to travers the payload with SwiftyJSON. A sample of the dynamic objects looks like this denoted in bold:
"180A": {
"id": "180A",
"label": "Oceanside Gate",
"path": "North",
"index": "1"
},
"195C": {
"id": "195C",
"label": "Dune Beach Gate",
"path": "North",
"index": "2"
},
"211F": {
"id": "211F",
"label": "Sunset Harbor Gate",
"path": "North",
"index": "3"
}
Sample JSON Payload:
{
"Direction": {
"NorthGates": {
"180A": {
"id": "180A",
"label": "Oceanside Gate",
"path": "North",
"index": "1"
},
"195C": {
"id": "195C",
"label": "Dune Beach Gate",
"path": "North",
"index": "2"
},
"211F": {
"id": "211F",
"label": "Sunset Harbor Gate",
"path": "North",
"index": "3"
}
}
}
}
Using SwiftyJSON I'm able to successfully print the label of a known Object, such as "180A":
DataManager.getTopAppsDataFromFileWithSuccess { (data) -> Void in
let json = JSON(data: data)
if let gateLabel = json["Direction"]["NorthGates"]["180A"]["label"].stringValue {
//output: "Oceanside Gate"
println("NSURLSession: \(gateLabel)")
}
}
Since the dynamic object names are not static, I'm unable to use the pre-defined object names in the code above to locate the label value. The following attempts return nil values:
//stringValue = nil
if let gateLabel = json["Direction"]["NorthGates"][0].stringValue {
println("NSURLSession: \(gateLabel)")
}
//stringValue = nil
if let gateLabel = json["Direction"]["NorthGates"][0]["label"].stringValue {
println("NSURLSession: \(gateLabel)")
}
This is the solution:
if let gates:[String: JSON] = json["Direction"]["NorthGates"].dictionaryValue {
for item in gates {
println("Dynamic Object Gate Name: \(item.0)") //Gate Name
println(item.1["label"].stringValue) //Gate Label
println(item.1["path"].stringValue) //Gate Path
println(item.1["index"].stringValue) //Gate Index
}
}