I'm new to iOS development
I need to make an API request sending some POST values and receiving json object
Ofc I have searched for tutorials and have seen other questions but all the codes I've found are causing all kind of errors.
This is what I've tried last:
func getAppConfig() async {
guard let url = URL(string:"https://blasrv.com/appconfig.php")
else{
return }
let body: [String: String] = ["userid": "420", "device": "ios"]
let finalBody = try? JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request){
(data, response, error) in
guard let data = data else{
return
}
do{
let jsondata = Data(data)
if let json = try JSONSerialization.jsonObject(with: jsondata, options: []) as? [String: Any] {
// try to read out a string array
if let nickname = json["nickname"] as? [String] {
print(nickname)
}
}
gotConfig = true
await fetchData()
}catch{
print("data not valid")
}
}
.resume()
}
It gives:
Cannot pass function of type '(Data?, URLResponse?, Error?) async -> Void' to parameter expecting synchronous function type
on
URLSession.shared.dataTask(with: request)
The problem is that you mix usage of old asynchronous way with new async wait way , you need
class ViewController: UIViewController {
var gotConfig = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
Task {
do {
try await getAppConfig()
}
catch {
print(error)
}
}
}
func getAppConfig() async throws {
guard let url = URL(string:"https://blasrv.com/appconfig.php") else { return }
let body: [String: String] = ["userid": "420", "device": "ios"]
let finalBody = try JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let (data, _) = try await URLSession.shared.data(for: request)
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
// try to read out a string array
if let nickname = json["nickname"] as? [String] {
print(nickname)
}
}
gotConfig = true
await fetchData()
}
func fetchData() async {
}
}
I am using URLSession. I am not receiving any error or response.
It works with one url. However it does not work with one another.
I have also tried percentencoding. But it doesn't work too.
The code is below
let urlString = "https://stark-spire-93433.herokuapp.com/json"//This is not working
//let urlString = "https://jsonplaceholder.typicode.com/todos"//This is working
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)//URLSession.shared
var request = URLRequest(url: URL(string:urlString)!)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONSerialization.data(withJSONObject: [], options: [])
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
print("response---",response)
print("error--",error)
if data != nil {
let json = try? JSONSerialization.jsonObject(with: data!)
print("JSOn",json)
} else {
print("error data is nil")
}
})
task.resume()
Too cumbersome code.
This is sufficient
let url = URL(string:"https://stark-spire-93433.herokuapp.com/json")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { print(error!); return }
do {
let json = try JSONSerialization.jsonObject(with: data)
print("JSOn",json)
} catch {
print(error)
}
}
task.resume()
I am trying to post form-data using webservice, userName & password, but in response it's showing an error stating "Could not connect to the server.".
Please help me to send form data in the POST request.
let dict:[String:String] = ["userName": userName as! String, "password": password as! String]
do {
let jsonData = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
let url = URL(string: "(some url)")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if error != nil {
print(error!.localizedDescription)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
let resultValue:String = parseJSON["success"] as! String;
print("result: \(resultValue)")
print(parseJSON)
}
} catch let error as NSError {
print(error)
}
}
task.resume()
} catch {
print(error.localizedDescription)
}
I've tried adding values in the request, may be some values are missing in the request formed. Please help!
Thats the POSTMAN response
my calling api class
class ApiService
{
static func getPostString(params:[String:Any]) -> String
{
var data = [String]()
for(key, value) in params
{
data.append(key + "=\(value)")
}
return data.map { String($0) }.joined(separator: "&")
}
static func callPost(url:URL, params:[String:Any], finish: #escaping ((message:String, data:Data?)) -> Void)
{
var request = URLRequest(url: url)
request.httpMethod = "POST"
let postString = self.getPostString(params: params)
request.httpBody = postString.data(using: .utf8)
var result:(message:String, data:Data?) = (message: "Fail", data: nil)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if(error != nil)
{
result.message = "Fail Error not null : \(error.debugDescription)"
}
else
{
result.message = "Success"
result.data = data
}
finish(result)
}
task.resume()
}
}
and when use it
ApiService.callPost(url: url, params: params, finish: finishPost)
and the finish function
func finishPost (message:String, data:Data?) -> Void
{
do
{
if let jsonData = data
{
let parsedData = try JSONDecoder().decode(Response.self, from: jsonData)
print(parsedData)
}
}
catch
{
print("Parse Error: \(error)")
}
}
Hi I am very beginner for Swift and I am trying to make NSURLSession "Post" request sending some parameter like my below code
According to my below code response not coming from server can some one help me please
BackGroundClass:-
import UIKit
protocol sampleProtocal{
func getResponse(result:NSDictionary)
func getErrorResponse(error:NSString)
}
class BackGroundClass: NSObject {
var delegate:sampleProtocal?
func callPostService(url:String,parameters:NSDictionary){
print("url is===>\(url)")
let request = NSMutableURLRequest(URL: NSURL(string:url)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
//Note : Add the corresponding "Content-Type" and "Accept" header. In this example I had used the application/json.
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(parameters, options: [])
let task = session.dataTaskWithRequest(request) { data, response, error in
guard data != nil else {
print("no data found: \(error)")
return
}
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
print("Response: \(json)")
self.mainResponse(json)
} else {
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)// No error thrown, but not NSDictionary
print("Error could not parse JSON: \(jsonStr)")
self.eroorResponse(jsonStr!)
}
} catch let parseError {
print(parseError)// Log the error thrown by `JSONObjectWithData`
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
self.eroorResponse(jsonStr!)
}
}
task.resume()
}
func mainResponse(result:NSDictionary){
delegate?.getResponse(result)
}
func eroorResponse(result:NSString){
delegate?.getErrorResponse(result)
}
}
ViewController:-
import UIKit
class ViewController: UIViewController,sampleProtocal {
override func viewDidLoad() {
super.viewDidLoad()
let delegate = BackGroundClass();
delegate.self;
let params = ["scancode":"KK03799-008", "UserName":"admin"] as Dictionary<String, String>
let backGround=BackGroundClass();
backGround.callPostService("url", parameters: params)
}
func getResponse(result: NSDictionary) {
print("Final response is\(result)");
}
func getErrorResponse(error: NSString) {
print("Final Eroor code is\(error)")
}
}
Swift 4 post example with json payload-
func postAction(_ sender: Any) {
let Url = String(format: "your url")
guard let serviceUrl = URL(string: Url) else { return }
let parameterDictionary = ["username" : "Test", "password" : "123456"]
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: []) else {
return
}
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
} catch {
print(error)
}
}
}.resume()
}
Try to run this function and print the response, it is in Swift 4.0.
Here, I have prepared codable structure:
struct LoginData: Codable {
var code: Int?
var message: String?
var status: String?
var token: String?
var data: DataSet?
}
struct DataSet: Codable {
var email : String?
var contactNo : String?
var firstName : String?
var lastName: String?
var dob : String?
var gender : String?
var address: String?
var city : String?
var state : String?
var country : String?
var zip : String?
var username: String?
}
If you get your response printed correctly then pass it to your viewController.
func loginWS(parameters:[String:String], completionHandler: #escaping (Any?) -> Swift.Void) {
guard let gitUrl = URL(string: BASE_URL+ACTION_URL) else { return }
print(gitUrl)
let request = NSMutableURLRequest(url: gitUrl)
// uncomment this and add auth token, if your project needs.
// let config = URLSessionConfiguration.default
// let authString = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMywiUGFzc3dvcmQiOiIkMmEkMTAkYVhpVm9wU3JSLjBPYmdMMUk2RU5zdU9LQzlFR0ZqNzEzay5ta1pDcENpMTI3MG1VLzR3SUsiLCJpYXQiOjE1MTczOTc5MjV9.JaSh3FvpAxFxbq8z_aZ_4OhrWO-ytBQNu6A-Fw4pZBY"
// config.httpAdditionalHeaders = ["Authorization" : authString]
let session = URLSession.shared
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = try! JSONSerialization.data(withJSONObject: parameters, options: [])
let task = session.dataTask(with: request as URLRequest) { data, response, error in
guard let data = data else { return }
do {
// let decoder = JSONDecoder()
// here replace LoginData with your codable structure.
let gitData = try JSONDecoder().decode(LoginData.self, from: data)
print("response data:", gitData)
completionHandler(gitData)
} catch let err {
print("Err", err)
}
}.resume()
}
Here is a sample complete solution compatible with Swift 4 and Swift 5.
Endpoint to create urls
struct Endpoint {
let path: String
let queryItems: [URLQueryItem]?
}
extension Endpoint {
var url: URL? {
var components = URLComponents()
components.scheme = "https"
components.host = "YOUR_HOST"
components.path = path
components.queryItems = queryItems
return components.url
}
}
User object model for request body
struct User: Encodable {
let name: String
let surname: String
let age: Int
// this is to customise init
init(name: String,
surname: String,
age: Int) {
self.name = name
self.surname = surname
self.age = age
}
enum CodingKeys: String, CodingKey {
case name, surname, age
}
}
UserResponse model for http response comes from API
struct UserResponse: Decodable {
let message: String
let userId: String?
enum CodingKeys: String, CodingKey {
case message, userId = "user_id" // API returns userId as "user_id"
}
}
APIClient make http requests for our api
protocol APIClientProtocol: Any {
func sendUser(_ user: User, completionBlock: #escaping (_ userResponse: UserResponse?, _ error: APIClient.Error?) -> Void)
}
class APIClient: APIClientProtocol {
fileprivate let defaultSession: URLSession = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 10.0
configuration.timeoutIntervalForResource = 10.0
return URLSession(configuration: configuration, delegate: nil, delegateQueue: nil)
}()
public init() { }
public func uploadUser(_ user: User, completionBlock: #escaping (UserResponse?, APIClient.Error?) -> Void) {
guard let url = Endpoint(path: "/user/upload", queryItems: nil).url else {
completionBlock(nil, .brokenURL)
return
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
do {
let jsonData = try JSONEncoder().encode(user)
urlRequest.httpBody = jsonData
} catch {
completionBlock(nil, .serialization(error.localizedDescription))
return
}
let task = defaultSession.dataTask(with: urlRequest) { data, urlResponse, error in
if let error = error {
completionBlock(nil, .http(error.localizedDescription))
return
}
guard let httpResponse = urlResponse as? HTTPURLResponse else {
return
}
if httpResponse.statusCode == 200 {
guard let data = data else {
return
}
do {
let userResponse = try JSONDecoder().decode(UserResponse.self, from: data)
completionBlock(userResponse, nil)
} catch let error {
completionBlock(nil, .serialization(error.localizedDescription))
}
} else {
completionBlock(nil, .http("Status failed!"))
}
}
task.resume()
}
}
extension APIClient {
enum Error: Swift.Error, Equatable {
case brokenURL
case serialization(String)
case http(String)
}
}
Post Class
func post(params : Dictionary<String, String>, url : String) {
var request = NSMutableURLRequest(URL: NSURL(string: url))
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil) {
println(err!.localizedDescription)
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: '\(jsonStr)'")
}
else {
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
var success = parseJSON["success"] as? Int
println("Succes: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: \(jsonStr)")
}
}
})
task.resume()
}
call This Method Like This
self.post(["username":"jameson", "password":"password"], url: "http://localhost:4567/login")
Hope It Helps :)
Http body is missing. Example - setting string paramets as body
let paramString = String(format:"param1=%#¶m2=%#",param1,param2)
request.httpBody = paramString.data(using: String.Encoding.utf8)
here just try
request.httpBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
func getData(searchString:String,completion:#escaping(Any)->Void){
let url = "https://itunes.apple.com/search?term="+searchString
URLSession.shared.dataTask(with: URL.init(string: url)!){(data,response,err) in
if let responsedata = data{
DispatchQueue.main.async {
completion(responsedata)
}
}
}.resume()
}
Try this: (Swift 4.2)
public func submitDelivery(delivery:DeliveryModal,responseCode:String,completion:#escaping SubmitCompletionBlock){
let urlString = BaseURL.getURL(urlType: .submit(responseCode))
guard let url = URL(string: urlString) else { return }
var request : URLRequest = URLRequest(url: url)
request.httpMethod = HttpMethod.post.rawValue
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
do {
let jsonData = try encoder.encode(delivery)
request.httpBody = jsonData
} catch {
print(error.localizedDescription)
completion(nil,nil,NSError.init())
}
let dataTask = URLSession.shared.dataTask(with: request) {
data,response,error in
guard let data = data else {
completion(nil,response,NSError.init())
return
}
do {
let data = try JSONDecoder().decode(DeliverySubmitResponseModal.self, from: data)
DispatchQueue.main.async {
completion(data,response,error)
}
} catch let error {
debugPrint(error.localizedDescription)
}
}
dataTask.resume()
}
I am calling rest api using singleton class as I need to call this api from 3-4 view controllers. To pass the data, I implemented one protocol method also.
I am not sure this is the right way of passing data and use of singleton class. Could anyone please guide me in this? Please guide me if I am missing or doing wrong in the code. I appreciate your time and suggestions.
//This is my NetworkService class
protocol NetworkServicesDelegate {
// protocol method
func serviceData(arrayData:NSArray)
}
class NetworkServices:NSObject{
static let sharedInstance = NetworkServices()
var delegate: NetworkServicesDelegate?
var dataArray: NSArray?
func getData(paramValue : String,apiName:String)
{
let configURL = NSBundle.mainBundle().objectForInfoDictionaryKey("ConfigURL") as! String
guard let url = NSURL(string: configURL+"/"+apiName) else {
print("Error: cannot create URL")
return
}
let request = NSMutableURLRequest(URL:url)
let defaultSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let params = ["myKey":paramValue]
let valid = NSJSONSerialization.isValidJSONObject(params)
print(valid)
request.HTTPBody = try? NSJSONSerialization.dataWithJSONObject(params, options: [])
let task = defaultSession.dataTaskWithRequest(request, completionHandler: { (data:NSData?, response:NSURLResponse?, error:NSError?) in
if let HTTPResponse = response as? NSHTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
self.dataArray = try! NSJSONSerialization.JSONObjectWithData(data!, options: [] ) as! NSArray
self.serviceData(self.dataArray!)
}
}
})
task.resume()
}
private func serviceData(serviceDataArray: NSArray){
guard self.delegate != nil else {
return
}
delegate?.serviceData(serviceDataArray)
print("serviceDataArray : \(serviceDataArray)")
}
}
You can follow the following approach:
Make a static or class function and take the delegate as an additional parameter
Call the delegate function after the data is download from the api in competition handler.
And from any of the view controller call this function like this:
NetworkServices.getData("yourparam", apiName: "yourAPINAME", delegate: self)
Modified NetworkServices class code below.:
protocol NetworkServicesDelegate {
func serviceData(arrayData:NSArray)
}
class NetworkServices:NSObject{
class func getData(paramValue : String,apiName:String, delegate:NetworkServicesDelegate?)
{
let configURL = NSBundle.mainBundle().objectForInfoDictionaryKey("ConfigURL") as! String
guard let url = NSURL(string: configURL+"/"+apiName) else {
print("Error: cannot create URL")
return
}
let request = NSMutableURLRequest(URL:url)
let defaultSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let params = ["myKey":paramValue]
let valid = NSJSONSerialization.isValidJSONObject(params)
print(valid)
request.HTTPBody = try? NSJSONSerialization.dataWithJSONObject(params, options: [])
let task = defaultSession.dataTaskWithRequest(request, completionHandler: { (data:NSData?, response:NSURLResponse?, error:NSError?) in
if let HTTPResponse = response as? NSHTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
let dataArray:NSArray = try! NSJSONSerialization.JSONObjectWithData(data!, options: [] ) as! NSArray
delegate?.serviceData(dataArray)
}
}
})
task.resume()
}
}