how to pass value to empty json object in swift using Alamofire - json

I have a api whose body has one dictionary key that is empty value.
Eg. {
"customer_name": "name"
"request_data": {}
}
I am using alamofire for this post request.
I am not able to understand what should i pass as a value to this key when calling the api.
My code:
Network Service -
func KYCRequestWithTemplate(parameters: KYCRequest_WithTemplateModel, completionHandler: #escaping Handler) {
let authorizationValue = "Basic authorization value"
let headers: HTTPHeaders = [
"content-type": "application/json",
"authorization": "\(authorizationValue)"
]
AF.request("url", method: .post, parameters: parameters, encoder: JSONParameterEncoder.default, headers: headers).response { response in
switch response.result {
case .success(let data):
do {
let json = try JSONDecoder().decode(KYCRequest_WithTemplate.self, from: data!)
print(json)
if response.response?.statusCode == 200 || response.response?.statusCode == 201 {
completionHandler(.success(json))
}else {
completionHandler(.failure(.custom(message: "Please check your network connectivity")))
}
}catch {
print(error.localizedDescription)
completionHandler(.failure(.custom(message: "Please try again")))
}
case .failure(let error):
print(error.localizedDescription)
completionHandler(.failure(.custom(message: "Please try again")))
}
}
}
Model :
//for post method
struct KYCRequest_WithTemplateModel: Encodable {
let customer_identifier: String
let customer_name: String
let reference_id: String
let template_name: String
let notify_customer: Bool
let request_details: RequestDetails
let transaction_id: String
let generate_access_token: Bool
}
struct RequestDetails: Codable {
}
Calling API:
I am getting error here. Please help me understand what shall I pass here as a value
let kycTemplateData = KYCRequest_WithTemplateModel(customer_identifier: "\(mobileNo)", customer_name: "\(userName)", reference_id: "id", template_name: "template_name", notify_customer: true, request_details: "**I am getting error here. Please help me understand what shall I pass here as a value**", transaction_id: "id", generate_access_token: true)

Related

Unable to decode JSON data while parsing in swift

