My ResponseString is as follows,
SUCCESS:
{"code":200,"shop_detail":{"name":"dad","address":"556666"},
"shop_types : [{"name":"IT\/SOFTWARE","merchant_type":"office"}]}
My Get request code with headers is as follows,
func getProfileAPI() {
let headers: HTTPHeaders = [
"Authorisation": AuthService.instance.tokenId ?? "",
"Content-Type": "application/json",
"Accept": "application/json"
]
print(headers)
let scriptUrl = "http://haitch.igenuz.com/api/merchant/profile"
if let url = URL(string: scriptUrl) {
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = HTTPMethod.get.rawValue
urlRequest.addValue(AuthService.instance.tokenId ?? "", forHTTPHeaderField: "Authorization")
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
Alamofire.request(urlRequest)
.responseString { response in
debugPrint(response)
print(response)
if let result = response.result.value // getting the json value from the server
{
print(result)
let jsonData1 = result as NSString
print(jsonData1)
let name = jsonData1.object(forKey: "code") as! [AnyHashable: Any]
print(name)
// var data = jsonData1!["shop_detail"]?["name"] as? String
} }
}
When I tried to get the value for "name" its getting'[<__NSCFString 0x7b40f400> valueForUndefinedKey:]: this class is not key value coding-compliant for the key code. Please guide me to get the values of name, address..?????
You can use the Response Handler instead of Response String Handler:
Response Handler
The response handler does NOT evaluate any of the response data. It
merely forwards on all information directly from the URL session
delegate. It is the Alamofire equivalent of using cURL to execute a Request.
struct Root: Codable {
let code: Int
let shopDetail: ShopDetail
let shopTypes: [ShopType]
}
struct ShopDetail: Codable {
let name, address: String
}
struct ShopType: Codable {
let name, merchantType: String
}
Also you can omit the coding keys from your struct declaration if you set your decoder keyDecodingStrategy (check this) to .convertFromSnakeCase as already mentioned in comments by #vadian:
Alamofire.request(urlRequest).response { response in
guard
let data = response.data,
let json = String(data: data, encoding: .utf8)
else { return }
print("json:", json)
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let root = try decoder.decode(Root.self, from: data)
print(root.shopDetail.name)
print(root.shopDetail.address)
for shop in root.shopTypes {
print(shop.name)
print(shop.merchantType)
}
} catch {
print(error)
}
}
For more information about encoding and decoding custom types you can read this post.
You can try to convert the json string to data then decode it
struct Root: Codable {
let code: Int
let shopDetail: ShopDetail
let shopTypes: [ShopType]
}
struct ShopDetail: Codable {
let name, address: String
}
struct ShopType: Codable {
let name, merchantType: String
}
Then
let jsonStr = result as! String
let dec = JSONDecoder()
dec.keyDecodingStrategy = .convertFromSnakeCase
let res = try? dec.decode(Root.self,from:jsonStr.data(using:.utf8)!)
Note your str json may be invalid as you miss " after shop_types so make sure it looks like this
{"code":200,"shop_detail":{"name":"dad","address":"556666"},
"shop_types" : [{"name":"IT/SOFTWARE","merchant_type":"office"}]}
Related
I am able to parse and decode data coming from IMGUR website. However when I try to print out one of the properties from Data it doesn’t show anything. How do I fix this? Also I want to access the contents of images, specifically the links. How can I access the contents Of the image since it’s an array?
struct PhotoResponse:Codable {
let success: Bool
let status: Int
let data: [Data]
}
struct Data:Codable {
let id: String
let title: String
let views: Int
let link: String
let images: [Image]?
let animated: Bool?
}
struct Image: Codable {
let id: String
let imageDescription: String?
let link: String?
let size: Int
}
class NetworkService{
static let shared = NetworkService()
private let baseURL = "https://api.imgur.com/3/gallery"
private init() {}
func getJSON( searchName: String, completion: #escaping([Data]) -> Void){
let endPoints = baseURL + "/search/time/week/?q=\(searchName)"
guard let url = URL(string: endPoints ) else{
return
}
var request = URLRequest(url: url)
let headers = ["Authorization": ""]
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Failed to query database", error)
}
guard let data = data else {
print("Data not received\(String(describing: error))")
return
}
let decoder = JSONDecoder()
do{
let decodedJson = try decoder.decode(PhotoResponse.self, from: data)
DispatchQueue.main.async {
completion(decodedJson.data)
}
}catch let error{
print("Json failed to decode\(String(describing: error))")
return
}
}.resume()
}
}
NetworkService.shared.getJSON(searchName: "cat") { (photos) in
for photo in photos {
print(photo.title)
print(photo.id)
}
Swift already has a Data struct, try renaming yours to something else, like MyData. Do the same with Image.
New to swift and wanted to display some data from a post request each time a user presses a button.
Class and struct for Post request:
import Foundation
struct Response: Codable, Identifiable{
var id = UUID()
var model = String()
var choices = String()
var generatedtext: [GeneratedText]
}
struct GeneratedText: Codable{
var finish_reason = String()
var index = Int()
var logprobs = String()
var text = String()
}
class GPT3TextComepletion: ObservableObject{
#Published var response = [Response]()
func textCompletion(promptText:String, completion:#escaping ([Response]) -> () ){
let token = "redacted"
let url = URL(string: "redacted URL")!
// prepare json data
var json: [String: Any] = [
"temperature": 0.8,
"max_tokens": 64,
"top_p": 1,
"frequency_penalty": 0,
"presence_penalty": 0,
"stop": ["\n\n"]]
json["prompt"] = promptText
let jsonData = try? JSONSerialization.data(withJSONObject: json)
// create post request
var request = URLRequest(url: url)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.setValue( "Bearer \(token)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
//TODO: Remove this once i get the response to display
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
}
let response = try! JSONDecoder().decode([Response].self, from: data)
DispatchQueue.main.async {
completion(response)
}
}
task.resume()
}
}
View:
Removed the unnecessary styling and other code from the below view:
#State var prompt: String = "This is some editable text..."
#State var response = [Response]()
utton(action: {GPT3TextComepletion().textCompletion(promptText: prompt, completion: {(response) in self.response = response })})
List (response){ response in
VStack{
Text(response.model)}}
However upon running the emulator and attempting the post call there seems to be an issue with how i am decoding the data and most likely how i have organized my structs, error message:
"Expected to decode Array but found a dictionary instead."
JSON:
["id": cmpl-4PCJZrxEm8YlCwFSTZlfLpnAUcMPl, "created": 1641910885, "object": text_completion, "model": davinci:2020-05-03, "choices": <__NSSingleObjectArrayI 0x6000012f1dc0>(
{
"finish_reason" = stop;
index = 0;
logprobs = "<null>";
text = "";
}
)
]
Obviously i am doing something wrong with how i am defining my struct however I have tried a number of different things with no success over the last few days.
Two main questions:
Is there an alternate way to display response of the post request without using List and making the struct identifiable?
What I am doing wrong with my structs here?
Thanks!
I want to append another dictionary as a parameter to httpBody of URLRequest
Request Model:
struct RequestModel: Encodable {
let body: Body
}
struct Body: Encodable {
let name: String
let score: String
let favList: [String]
}
Api Request:
do {
var urlRequest = URLRequest(url: resourceURL)
urlRequest.httpMethod = kHTTPMethodPOST
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.httpBody = try JSONEncoder().encode(self.requestModel)
let dataTask = URLSession.shared.dataTask(with: urlRequest) { data, response, error in
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200,
let jsonData = data else {
completion(.failure(.responseError))
return
}
}
dataTask.resume()
} catch {
completion(.failure(.unknownError))
}
Another dictionary: airports
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
trying to append airports dictionary parameter to URLRequest but can't append.
Appreciate your help and suggestion!
Thanks
If you have to append the airports dictionary to the request body, you may want to include it in the Request model itself.
I would suggest updating your RequestModel and make it Encodable.
And include your airports dict as a part of your RequestModel
Something like this
struct RequestModel: Encodable {
let body: Body
let airportsDict: [String:String]
}
struct Body: Encodable {
let name: String
let score: String
let favList: [String]
}
This way your httpBody will have all the data you want to pass.
Hope this helps
The usual syntax to POST JSON is
do {
var urlRequest = URLRequest(url: resourceURL)
urlRequest.httpMethod = "POST"
let postData = try JSONEncoder().encode(self.requestModel)
urlRequest.httpBody = postData
urlRequest.setValue("\(postData.count)", forHTTPHeaderField:"Content-Length")
urlRequest.setValue("application/json", forHTTPHeaderField:"Accept")
urlRequest.setValue("application/json", forHTTPHeaderField:"Content-Type")
}
I'M using tableview to parsing JSON data. the parse data in tableview in successful parsed on my tableView but the problem is users click the tableview cell to pass to details ViewController.But the problem is i can't parse JSON in details ViewController in
here is my JSON looks
[
{
"id": "263",
"userId": "2692"
}
]
here is my code
guard let url = URL(string: URL API) else { return }
var request = URLRequest(url: url)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer \(AccessToken!)", forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
do {
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [string: anyobject]
print(json)
label.text = json["id"] as? string
}catch {
}
}.resume()
Please try this codes
do {
if let json = try JSONSerialization.jsonObject(with: data!) as? [[String: String]] {
for data in json {
label.text = data["id"] as? String
}
}
} catch { print(error) }
Parse json in swift4 using Codable protocol.
declare your model like this:
struct Model: Codable {
let id: Double
let userId: Double
enum CodingKeys : String, CodingKey {
case id = "id"
case userId = "userId"
}
}
then, after getting data, use this:
do {
let arrayValue = try JSONDecoder().decode([Model], from: data)
}
catch {
}
Note that your json is array not dictionary!
I am using two models GET and POST which are encodable and decodable
using the below code i am able to get the data in GET model, but i am not able to post the data with POST model.
please guide me how to post the data using POST model
let url = URL(string: "<YOUR URL HERE>")
let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = [
"Accept" : "application/json",
"Content-Type" : "application/x-www-form-urlencoded"
]
let session = URLSession(configuration: config)
var request = URLRequest(url: url!)
request.encodeParameters(parameters: ["username": username, "password":
password])
let task = session.dataTask(with: request) { data, response, error in
guard let data = data else { return }
do {
let sentPost = try JSONDecoder().decode(Get.self, from: data)
print(sentPost)
} catch {}
}
task.resume()
model
struct Post: Encodable, Decodable {
let username: String
let password: String
}
extension for URLRequest
extension URLRequest {
private func percentEscapeString(_ string: String) -> String {
var characterSet = CharacterSet.alphanumerics
characterSet.insert(charactersIn: "-._* ")
return string
.addingPercentEncoding(withAllowedCharacters: characterSet)!
.replacingOccurrences(of: " ", with: "+")
.replacingOccurrences(of: " ", with: "+", options: [], range: nil)
}
mutating func encodeParameters(parameters: [String : String]) {
httpMethod = "POST"
let parameterArray = parameters.map { (arg) -> String in
let (key, value) = arg
return "\(key)=\(self.percentEscapeString(value))"
}
httpBody = parameterArray.joined(separator: "&").data(using: String.Encoding.utf8)
}
}
You don't need to create another string and then to data. This will be handled by Codable protocol and your JSONEncoder. You need to encode your post type using JSONEncoder and provide the data to the request.httpBody
Try this:
let url = URL(string: "<YOUR URL HERE>")
let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = [
"Accept" : "application/json",
"Content-Type" : "application/x-www-form-urlencoded"
]
do {
let aPost = Post(username: "username", password: "password")
let encoder = JSONEncoder()
let encodedPost = try encoder.encode(aPost)
let session = URLSession(configuration: config)
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.httpBody = encodedPost
let task = session.dataTask(with: request) { data, response, error in
do {
let sentPost = try JSONDecoder().decode(Get.self, from: data)
print(sentPost)
} catch {
print(error.localizedDescription)
}
}
task.resume()
} catch {
print(error.localizedDescription)
}