Swift get value body from Post Json method - json

I try to Post Json with alamofire, which I can, but I need a value that I get from the result of that successful API post. how do I get value from post method JSON in swift? i use Alamofire to make things simple.
{
"phoneNum": "+1234566869",
"phoneNumTarget": "+2345687960",
"id": "79999000"
}
so this is the body parameter for my Post JSON,
and this is the result of a successful post JSON
{
"data": {
"orderId": "79999000",
"uniquesRoomId": 12341414,
"users": [
{
"avatar_url": "https:// some web",
"phone_number": "085858490282",
"fullname": "BuzzLightyear"
},
{
"avatar_url": "https:// some web",
"phone_number": "085858490282",
"fullname": "General Zurg"
}
],
"chat_name": "user2"
},
"message": "room has been successfully created",
"success": true
}
Now I want to retrieve all the value that I get from that post Json method, how do I do it? do I need to make a struct first like when I want to make get method request for JSON?
*update question
let data : [DataClass] = [ ]
AF.request(web, method: .post, parameters: chataja,encoder:
JSONParameterEncoder.default).responseJSON { (response) in
switch (response.result) {
case.success :
self.data = response
break
i try for this and it getting some error

You need to parse this response through Decodable confirmed structs
import Foundation
// MARK: - User
struct User: Codable {
let data: DataClass
let message: String
let success: Bool
}
// MARK: - DataClass
struct DataClass: Codable {
let orderID: String
let uniquesRoomID: Int
let users: [UserElement]
let chatName: String
enum CodingKeys: String, CodingKey {
case orderID = "orderId"
case uniquesRoomID = "uniquesRoomId"
case users
case chatName = "chat_name"
}
}
// MARK: - UserElement
struct UserElement: Codable {
let avatarURL: String
let phoneNumber, fullname: String
enum CodingKeys: String, CodingKey {
case avatarURL = "avatar_url"
case phoneNumber = "phone_number"
case fullname
}
}
AF.request(web, method: .post, parameters: chataja,encoder:
JSONParameterEncoder.default).responseJSON { (response) in
switch (response.result) {
case .success(let data) :
let user = try? JSONDecoder().decode(User.self, from: data)

Related

How to decode in model when custom object's key missing from json

I have a Json in which there is the possibility that a few keys can be missing
Full JSON looks like this
{
"data": "some text",
"id": "3213",
"title": "title",
"description": "description",
"customObj1": [{
"id": "2423",
"count": 35
........
.......
}]
"customObj2": [{
"number": "2423",
"name": "john"
........
.......
}]
"customObj3": [{
"like": "2423",
"Other": 9
........
.......
}]
}
the custom object (1,2,3) may or may not be available in JSON, How can I write the model in swift using codable and struct?
here is how the model (dummy) look like
// MARK: - Response
struct Response: Codable {
let data, id, title, ResponseDescription: String
let customObj1: [CustomObj1]
let customObj2: [CustomObj2]
let customObj3: [CustomObj3]
enum CodingKeys: String, CodingKey {
case data, id, title
case ResponseDescription = "description"
case customObj1, customObj2, customObj3
}
}
// MARK: - CustomObj1
struct CustomObj1: Codable {
let id: String
let count: Int
}
// MARK: - CustomObj2
struct CustomObj2: Codable {
let number, name: String
}
// MARK: - CustomObj3
struct CustomObj3: Codable {
let like: String
let other: Int
enum CodingKeys: String, CodingKey {
case like
case other = "Other"
}
}
I have tried using decode init but need help
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
if (values.contains(. customObj1)) {
// here I need help }
else {
self.category = nil
}
}
}

Swift IOS Failed to access json array data using Codable

How to access JSON using Codable. this is my sample json.
{
"status": "success",
"message": "Data received successfully",
"course": {
"id": 1,
"description": "something",
"name": "ielts",
"attachments": [
{
"id": 809,
"attachment": "https:--",
"file_name": "syllabus.pdf",
"description": "course",
},
{
"id": 809,
"attachment": "https:--",
"file_name": "syllabus.pdf",
"description": "course",
}]
"upcased_name": "IELTS"
}
}
This is my code.
struct ResponseObject: Codable {
let course: [Course]
}
struct Course: Codable {
let id: Int
let name: String
let description: String
let attachments: [Attachments]
}
struct Attachments: Codable {
let id: Int
let attachment: String
let file_name: String
let description: String
let about: String
}
var course: [Course] = []
This is my api call.
func fetchUserData() {
let headers: HTTPHeaders = [
"Authorization": "Token token="+UserDefaults.standard.string(forKey: "auth_token")!,
"Accept": "application/json"
]
let params = ["course_id" : "1"] as [String : AnyObject]
self.showSpinner("Loading...", "Please wait!!")
DispatchQueue.global(qos: .background).async {
AF.request(SMAConstants.courses_get_course_details , parameters: params, headers:headers ).responseDecodable(of: ResponseObject.self, decoder: self.decoder) { response in
DispatchQueue.main.async {
self.hideSpinner()
guard let value = response.value else {
print(response.error ?? "Unknown error")
return
}
self.course = value.course
}
}
}
}
}
I am getting following error.
responseSerializationFailed(reason:
Alamofire.AFError.ResponseSerializationFailureReason.decodingFailed(error:
Swift.DecodingError.typeMismatch(Swift.Array,
Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue:
"course", intValue: nil)], debugDescription: "Expected to decode
Array but found a dictionary instead.", underlyingError: nil))))
Your model object does not match the JSON structure. Try this instead:
struct ResponseObject: Codable {
let status, message: String
let course: Course
}
struct Course: Codable {
let id: Int
let courseDescription, name: String
let attachments: [Attachment]
let upcasedName: String
enum CodingKeys: String, CodingKey {
case id
case courseDescription = "description"
case name, attachments
case upcasedName = "upcased_name"
}
}
struct Attachment: Codable {
let id: Int
let attachment, fileName, attachmentDescription: String
enum CodingKeys: String, CodingKey {
case id, attachment
case fileName = "file_name"
case attachmentDescription = "description"
}
}
and to download and parse this with plain Swift and Foundation, use code like this:
let url = URL(string: SMAConstants.courses_get_course_details)!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print(error)
return
}
if let data = data {
do {
let response = try JSONDecoder().decode(ResponseObject.self, from: data)
// access your data here
} catch {
print(error)
}
}
}
task.resume()

How to map this heterogeneous object with the model in swift?

Okay, so I am stuck at decoding the last item of this particular json by this the model, "payload" is always nil, Inside this "payload" object I can make my own json structure, I am able to decode the "text" but when it comes to the last item which is "payload", it is not working and is always nil.
I am not using any third-party library.
My Model Class.
struct DailougeFlowModel : Decodable {
// private enum CodingKeys : String, CodingKey {
// case responseId = "responseId"
// case queryResult = "queryResult"
// }
let responseId : String?
let queryResult : QueryResult?
}
struct QueryResult: Decodable {
// private enum CodingKeys : String, CodingKey {
// case fulfillmentText = "fulfillmentText"
// case fulfillmentMessages = "fulfillmentMessages"
// }
let fulfillmentText : String?
let fulfillmentMessages : [FulfillmentMessages]?
}
struct FulfillmentMessages: Decodable {
let text : TextModel?
let payLoad : Questions?
}
struct TextModel: Decodable {
let text : [String]?
}
struct Questions : Decodable{
let questions : [String]?
}
This json is what I am getting from the dailogeflow(V2). I am integrating a chatbot in the application.
{
"responseId": "2b879f78-cc05-4735-a7e8-067fdb53a81d-f6406966",
"queryResult": {
"fulfillmentMessages": [
{
"text": {
"text": [
"Text Here"
]
}
},
{
"text": {
"text": [
"Another Reply For Hi"
]
}
},
{
"payload": {
"questions": [
"Question One",
"Question Two",
"Question Three",
"Question Four"
]
}
}
]
}
}
Specify the inner model names as it is in the json response, if you want to specify your own model name then you would need to set an enum in each model just like the first model 'ResponseModel'
// MARK: - ResponseModel
struct ResponseModel: Codable {
let responseID: String
let queryResult: QueryResult
enum CodingKeys: String, CodingKey {
case responseID = "responseId"
case queryResult
}
}
// MARK: - QueryResult
struct QueryResult: Codable {
let fulfillmentMessages: [FulfillmentMessage]
}
// MARK: - FulfillmentMessage
struct FulfillmentMessage: Codable {
let text: Text?
let payload: Payload?
}
// MARK: - Payload
struct Payload: Codable {
let questions: [String]
}
// MARK: - Text
struct Text: Codable {
let text: [String]
}

Parsing Array of dictionaries in Swift using Codable

I have a JSON response from an API and I cannot figure out how to convert it into an user object (a single user) using Swift Codable. This is the JSON (with some elements removed for ease of reading):
{
"user": [
{
"key": "id",
"value": "093"
},
{
"key": "name",
"value": "DEV"
},
{
"key": "city",
"value": "LG"
},
{
"key": "country",
"value": "IN"
},
{
"key": "group",
"value": "OPRR"
}
]
}
You could do it in two steps if you want to. First declare a struct for the received json
struct KeyValue: Decodable {
let key: String
let value: String
}
Then decode the json and map the result into a dictionary using the key/value pairs.
do {
let result = try JSONDecoder().decode([String: [KeyValue]].self, from: data)
if let array = result["user"] {
let dict = array.reduce(into: [:]) { $0[$1.key] = $1.value}
Then encode this dictionary into json and back again using a struct for User
struct User: Decodable {
let id: String
let name: String
let group: String
let city: String
let country: String
}
let userData = try JSONEncoder().encode(dict)
let user = try JSONDecoder().decode(User.self, from: userData)
The whole code block then becomes
do {
let decoder = JSONDecoder()
let result = try decoder.decode([String: [KeyValue]].self, from: data)
if let array = result["user"] {
let dict = array.reduce(into: [:]) { $0[$1.key] = $1.value}
let userData = try JSONEncoder().encode(dict)
let user = try decoder.decode(User.self, from: userData)
//...
}
} catch {
print(error)
}
A bit cumbersome but no manual key/property matching is needed.
you could try a struct with like this
struct Model: Codable {
struct User: Codable {
let key: String
let value: String
}
let singleuser: [User]
}
Create a struct with 2 variables key and value
public struct UserModel: Codable {
public struct User: Codable {
public let key: String
public let value: String
}
public let user: [User]
}
After that using JSONDecoder to decode your string.
func decode(payload: String) {
do {
let template = try JSONDecoder().decode(UserModel.self, from: payload.data(using: .utf8)!)
} catch {
print(error)
}
}

Swift FAILURE: type Mismatch(Swift.Array<Any>)

Is there anyone can help me fix my model? It seems it does not match with the JSON from API Response.
JSON response from postman
{
"error_code": 0,
"data": [
{
"kode": "001",
"name": "BANK INDONESIA PUSAT JAKARTA"
},
{
"kode": "002",
"name": "PT. BANK RAKYAT INDONESIA (Persero) Tbk."
},
{
"kode": "003",
"name": "BANK EKSPOR INDONESIA"
}
],
"msg": "OK"
}
Last Model Edited:
struct ObjectBank: Codable {
let errorCode: Int
let data: [Bank]
let msg: String
enum CodingKeys : String, CodingKey {
case errorCode = "error_code" , data , msg
}
}
struct Bank: Codable {
let kode: String
let name: String
}
Still got error like this
Store model using alamofire
private static func performRequest<T:Decodable>(route:APIRouter,
decoder: JSONDecoder = JSONDecoder(), completion:#escaping
(Result<T>)->Void) -> DataRequest {
// Alamofire.request(route).responseJSON {
// response in
// print(response)
// }
return Alamofire.request(route).responseJSONDecodable (decoder:
decoder){ (response: DataResponse<T>) in
//print(response)
completion(response.result)
}
}
data is an array not dictionary
let data:[Bank]
//
struct ObjectBank: Codable {
let errorCode: Int
let data: [Bank]
let msg: String
enum CodingKeys : String, CodingKey {
case errorCode = "error_code" , data , msg
}
}
struct Bank: Codable {
let kode: String
let name: String
}
//
do {
let dic = try JSONDecoder().decode(ObjectBank.self,data)
}
catch {
print(error)
}
The structure of your response is ok in principle which you can see using the following Playground:
import Cocoa
let jsonData = """
{
"error_code": 0,
"data": [
{
"kode": "001",
"name": "BANK INDONESIA PUSAT JAKARTA"
},
{
"kode": "002",
"name": "PT. BANK RAKYAT INDONESIA (Persero) Tbk."
},
{
"kode": "003",
"name": "BANK EKSPOR INDONESIA"
}
],
"msg": "OK"
}
""".data(using: .utf8)!
struct ObjectBank: Codable {
let errorCode: Int
let data: [Bank]
let msg: String
enum CodingKeys : String, CodingKey {
case errorCode = "error_code" , data , msg
}
}
struct Bank: Codable {
let kode: String
let name: String
}
do {
let banks = try JSONDecoder().decode(ObjectBank.self, from: jsonData)
print(banks)
} catch {
print(error)
}
This will parse without error. Since I do not know AlamoFire very well I have to assume that there is something going wrong with the type of your completion closure. It will "somehow" have to guess that you want to parse ObjectBank in order to make any sense of your response.
Maybe you would have an easier time with responseData?