I am using generic codable protocol for JSON parsing
below is the JSON structure and postman response
{
"jsonrpc": "2.0",
"result": {
"categories": [
{
"id": 91,
"title": "ADMINISTRATION & SECRETARIAL",
},
{
"id": 62,
"title": "BEAUTY",
},
{
"id": 325,
"title": "CARE",
for above response i have created model like below:
struct CategoryModel: Codable {
let jsonrpc: String?
let result: ResultCat?
}
struct ResultCat: Codable {
let categories: [Categorymine]?
}
struct Categorymine: Codable {
let id: Int?
let title, slug: String?
}
code: in this code i am getting response above switch response.result case and data also getting (11113 bytes).. but here i am unable to decode data i think.. when i call service not getting response
please guide me to get response
first time i am working with generics, where am i wrong. please guide me
import Foundation
import Alamofire
class GeneralResponse<T: Codable>: Codable {
var jsonrpc: String
var result: T?
}
struct RequestObject {
var method: HTTPMethod
var path: String
var token: String?
var params: [String: Any]?
}
class WebService {
private let decoder: JSONDecoder
public init(_ decoder: JSONDecoder = JSONDecoder()) {
self.decoder = decoder
}
public func serviceCall<T: Codable>(_ objectType: T.Type,
with request: RequestObject,
completion: #escaping (GeneralResponse<T>?, Error?) -> Void) {
var headerParams: HTTPHeaders?
AF.request(request.path, method: request.method, parameters: request.params,encoding: JSONEncoding.default, headers: headerParams)
.responseJSON { response in
print("Json response: \(response)")//getting response here as well
switch response.result {
case .success(let dictData):
let JSON = dictData as? [String : Any]
do {
let data = response.data
print("only data \(data)")//Optional(11113 bytes)
let responseData = try self.decoder.decode(GeneralResponse<T>.self, from: data ?? Data())
print("model data \(String(describing: responseData.result))")//Optional(TestigAllInOne.CategoryModel(jsonrpc: nil, result: nil))
} catch {
completion(nil, error)
}
case .failure(let error):
let error = error
print(error.localizedDescription)
}
}
}
}
in console i am getting like this:
only data Optional(11113 bytes)
model data Optional(TestigAllInOne.CategoryModel(jsonrpc: nil, result: nil))
i am using service call in viewcontroller like this:
var catData: CategoryModel? {
didSet {}
}
func genericCall(){
let request = RequestObject(method: .get, path: "https://tt.com/dev/api/get-category", params: nil)
WebService().serviceCall(CategoryModel.self, with: request) { (response, error) in
if let items = response?.result {
print("viewcontroller response \(items)")
DispatchQueue.main.sync {
self.catData = items
self.tableView.reloadData()
}
}
else{
print(error)
}
}
}
Acording to your Model T should be of type ResultCat and not CategoryModel
WebService().serviceCall(ResultCat.self, with: request)
look at your generic class:
class GeneralResponse<T: Codable>: Codable {
var jsonrpc: String
var result: T?
}
so T in this context is the type of the result var.
Edit to address the comment:
if i want to pass whole CategoryModel in serviceCall then how to change my code.
I asume you want to call the function as described in the question. To achieve this simply get rid of your generic struct as you wouldn´t use it in that case.
public func serviceCall<T: Codable>(_ objectType: T.Type,
with request: RequestObject,
completion: #escaping (T?, Error?) -> Void) {
and:
let responseData = try self.decoder.decode(T.self, from: data ?? Data())

Swift - JSON decoding

I have a JSON response from an api call. The problem is I get different JSON responses depending on whether the user has entered the correct credentials or not. My question is how do I read and decode these responses to a useable struct and what is the best way to go about decoding these different responses. one thing I noticed is both response have a common "isSuccess" that may be useful. I have little to no experience with swift or reading JSON so this is all a learning experience for me.
This is the response for successful login
{"result":{"login":{"isAuthorized":true,"isEmpty":false,"userName":{"isEmpty":false,"name":{"firstName":"Jason","lastName":"Test","displayName":"Test, Jason","isEmpty":false,"fullName":"Jason Test"},"canDelete":false,"id":5793,"canModify":false},"username":"test#testable.com"},"parameters":{"isEmpty":false,"keep_logged_in_indicator":false,"username":"test#testable.com"}},"isAuthorized":true,"version":{"major":"2021","minor":"004","fix":"04","display":"2021.004.04","isEmpty":false},"isSystemDown":false,"timestamp":"2021-07-28T02:47:33Z","isSuccess":true}
This is the response for failure
{"isAuthorized":true,"version":{"major":"2021","minor":"004","fix":"04","display":"2021.004.04","isEmpty":false},"isSystemDown":false,"errors":[{"password":"Unable to login as 'test#testable.com'"}],"timestamp":"2021-07-28T02:47:05Z","isSuccess":false}
This is the code I have written for my api calls
func request<T: Decodable>(endPoint: EndPoint, method: Method, parameters: [String: Any]? = nil, completion: #escaping(Result<T, Error>) -> Void) {
// Creates a urlRequest
guard let request = createRequest(endPoint: endPoint, method: method, parameters: parameters) else {
completion(.failure(AppError.invalidUrl))
return
}
let session = URLSession.shared
session.dataTask(with: request) { data, response, error in
var results: Result<Data, Error>?
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
completion(.failure(AppError.badStatusCode))
return
}
if let response = response {
// Gets the JSESSIONID
let cookieName = "JSESSIONID"
if let cookie = HTTPCookieStorage.shared.cookies?.first(where: { $0.name == cookieName }) {
debugPrint("\(cookieName): \(cookie.value)")
}
print(response)
}
if let data = data {
results = .success(data)
// Converts data to readable String
let responseString = String(data: data, encoding: .utf8) ?? "unable to convert to readable String"
print("Server Response: \(responseString.description)")
} else if let error = error {
results = .failure(error)
print("Server Error: \(error.localizedDescription)")
}
DispatchQueue.main.async {
self.handleResponse(result: results, completion: completion)
}
}.resume()
}
private func handleResponse<T: Decodable>(result: Result<Data, Error>?, completion: (Result<T, Error>) -> Void) {
guard let result = result else {
completion(.failure(AppError.unknownError))
return
}
switch result {
case .success(let data):
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print("Server JsonObject response: \(json)")
} catch {
completion(.failure(AppError.errorDecoding))
}
let decoder = JSONDecoder()
// Decodes that json data
do {
} catch {
}
case .failure(let error):
completion(.failure(error))
}
}
Im mostly interesting in being able to display the json error that occurs when credentials are incorrect. The deadline for my project Is slowing approaching and any help or suggestions would be much appreciated.
You can use Swift's Result type to differentiate a successful result from a failed result.
The Result type is not decodable by default so you will need to write a custom decoder like this:
struct Response: Decodable {
let result: Swift.Result<Result, Errors>
enum CodingKeys: String, CodingKey {
case isSuccess
case errors
case result
}
struct Result: Codable {
let login: Login
struct Login: Codable {
let isAuthorized: Bool
}
}
struct Errors: Error {
let contents: [[String: String]]
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if try container.decode(Bool.self, forKey: .isSuccess) {
result = .success(try container.decode(Result.self, forKey: .result))
} else {
result = .failure(
Errors(contents: try container.decode([[String: String]].self, forKey: .errors))
)
}
}
}

Value of type 'Result<Any, AFError>' has no member 'value' JSON

Does anyone knows how to solve this bug? By the way, I'm a beginner, be kind!
AF.request(URL_LOGIN, method: .post, parameters: body, encoding: JSONEncoding.default, headers: header).responseJSON { (response) in
if response.result.erro == nil {
if let json = response.result.erro as? Dictionary<String, Any> {
if let email = json["user"] as? String {
self.userEmail = email
}
if let token = json["token"] as? String {
self.authToken = token
}
}
self.isLoggedIn = true
completion(true)
} else {
completion(false)
debugPrint(response.result.error as Any)
enter image description here
First of all check your spelling, erro is pointless.
According to the error the value for result is Result<Any, AFError>, Result is an enum with associated types and two cases: success and failure
The syntax must be something like
AF.request(URL_LOGIN, method: .post, parameters: body, encoding: JSONEncoding.default, headers: header).responseJSON { (response) in
switch response.result {
case .success(let result):
if let json = result as? Dictionary<String, Any> {
if let email = json["user"] as? String {
self.userEmail = email
}
if let token = json["token"] as? String {
self.authToken = token
}
}
self.isLoggedIn = true
completion(true)
case .failure(let error):
completion(false)
debugPrint(error)
}
}
The logic is not very logic. I'm sure that self.isLoggedIn is not supposed to be true if email and token are invalid and should be set to false when an error occurs.

How should I go about parsing a JSON response from an API with Alamofire and SwiftyJSON?

I am trying to parse a JSON from an API using Alamofire and SwiftyJSON, but am having trouble trying to access the information in the JSON. I need to simply parse the JSON for an item called "ask_price": and also "time_coinapi" but I am not sure how I manage the response, or if I have to use a different method. here is what I have at the moment:
class CoinAPIManager {
var prices: [String] = []
var times: [String] = []
static let shared = CoinAPIManager()
func getReq() {
let headers: HTTPHeaders = [
"X-CoinAPI-Key": "Key"
]
Alamofire.request("https://rest.coinapi.io/v1/quotes/BITSTAMP_SPOT_BTC_USD/history?time_start=2018-08-21T00:00:00&time_end=2018-08-22T00:00:00&limit=100", headers: headers).responseJSON { response in
debugPrint(response)
if let data = try? String(contentsOf: response) {
let json = JSON(parseJSON: data)
parse(json: json)
}
}
func parse(json: JSON) {
for result in json[].arrayValue {
let price = result["ask_price"].stringValue
}
}
}
}
and I have also tried this:
func getReq() {
let headers: HTTPHeaders = [
"X-CoinAPI-Key": "Key"
]
Alamofire.request("https://rest.coinapi.io/v1/quotes/BITSTAMP_SPOT_BTC_USD/history?time_start=2018-08-21T00:00:00&time_end=2018-08-22T00:00:00&limit=100", headers: headers).responseJSON { response in
debugPrint(response)
switch response.result {
case .failure(let error):
// Do whatever here
return
case .success(let data):
// First make sure you got back a dictionary if that's what you expect
guard let json = data as? [String : AnyObject] else {
print("Failed to get expected response from webserver.")
return
}
// Then make sure you get the actual key/value types you expect
guard var price = json["ask_price"] as? Double else {
print("Failed to get data from webserver")
return
}
}
What am I doing wrong? this is how the JSON looks:
[
{
"symbol_id": "BITSTAMP_SPOT_BTC_USD",
"time_exchange": "2013-09-28T22:40:50.0000000Z",
"time_coinapi": "2017-03-18T22:42:21.3763342Z",
"ask_price": 770.000000000,
"ask_size": 3252,
"bid_price": 760,
"bid_size": 124
},
{
"symbol_id": "BITSTAMP_SPOT_BTC_USD",
"time_exchange": "2013-09-28T22:40:50.0000000",
"time_coinapi": "2017-03-18T22:42:21.3763342",
"ask_price": 770.000000000,
"ask_size": 3252,
"bid_price": 760,
"bid_size": 124
}
]
previous question deleted and reposted due to large mistake
you need to change your response to SwiftyJSON object like this
Alamofire.request("https://rest.coinapi.io/v1/quotes/BITSTAMP_SPOT_BTC_USD/history?time_start=2018-08-21T00:00:00&time_end=2018-08-22T00:00:00&limit=100", headers: headers).responseJSON { response in
debugPrint(response)
switch response.result {
case .failure(let error):
// Do whatever here
return
case .success:
// First make sure you got back a dictionary if that's what you expect
let responseJSON = JSON(response.result.value!)
if responseJSON.count != 0 {
print(responseJSON)
//do whatever you want with your object json
}
}
}
i suggest in your ApiManager you can use completion blocks to manage asyncronous request, check the next code.
class func getRequestWithoutParams(didSuccess:#escaping (_ message: JSON) -> Void, didFail: #escaping (_ alert:UIAlertController)->Void){
Alamofire.request("http://foo.bar"),method: .post,parameters: parameters,encoding: JSONEncoding.default,headers:nil).responseJSON { response in
switch response.result{
case .success:
let res = JSON(response.result.value!)
didSuccess(res)
break
case .failure(let error):
let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
let done = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(done)
didFail(alert)
}
}
}
From Swift 4, you should be able to use codable to solve it:
struct YourStructure: Codable {
let symbol_id: String?
let time_exchange: String?
let ask_price: String?
private enum CodingKeys: String, CodingKey {
case symbol_id = "symbol_id"
case time_exchange = "time_exchange"
case ask_price = "ask_price"
}
}
And then parse it with JSONDecoder
let decoder = JSONDecoder()
let parsedData = decoder.decode(YourStructure.self, from: "YourJsonData")

How to connect http server using Swift and Alamofire

Hi I new at swift and I got problem with server connection. I am trying to make request using a method post to login to server using username and password. How I can connect to the server and authentificate?
error messsage:
["id": <null>, "error": {
code = "-32700";
message = "Parse error";
}, "jsonrpc": 2.0]
Code:
class ViewController: UIViewController {
override func viewDidLoad() {
var userName = "root"
var password = "admin01"
// http://192.168.1.1/ubus
//var LOGIN_TOKEN = 0000000000000000
let url: String = "http://192.168.1.1/ubus"
let param: [String: Any] = ["username": "admin", "password": "admin01", "token": "0000000000000000"]
Alamofire.request(url, method: .post, parameters: param,
encoding: JSONEncoding.default)
.responseJSON { response in
guard response.result.error == nil else {
// got an error in getting the data, need to handle it
print("error calling post")
print(response.result.error!)
return
}
// make sure we got some JSON since that's what we expect
guard let json = response.result.value as? [String: Any] else {
print("didn't get todo object as JSON from API")
print("Error: \(response.result.error)")
return
}
print(json)
}
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
Json at server which I need to get:
{"jsonrpc":"2.0","id":1,"result":[0,{"ubus_rpc_session":"07e111d317f7c701dc4dfde1b0d4862d","timeout":300,"expires":300,"acls":{"access-group":{"superuser":["read","write"],"unauthenticated":["read"]},"ubus":{"*":["*"],"session":["access","login"]},"uci":{"*":["read","write"]}},"data":{"username":"root"}}]}
Request should look like:
"{ \"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"call\", \"params\": [ \"00000000000000000000000000000000\", \"session\", \"login\", { \"username\": \"root\", \"password\": \"admin01\" } ] }"
Try to use this code:
Alamofire.request(url, method: .post, parameters: parameters).responseJSON { response in
if(response.result.isFailure){
print("no data!");
}else{
print("received data!");
// make sure we got some JSON since that's what we expect
guard let json = response.result.value as? [String: Any] else {
print("didn't get todo object as JSON from API")
print("Error: \(response.result.error)")
return
}
print(json)
}
}