I'm attempting to make a call to the real time database that I have constructed in firebase. I have utilized the three different methods stated in the documentation, however, I still get an unacceptable access code.
Below are the current code and method that I am using.
let apiToContact = "https://gameofchats-c29ab.firebaseio.com/users.json?auth=AIzaSyBK3J4tzVQNJlhqqmYPRWXlJqnzFB1Hj4k"
let request = Alamofire.request(apiToContact, method: .get, parameters: nil, encoding: URLEncoding.queryString, headers: nil)
request.validate().responseJSON(){ response in
switch response.result {
case .success:
if let value = response.result.value {
let json = JSON(value)
let allEventData = json["events"].arrayValue
// Do what you need to with JSON here!
// print(json)
// print("\n\nlook here\n\n")
// print(allRestaurantData)
// The rest is all boiler plate code you'll use for API requests
print("\n\nlook here\n\n")
print(allEventData)
// var firstRestaurant = allRestaurantData[0]
//print(firstRestaurant)
// will populate all Restaurants Array with restaurant objects
/*
for restaurantStruct in allRestaurantData {
self.allRestaurants.append(Restaurants(json: restaurantStruct))
}
for restaurantsName in self.allRestaurants{
print(restaurantsName.restaurantApiKey)
print("\n")
}
*/
// will take the imageUrl array and populate it with the logoURL of the restaurants for later user
/* for images in self.allRestaurants{
self.imageUrl.append(images.logoUrl)
print(images.logoUrl)
print("\n")
}
*/
}
case .failure(let error):
print(error)
}
Related
I'm struggling with making badge requests with Alamofire and I need help.
I have some ids and with them I need to struct parameters (Dictionary String) and send a GET request with Alamofire. Everything is fine, but I need to cover the case when ids are above 200, because when they are more than 200, API returns 414 code status (too long URL). So when ids are more than 200 they are separated in chunks. With each chunk I'm making a new request to API. The problem is that I return only the first 200 ids when I call my method. Here is an example:
func request (_ idsDict: [String: [String]], _ idSchema: String, _ completion: #escaping Result<SomeModel, Error>) -> Void {
let chunks = transformEntitiesIdsToChunks(idsDict)
let decoder = JSONDecoder()
chunks.forEach {chunk in
let parameters = constructQueryParams(idsDict, chunk, idSchema, apiKey, clientId)
AF.request(baseURL, parameters: parameters).response { response in
switch response.result {
case .success(let data):
// some error handling for decoding and no data
completion(.success(data.data))
case .failure(let error):
return completion(.failure(error.localizedDescription))
}
}
}
}
// Method wraps AF request in a continuation block and makes sure that the closure from request method returned data or throwed error.
// That way fetching from API becomes async/await and can be used in do/try/catch block.
func getIdsEntities (_ idsDict: [String: [String]], _ idSchema: String) async throws -> [SomeModel] {
return try await withUnsafeThrowingContinuation { continuation in
request(idsDict, idSchema) { result in
switch result {
case .success(let data):
continuation.resume(returning: data)
return
case .failure(let error):
continuation.resume(throwing: error)
return
}
}
}
}
I have tried with recursive functions and with DispatchGroup but none of them worked. Any help will be appriciated. Thank you in advance.
Thanks to Larme's comment I was able to find my mistake. When making request to API I was passing the decoded response to the completion closure. To fix this I had to declare an array of model let responses:[SomeModel] = [] and append the decoded result to it. I used let group = DispatchGroup() so I can wait the requests to execute and have my final array of results and then I used group.notify(queue: .main, execute: {completion(.success(responses))}) to return to the main queue and have my array of completed fetched data. This is now how my code looks like:
private func request (_ idsDict: [String: [String]], _ idSchema: String, _ completion: #escaping APIListResponseClosure<SomeModel>) -> Void {
var responses: [SomeModel] = []
let group = DispatchGroup()
let chunks = transformEntitiesIdsToChunks(idsDict)
let decoder = JSONDecoder()
chunks.forEach {chunk in
group.enter()
let parameters = constructQueryParams(idsDict, chunk, idSchema, apiKey, clientId)
AF.request(baseURL, parameters: parameters).response { response in
switch response.result {
case .success(let data):
// some error handling for decoding and no data
responses.append(data.data)
group.leave()
case .failure(let error):
return completion(.failure(.APIError(error.localizedDescription)))
}
}
}
group.notify(queue: .main, execute: {
print("Ids are fetched")
completion(.success(responses))
})
}
Thanks again to Larme and I hope I helped someone else with this case.
I have a JSON array at url = https://api.github.com/users/greenrobot/starred .
I want to count how many objects are there in that array using swift. I don't want data present, I just want count of it.
Assuming you downloaded the contents of that URL into a variable data of type Data:
if let object = try? JSONSerialization.jsonObject(with: data, options: []) as? [[String: AnyHashable]] {
let count = object[0].keys.count
}
I assume that you are using Alamofire for making a network request. In the code below we are just extracting the value object from Alamofire result. We convert the value to Array of dictionaries and then you can just get the count.
AF.request("https://api.github.com/users/greenrobot/starred",method: .get).responseJSON { apiResponse in
switch apiResponse.result{
case .success(_):
let dictionary = apiResponse.value as? [[String:Any]]
print("dictionaryCount \(dictionary?.count ?? -1)")
case .failure(_):
print("error \(apiResponse.error?.underlyingError?.localizedDescription ?? "")")
}
}
The GitHub starred API returns a maximum of 30 items by default, in the case of greenrobot with a total number of 372 it's not meaningful.
A smart way to get the actual number of starred items is to specify one item per page and to parse the Link header of the HTTP response which contains the number of the last page
Task {
do {
let url = URL(string: "https://api.github.com/users/greenrobot/starred?per_page=1")!
let (_, response) = try await URLSession.shared.data(from: url)
guard let link = (response as? HTTPURLResponse)?.value(forHTTPHeaderField: "Link") else {
throw URLError(.badServerResponse)
}
let regex = try NSRegularExpression(pattern: "page=(\\d+)")
if let lastMatch = regex.matches(in: link).last {
let range = Range(lastMatch.range(at: 1), in: link)!
let numberOfStarredItems = String(link[range])
print(numberOfStarredItems)
} else {
print("No match found")
}
} catch {
print(error)
}
}
i'm currently facing the Problem that after the OAuth1 process, when i actually want to send the image, flickrapi responds with: No Photo Specified. :
<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="fail">
<err code="2" msg="No photo specified" />
</rsp>
I am using the OAtuthSwift Framework for ios on XCode 10, Swift 4 for this task.
oAuthSwift = OAuth1Swift(consumerKey: flickr.apiKey,
consumerSecret: flickr.apiSecret,
requestTokenUrl: "https://www.flickr.com/services/oauth/request_token",
authorizeUrl: "https://www.flickr.com/services/oauth/authorize",
accessTokenUrl: "https://www.flickr.com/services/oauth/access_token")
if oAuthSwift != nil {
oAuthSwift?.authorizeURLHandler = SafariURLHandler(viewController: self, oauthSwift: oAuthSwift!)
guard let rwURL = URL(string: "iflickr://oauth-callback/iflickr") else {
return
}
let handle = oAuthSwift!.authorize( withCallbackURL: rwURL) { [unowned self] result in
switch result {
case .success(let (credential, response, parameters)):
print(credential.oauthToken)
print(credential.oauthTokenSecret)
guard let img = self.image?.jpegData(compressionQuality: 0.0) else {
print ("cant convert image")
return
}
var params = parameters
// Until Here seems everything fine
self.oAuthSwift!.client.postImage(flickr.uploadEndpoint, parameters: params, image: img) { upResult in
switch upResult {
case .failure(let error):
print (error)
case .success(let response):
let respData = response.data
if let string = response.string {
print ("\nRESULT:\n - \(string)\n")
// Here it prints the above described `No Photo Specified`
}
}
}
case .failure(let error):
print(error.localizedDescription)
}
}
}
I also tried to do the Request by myself and just take the values of the Dictionary provided from the OAuth process (parameters), but then it says something like: No Token were provided..
Can someone Help?
Like mentioned from #Clemens Brockschmidt, the image parameter were not correct. OAuthSwift provided standardwise "media" as parameter name, which was not accepted by the flickr upload API.
After recognise this, i changed the parameter name from "media" to "photo".
Code is in
OAuthSwift/Sources/OAuthSwiftClient.swift:multiPartRequest(), line 125
https://github.com/OAuthSwift/OAuthSwift/blob/b8941a23d1584ba17426c312bb957de355341f4a/Sources/OAuthSwiftClient.swift#L125
I'm very new to Swift 3, and i have to do a GET request on my API. I'm using Alamofire, which uses Asynchronous functions.
I do exactly the same on my Android App, and the GET returns JSON data
This is my code in swift :
func getValueJSON() -> JSON {
var res = JSON({})
let myGroup = DispatchGroup()
myGroup.enter()
Alamofire.request(url_).responseJSON { response in
res = response.result.value as! JSON
print("first result", res)
myGroup.leave()
}
myGroup.notify(queue: .main) {
print("Finished all requests.", res)
}
print("second result", res)
return res
}
But i have a problem with the line "res = response.result.value" wich gives me the error : Thread 1 : signal SIGABRT
I really don't understand where the problem comes from, it was pretty hard to do a "synchronous" function, maybe i'm doing it wrong.
My objective is to store the result of the request in a variable that i return. Anyone can help ?
I'd recommend you to use Alamofire together with SwiftyJSON because that way you'll be able to parse JSON easier a lot.
Here's a classical example:
Alamofire.request("http://example.net", method: .get).responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
print("JSON: \(json)")
case .failure(let error):
print(error)
}
}
If you need to pass parameters, or headers, just add it in the request method.
let headers: HTTPHeaders = [
"Content-Type:": "application/json"
]
let parameters: [String: Any] = [
"key": "value"
]
So your request will be something like this (this is POST request):
Alamofire.request("http://example.net", method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON { response in
switch response.result {
case .success(let value):
print(value)
case .failure(let error):
print(error)
}
}
I haven't tested it, but it should work. Also, you need to set allow arbitary load to yes (App Transport Security Settings in info.plist) if you want to allow requests over HTTP protocol.
This is NOT recommended, but it's fine for development.
I am using Alamofire version 3.1.5 with my xCode version 7.3. I tried it on many apps of mine. But I do not get any result. No error is seen before the execution. My code is like this:
var apiUrl : String
var alamoFireManager:Manager!
var configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
init(apiUrl : String){
self.apiUrl = apiUrl
configuration.timeoutIntervalForRequest = 30.0
alamoFireManager = Alamofire.Manager(configuration: configuration)
}
print(apiUrl)
alamoFireManager.request(.GET, apiUrl, encoding: .JSON).validate(contentType: ["application/json"]) .responseJSON { response in
print(response.result.value)
switch response.result{
case .Success:
if let value = response.result.value{
let json = JSON(value)
print (json)
callback.onResponse(value) // this is where my value is sent
}
case .Failure(let error):
print(error.localizedDescription)
}
}
I checked using breakpoint and the app directly reaches this last braces frm the alamofire line.
I think the issue is you are not calling resume(). From the Alamofire doc
If the owning manager does not have startRequestsImmediately set to
true, the request must call resume() in order to start.
try this
alamoFireManager.request(.GET, apiUrl, encoding: .json).validate(contentType: ["application/json"]).resume().responseJSON { response in
print(response.result.value)
switch response.result{
case .Success:
if let value = response.result.value{
let json = JSON(value)
print (json)
callback.onResponse(value) // this is where my value is sent
}
case .Failure(let error):
print(error.localizedDescription)
}
}