I have defined the parameters to pass to rapidAPI using Alamofire, but I've got an error.
I followed everything they said in the API documentation. If I put the full URL into a string it works fine, but when I pass as a parameter it doesn't
import UIKit
import Alamofire
import SwiftyJSON
class ViewController: UIViewController {
let CURRENT_BR_LEAGUE_URL = "https://api-football-v1.p.rapidapi.com/v2/leagues/country/"
override func viewDidLoad() {
super.viewDidLoad()
let params = ["country_name" : "england", "season" : "2018"]
getLeague(url: CURRENT_BR_LEAGUE_URL, parameters: params)
}
func getHeaders() -> [String : String] {
let headers = [
"X-RapidAPI-Host": "api-football-v1.p.rapidapi.com",
"X-RapidAPI-Key": "xxxxxxxxxxxxxxxxxxx"
]
return headers
}
func getLeague (url : String, parameters : [String : String]) {
Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding(destination: .queryString), headers: getHeaders()).responseJSON {
response in
if response.result.isSuccess {
let leagueJSON : JSON = JSON(response.result.value!)
print(leagueJSON)
print()
}
else {
}
}
}
}
It throws a "wrong country" error. If I use full URL
let CURRENT_BR_LEAGUE_URL = "https://api-football-v1.p.rapidapi.com/v2/leagues/country/england/2018" it works fine.
If I use "https://api-football-v1.p.rapidapi.com/v2/leagues/country/"
and set the parameters
let params = ["country_name" : "england", "season" : "2018"]
it does not work
In Your Code, you are making a get request. So you have to pass the params bind with your base URL. Please try the below code hopefully it will work for you.
class ViewController: UIViewController {
let CURRENT_BR_LEAGUE_URL = "https://api-football-v1.p.rapidapi.com/v2/leagues/country/%#/%#"
override func viewDidLoad() {
super.viewDidLoad()
let params = ["country_name" : "england", "season" : "2018"]
let urlString = String(format: CURRENT_BR_LEAGUE_URL, params["country_name"],params["season"])
getLeague(url: urlString, parameters: nil)
}
func getHeaders() -> [String : String] {
let headers = [
"X-RapidAPI-Host": "api-football-v1.p.rapidapi.com",
"X-RapidAPI-Key": "xxxxxxxxxxxxxxxxxxx"
]
return headers
}
func getLeague (url : String, parameters : [String : String]?) {
Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding(destination: .queryString), headers: getHeaders()).responseJSON {
response in
if response.result.isSuccess {
let leagueJSON : JSON = JSON(response.result.value!)
print(leagueJSON)
print()
}
else {
}
}
}
}
As I looked now into RapidApi documentation for API-Football, you don't need the parameters. You just need to construct the URL from different parts and then make a GET request.
class ViewController: UIViewController {
let MAIN_URL = "https://api-football-v1.p.rapidapi.com/v2/leagues/country/"
override func viewDidLoad() {
super.viewDidLoad()
getLeague(for: "england", year: 2018)
}
func getHeaders() -> [String : String] {
let headers = [
"X-RapidAPI-Host": "api-football-v1.p.rapidapi.com",
"X-RapidAPI-Key": "xxxxxxxxxxxxxxxxxxx"
]
return headers
}
func getLeague (for country : String, year: Int) {
let url = MAIN_URL + country + "/\(year)/"
Alamofire.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: getHeaders()).responseJSON {
response in
if response.result.isSuccess {
let leagueJSON : JSON = JSON(response.result.value!)
print(leagueJSON)
print()
}
else {
}
}
}
}
Related
if let vendorId = vendor?.id {
APIManager.shared.getProducts(vendorId: vendorId, completionHandler: { (json) in
if json != nil { <<<<<<<<<Comparing non-optional value of type 'JSON' to 'nil' always returns true
self.products = []
if let tempProducts = json["products"].array {
for item in tempProducts {
let product = Product(json: item)
self.products.append(product)
}
self.tableView.reloadData()
Helpers.hideActivityIndicator(self.activityIndicator)
}
}
})
}
}
In My APIManager.swift
import Foundation
import Alamofire
import SwiftyJSON
import FBSDKLoginKit
class APIManager {
static let shared = APIManager()
let baseURL = NSURL(string: BASE_URL)
var accessToken = ""
var refreshToken = ""
var expired = Date()
// Request Server Function
func requestServer(method: Alamofire.HTTPMethod , path: String, params: [String: AnyObject]?, encoding: ParameterEncoding, completionHandler: #escaping (JSON?) -> Void ) {
let url = baseURL?.appendingPathComponent(path)
refreshTokenIfNeed {
AF.request(url!, method: method, parameters: params, encoding: encoding, headers: nil).responseJSON{ response in
switch response.result {
case .success(let value):
let jsonData = JSON(value)
completionHandler(jsonData)
break
case .failure:
completionHandler(nil)
break
}
}
}
}
// API - Getting the latest order (Customer)
func getLatestOrder(completionHandler: #escaping (JSON) -> Void) {
let path = "api/customer/order/latest/"
let params: [String: Any] = [
"access_token": self.accessToken
]
requestServer(method: .get, path: path, params: params as [String : AnyObject], encoding: URLEncoding()) { (json) in
print(json!)
}
}
}
as json is non optional in your case, comparing it with nil will always return true.
You simply cannot compare it with nil.
If you expect it to be nil, then it should be optional.
If you are sure that it will never be nil, let it be like it is now, just remove the if condition. But be aware that if it goes nil during runtime it would cause crash.
I have an admin panel which admin can insert question and gives 3 options of answers to users to choose. The admin is able to insert questions according to different chapters...its like a quiz game..The correct answer is then given an int value so in my collection of 3 buttons, I am able to know which is the correct button user has chosen. But now my problem is, in my Postman:
in my swift code
func getaQuestionaByaChapter(chapterName: String,question: String, answer1: String, answer2 : String, answer3: String, answer: Int, completion: #escaping (JSON?, Error?) -> Void) {
let parameters: [String : Any] = [
"secret_key" : "b3370e1590a2cf2b430e8cf8a8b361bd",
"_action" : "GETQUESTIONBYCHAPTER",
"GETQUESTIONBYCHAPTER" : chapterName,
"question" : question,
"option1" : answer1,
"option2" : answer2,
"option3" : answer3,
"answer" : answer
]
is this a declaration correct?
as for my storyboard:
and after this, i would be doing
button1.setTitle = answer1
questionlabel.text = question
in my swift file for the part where i link my API
import SwiftyJSON
import Alamofire
public class EduappRestClient {
enum ContentType: String {
case json = "application/json"
case jpeg = "image/jpeg"
case formEncoded = "application/x-www-form-urlencoded"
case none = "" //Content type will be empty
}
private static let url: URL = URL(string: "http://192.168.0.127:81/project/Online_Question/API/actiona")! //NSURL depreciated now using URL)
//singleton
static let sharedClient: EduappRestClient = EduappRestClient()
class func request(with url: URL,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
contentType: ContentType = .json,
encoding: ParameterEncoding = JSONEncoding.default,
additionalHeaders: [String: String] = [:],
completion: #escaping(JSON?, Error?) -> Void
) {
//MARK: Configure Headers
var headers: [String: String] = [:]
//if contenttype is specified as none type, leave content-type header field empty
if contentType != .none {
headers["Content-Type"] = contentType.rawValue
}
for (key, value) in additionalHeaders {
headers[key] = value
}
Alamofire.request(url, method: method, parameters: parameters, encoding: encoding, headers: headers).responseJSON(completionHandler: { (response) in
guard response.result.error == nil, let value = response.result.value else {
completion(nil, response.result.error)
return
}
let jsonData = JSON(value)
completion(jsonData, nil)
})
}
//MARK: - Getting questions by chapters
func getaQuestionaByaChapter(chapterName: String,question: String, answer1: String, answer2 : String, answer3: String, answer: Int, completion: #escaping (JSON?, Error?) -> Void) {
let parameters: [String : Any] = [
"secret_key" : "b3370e1590a2cf2b430e8cf8a8b361bd",
"_action" : "GETQUESTIONBYCHAPTER",
"GETQUESTIONBYCHAPTER" : chapterName,
"question" : question,
"option1" : answer1,
"option2" : answer2,
"option3" : answer3,
"answer" : answer
]
let URLString = EduappRestClient.url
EduappRestClient.request(with: URLString, method: .post, parameters: parameters) { (json, error) in
guard error == nil, let json = json else {
completion(nil, error)
return
}
let result: JSON = json[1]
//result will print
//"question": [
// {
//"question": "10+10",
//"chapter_name": "Chapter 2",
//"option1": "10",
//"option2": "20",
//"option3": "30",
//"answer": "20"
//}
//]
completion(result, nil)
}
}}
it will show my data accordingly??
After API response, you have to use.
class QuestionModel: Codable {
let questions: [Details]
}
class Details: Codable {
let question: String?
let chapter_name: String?
let option1: Int?
let option2: Int?
let option3: Int?
}
And after this, you have to parse the response in the model data:
func getaQuestionaByaChapter(chapterName: String, completion: #escaping (QuestionModel?, Error?) -> Void) {
let parameters: [String : Any] = [
"secret_key" : "b3370e1590a2cf2b430e8cf8a8b361bd",
"_action" : "GETQUESTIONBYCHAPTER",
"GETQUESTIONBYCHAPTER" : chapterName
]
let URLString = EduappRestClient.url
EduappRestClient.request(with: URLString, method: .post, parameters: parameters) { (json, error) in
guard error == nil, let json = json else {
completion(nil, error)
return
}
do {
let jsonData = try JSONSerialization.data(withJSONObject: json, options: JSONSerialization.WritingOptions.prettyPrinted)
let result = try JSONDecoder().decode(QuestionModel.self, from: jsonData)
completion(result, nil)
} catch let message {
print("JSON serialization error:" + "\(message)")
}
}
}}
Then in QuizViewController: You have to set the data:
EduappRestClient.sharedClient.getaQuestionaByaChapter(chapterName: "Chapter 2", completion: { (response, error) in
//json is the result from rest client
let firstQuestion = response?.questions.first
self.questionsLabel.text = firstQuestion?.question
self.answerButtons.setTitle("\(firstQuestion?.option1)", for: UIControlState.normal)
self.answerButtons.setTitle("\(firstQuestion?.option2)", for: UIControlState.normal)
self.answerButtons.setTitle("\(firstQuestion?.option3)", for: UIControlState.normal)
})
I have this JSON data to parse :
{
"data": {
"user_name": "JohP llDoe",
"email_address": "tozto#gmail.com"
},
"result": {
"code": 0
}
}
The data type change from a web-service to another, but the general structure is always the same.
So I create this general Class using EVReflection to parse the Data :
class MyResponse<T>: EVObject {
var data : T?
var result : Result?
}
class Result: EVObject {
var message : String = ""
var code : Int = 0
}
and for the Data :
class Preaccount : EVObject {
public var user_name : String = ""
public var email_address : String = ""
}
And to call the web-service I created this method :
Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers)
.responseObject { (response: DataResponse<MyResponse<Preaccount>>) in
if response.result.isSuccess {
print(response.result.value!)
}
if response.result.isFailure {
let error : Error = response.result.error!
}
}
And now I'am having a bad access :
Is there a way to create a generic method and pass the parsed model in parameters.
you can try this
class MyResponse: EVObject {
var data : Preaccount?
var result : Result?
}
and to process response data
Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers)
.responseObject { (response: DataResponse) in
if response.result.isSuccess {
print(response.result.value!)
var myResponse = MyResponse(json:response.result.value!)
}
.......
}
Finally here is my solution for the problem :
struct MyResponse<T: Decodable>: Decodable {
var data : T?
var result : Result?
}
struct Result: Decodable {
let message : String?
let code : Int
let form_errors : [String: [String]]?
}
struct Preaccount : Decodable {
let user_name : String
let email_address : String
}
And to call the web service :
func postRequest<T: Decodable>(url: String,
params : [String: Any]?,
returnType : T.Type)
{
Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers)
.responseDecodableObject { (response: DataResponse<FindoorResponse<T>>) in
//...
}
}
And here is an example to call the method :
AlamofireHelper.shared().postRequest(url: CHECK_USERNAME_URL, params: parameters, returnType: Preaccount.self)
I'd recommend using Decodable instead:
struct MyResponse<T: Decodable>: Decodable {
let data: T?
let result: Result?
}
struct Result: Decodable {
var message: String?
var code: Int
}
struct Preaccount: Decodable {
let user_name: String
let email_address: String
}
let data = """
{
"data": {
"user_name": "JohP llDoe",
"email_address": "tozto#gmail.com"
},
"result": {
"code": 0
}
}
""".data(using: .utf8)!
let result = try? JSONDecoder().decode(MyResponse<Preaccount>.self, from: data)
I'm using Swift 3 and Alamofire 4.0.
I want to create similar Alamofire POST request as Postman request shown in screenshot:
I've tried with these lines of code:
var parameters: [String: Any] = [
"client_id" : "xxxxxx",
"client_secret" : "xxxxx",
"device_token" : "xxxx",
"fullname" : "xxxxx",
"gender": "xxx"
]
Alamofire.request(url, method: .post, parameters: parameters).responseJSON { response in
print(response)
}
But I got this error:
How to implement POST request with Body as form-data using Alamofire in Swift 3?
Swift 3.0 - Alamofire - Working code for multipart form data upload *
// Parameters
let params: [String : String] =
["UserId" : "\(userID)",
"FirstName" : firstNameTF.text!,
"LastName" : lastNameTF.text!,
"Email" : emailTF.text!
]
// And upload
Alamofire.upload(
multipartFormData: { multipartFormData in
for (key, value) in params
{
multipartFormData.append((value.data(using: .utf8))!, withName: key)
}
},
to: url,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
upload.uploadProgress(queue: DispatchQueue(label: "uploadQueue"), closure: { (progress) in
})
case .failure(let encodingError):
print(encodingError)
}
}
)
Let me know if you still have issues with it.
after too much try I have succeded so try this
override func viewDidLoad() {
super.viewDidLoad()
let parameters: Parameters = ["client_id": "1","user_token":"xxxxxxxx"]
// Do any additional setup after loading the view, typically from a nib.
let url = "http://xxxxxxxxxxx/index.php/Web_api/get_client_profile"
//let timeParameter = self.getLastTimeStamp()
self.request = Alamofire.request(url, method: .post, parameters:parameters)
if let request = request as? DataRequest {
request.responseString { response in
//PKHUD.sharedHUD.hide()
do{
let dictionary = try JSONSerialization.jsonObject(with: response.data!, options: JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary
print(dictionary)
}catch{
}
}
}
}
var request: Alamofire.Request? {
didSet {
//oldValue?.cancel()
}
}
You can post a request using Alamofire.
let url = ""
let headers = [ "Content-Type" : "application/json"]
let para : Parameters = [ "data" : JSONObject]
Alamofire.request(url, method: .post, parameters: para, encoding: JSONEncoding.default, headers : headers)
.responseJSON { response in
print(response)
print(response.result)
}
Nothing to worry about.
Alamofire request method not changed so much(For Swift 3.0) if in case you know how to do that in Swift 2.0/2.2. If you understand the old method then you can easily understand this one also. Now lets take a closer look on the following boilerplate -
Alamofire.request(apiToHit, method: .post, parameters: parametersObject, encoding: JSONEncoding.default, headers: headerForApi).responseJSON { response in switch response.result{
case .success(_):
if let receivedData: Any = response.result.value{
if let statusCode: Int = response.response?.statusCode {
//Got the status code and data. Do your data pursing task from here.
}
}else{
//Response data is not valid, So do some other calculations here
}
case .failure(_):
//Api request process failed. Check for errors here.
}
Now here in my case -
apiToHit //Your api url string
.post //Method of the request. You can change this method as per you need like .post, .get, .put, .delete etc.
parametersObject // Parameters needed for this particular api. Same in case you are sending the "body" on postman etc. Remember this parameters should be in form of [String: Any]. If you don't need this then you can just pass nil.
JSONEncoding.default //This the encoding process. In my case I am setting this as .default which is expected here. You can change this to .prettyPrinted also if you need.
headerForApi //This is the header which you want to send while you are requesting the api. In my case it is in [String: String] format. If you don't need this then you can just pass nil.
.responseJSON //Expecting the response as in JSON format. You can also change this as you need.
Now, in my request I am using Switch inside the request closure to check the result like response in switch response.result{.
Inside case .success(_): case I am also checking for result data and http status code as well like this
if let receivedData: Any = response.result.value{
if let statusCode: Int = response.response?.statusCode {
}
}
Hope this helped. Thanks.
class func alamofireMethod(methods: Alamofire.HTTPMethod , url : URLConvertible , parameters : [String : Any],need_flag_inside : Bool = false, paramJson : Bool = true ,need_loader : Bool = true,Header: [String: String],handler:#escaping CompletionHandler,errorhandler : #escaping ErrorHandler)
{
if NetworkController.sharedInstance.checkNetworkStatus()
{
var alamofireManager : Alamofire.SessionManager?
var hed = Header
if let tok = UserDefaults.standard.value(forKey: "TOKEN") as? String {
hed = ["Authorization":"Bearer \(tok)"]
}
if need_loader {
// DELEGATE.showLoader()
}
var UrlFinal = ""
do
{
try UrlFinal = baseURL + url.asURL().absoluteString
}
catch{}
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForResource = 25
configuration.timeoutIntervalForRequest = 25
configuration.httpAdditionalHeaders = hed
alamofireManager = Alamofire.SessionManager(configuration: configuration)
alamofireManager = Alamofire.SessionManager.default
let json = JSON(parameters)
guard let jsonDict = json.dictionaryObject else {
return
}
var jsonData = Data()
do {
jsonData = try JSONSerialization.data(withJSONObject: jsonDict, options: [])
} catch {
//handle error
print(error)
}
var request = URLRequest(url: URL(string: UrlFinal)!)
request.httpMethod = methods.rawValue
if methods == .post || methods == .put
{
//check here
if paramJson {
hed["Content-Type"] = "application/json"
request.httpBody = jsonData
}else{
let postString = self.getPostString(params: parameters)
request.httpBody = postString.data(using: .utf8)
}
}
request.allHTTPHeaderFields = hed
Alamofire.request(request).responseJSON(queue: nil, options: JSONSerialization.ReadingOptions.allowFragments) { (response) in
print(parameters)
print(UrlFinal)
print(hed)
// DELEGATE.hideLoader()
if response.result.isSuccess
{
print(response)
handler(response.result.value! as AnyObject)
}
else if response.response?.statusCode == 401
{
// DELEGATE.redirectToLogin()
// DELEGATE.showToast(message: "Token Expired")
}
else{
// DELEGATE.showToast(message: default_failure)
errorhandler(response.result.error! as NSError)
print(response.result.error as Any)
}
}
}else{
// DELEGATE.showToast(message: "Please check your internet connection.")
}
}
Alomofire With Post and Put Method In swift
I'm reading Design+Code course and Ihave 2 files:
DNService.swift
StoriesTableViewController.swift
Form the DNService I'm loading data from DesignerNews API, here is the function who get the data :
static func storiesForSection(section: String, page: Int, response: (JSON) ->()) {
let urlString = baseURL + ResourcePath.Stories.description + "/" + section
let parameters = [
"page": String(page),
"client_id": clientID
]
Alamofire.request(.GET, urlString, parameters: parameters).responseJSON { (response) -> Void in
let swiftyData = JSON(response.result.value ?? [])
//print(swiftyData)
}
}
In the StoriesTableViewController, I call the function storiesForSection() but it don't retrieve the data :
var stories: JSON! = []
func loadStories(section: String, page: Int) {
DNService.storiesForSection(section, page: page) { (JSON) -> () in
self.stories = JSON["stories"]
self.tableView.reloadData()
}
}
I don't know how to fill self.stories in my StoriesTableViewcontroller...
I tried to store swiftyData in a var of DNService and make a getStoredSwiftyData() in StoriesTableViewCtler but it doesn't works too.
storiesForSection:page:response has a callback function, just call it with the JSON object as parameter.
Alamofire.request(.GET, urlString, parameters: parameters).responseJSON { (response) -> Void in
let swiftyData = JSON(response.result.value ?? [])
response(swiftyData)
}
//Swift4
import Alamofire
//only Getting Data from .get methods After getting data you can convert it into your suitable formate
let url2:URL=URL(string: values)!
Alamofire.request(url2).response
{ response in
if(response.data != nil)
{
}
else{
print(response.error)
}
}