Hello everyone I want to crate a base api service for my apps but when I try a lot of different way but i can't solve my problems. I have to use alamofire, promiseKit and generic's.
My first solution and his issue: I can get my json from api but when I try to decode my json every time it fails. There is the code:
func fetchData<T: Codable>(_ page: Int) -> Promise<T> {
let path = getPath(page)
return Promise<T> { seal in
AF.request(path, method: .get).validate(statusCode: 200..<300).responseString { response in
switch response.result {
case .success(let data):
if let json = data.data(using: .utf8) {
do {
let res = try JSONDecoder().decode(T.self, from: json)
print(res)
seal.fulfill(res)
} catch {
print("json serilaztion error")
print(error)
seal.reject(error)
}
}
case .failure(let error):
seal.reject(error)
}
}
}
}
My second solution and issue : When I do my request I get my json response and decode it but in this solution I can't return data with seal.fulfill(data) gives me "Cannot convert value of type 'Any' to expected argument type 'T'" and when I try to seal.fulfill(data as! T) like this when I run app always crashes. There is my code :
func fetchData<T: Codable>(_ page: Int) -> Promise<T> {
let path = getPath(page)
return Promise<T> { seal in
AF.request(path, method: .get).validate(statusCode: 200..<300).responseJSON { response in
switch response.result {
case .success(let data):
seal.fulfill(data as! T) // Cannot convert value of type 'Any' to expected argument type 'T'
case .failure(let error):
seal.reject(error)
}
}
}
}
Finally I'm using test api https://www.flickr.com/services/api/explore/flickr.photos.getRecent to test my code. How I can solved this issue's ? Thanks for your helps
Use responseDecodable instead of responseString or responseJSON.
AF.request(...).responseDecodable(of: T.self) { response in
...
}
Related
I've been working on API requests using Alamofire, and I want to know something for parsing the Error and to get the JSON data from the server instead of accessing the AFErrors. The code below works fine, but since I've been using .responseDecodable for decoding the response and also the MyError inherits Decodable, I was wondering if there is a similar way to decode data when I get the error response back, instead of using JSONDecoder().decode.
When I get the error response, it returns a JSON object with one value in it (message) from the server.
static let sessionManager: Session = {
let configuration = URLSessionConfiguration.af.default
configuration.timeoutIntervalForRequest = 30
return Session(configuration: configuration)
}()
Request.sessionManager.request(endpoint, method: httpMethod, parameters: params, headers: headers)
.responseDecodable(of: resDecodeType.self) { response in
switch response.result {
case .success(let successResponse):
completed(.success(successResponse))
case .failure(let error):
let errorStatusCode = response.response?.statusCode
do {
let data = try JSONDecoder().decode(MyError.self, from: response.data!) // -> this part...
} catch {
print(error)
}
}
}
}
struct MyError: Decodable {
let message: String
}
I'm trying to decode the json data after fetching json with alamofire. I have created the model class but i don't understand how to decode the data.
Alamofire.request("http://somerandomlink.xyz").responseJSON { (response) in
switch response.result {
case .failure(let error):
print(error)
case .success(let data):
do {
//print(response)
print("data: \(data)")
} catch let error {
print(error)
}
}
}
Model
struct LoremIpsum: Codable {
let var1: String
let var2: String
let var3: String
}
Alamofire has been updated to use Codable objects natively.
Use:
.responseDecodable(of: LoremIpsum.self) {
Instead of:
.responseJSON {
You can also use .responseData instead of responseJSON and then in the success case you can try decoding using JSONDecoder as follows:
let decoder = JSONDecoder()
do {
let users = try decoder.decode(LoremIpsum.self, from:data)
print("Users list :", users)
} catch {
print(error)
}
guard let users = try? JSONDecoder().decode(LoremIpsum.self, from: response) else {
return
}
I'm using JSONRPCKit lib, so there's final request contains that Request
let request1 = RPCRequest(params: SomeParams)
let batch1 = batchFactory.create(request1)
let httpRequest1 = MyServiceRequest(batch: batch1)
Session.send(httpRequest1){ result in
switch result {
case .success(let auth):
let gson = JSON(auth)
print(gson)
case .failure(let error):
print("Error: ", error)
}
}
I have to make a lot of requests like this. So i want to make it Generic to keep reuse it not typing everything again.
Could you please help me?
Just create a generic method which wraps these code inside something like this,
func sendRequest<T>(request: RCPRequest,
mapping: #escaping (JSON) throws -> T,
completion: #escaping (T?, Error?) -> Void) {
let batch = batchFactory.create(request)
let httpRequest = MyServiceRequest(batch: batch)
Session.send(httpRequest){ result in
switch result {
case .success(let auth):
let gson = JSON(auth)
do {
let output = try mapping(gson)
completion(output, nil)
} catch {
completion(nil, error)
}
case .failure(let error):
completion(nil, error)
}
}
}
Then call it like this,
let request1 = RPCRequest(params: SomeParams)
sendRequest(request: request1,
mapping: { json in
// convert from json to the custom type T, whatever T is
// throw error if something isnt right in json
},
completion: { output, error in
if let output = output {
}
})
I've tried to implement JSON Parsing in my App to see the latest Wordpress Posts from my website.
Now i have the following error:
"Contextual type for closure argument list expects 1 argument, but 3 were specified"
The "Problem Code"
func getPosts(getposts : String)
{
Alamofire.request(.GET, getposts, parameters:parameters)
.responseJSON { request, response, result in
switch result
{
case .Success(let data):
self.json = JSON(data)
self.tableView.reloadData()
case .Failure(let error):
print("Request failed with error: \(error)")
}
}
}
Hope you can help me (:
Best regards!
I Got it !
func getPosts(getposts : String)
{
Alamofire.request(.GET, getposts, parameters:parameters)
.responseJSON { response in
guard let data = response.result.value else{
print("Request failed with error")
return
}
self.json = JSON(data)
self.tableView.reloadData()
}
}
Simple code which takes Base URL and Parameter to service and method type.
Alamofire.request(.POST, "http://www.abc.cpm", parameters: ["consumer_key": "fnfkdkdndf"]).responseJSON { response in
print(response)
}
So I want to send a request to a specific API which is supposed to return a JSON file.
I am using Alamofire in order to get the JSON object :
dataFromAPI : JSON
Alamofire.request(.GET, myURL).responseJSON { (_, _, data) -> Void in
dataFromAPI = JSON(data)
}
My problem is that data is an array of AnyObject and the JSON function needs an AnyObject type. How can I transform one into another or resolve the problem ?
Not sure if I got your question, but will try to provide you an example of how I do it.
Changed code to your case.
Alamofire.request(.GET, myURL)
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.responseJSON { request, response, jsonResult in
switch jsonResult {
case .Success:
if let data = jsonResult.value as? AnyObject {
self.dataFromAPI = JSON(data)
}
case .Failure(_, let error):
print(error)
}
}
Normally I wouldn't do unwrapping to AnyObject, as it makes little sense.
I usually unwrap to [String: AnyObject] as I'm expecting Dictionary from my API, and then I attempt to convert it to my custom model class.
Correct me if I miss-understood the question. :)
Alamofire returns a Result<AnyObject> object. You should check if the result is a success or a failure before extracting the JSON:
Alamofire.request(.GET, myURL)
.responseJSON { request, response, result in
switch result {
case .Success(let JSON):
print("Success with JSON: \(JSON)")
case .Failure(let data, let error):
print("Request failed with error: \(error)")
if let data = data {
print("Response data: \(NSString(data: data, encoding: NSUTF8StringEncoding)!)")
}
}
}