Upload image to server in swift3 - json

I want to send an image as a parameter along with my request. I have used the code below to call my PUT request but I don't know how to append an image to the body.
func myImageUploadRequest()
{
let headers = [
"content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
"cache-control": "no-cache"
]
let parameters = [
[
"name": "Name",
"value": "Swift"
],
[
"name": "Key",
"fileName": "123.png"
//UIImagePNGRepresentation(myImageView.image!)
]
]
let boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"
var body = ""
var error: NSError? = nil
do{
for param in parameters {
let paramName = param["name"]!
body += "--\(boundary)\r\n"
body += "Content-Disposition:form-data; name=\"\(paramName)\""
if let filename = param["fileName"] {
let contentType = param["content-type"]!
let fileContent = try String(contentsOfFile: filename as! String, encoding: String.Encoding.utf8)
if (error != nil) {
print(error)
}
body += "; filename=\"\(filename)\"\r\n"
body += "Content-Type: \(contentType)\r\n\r\n"
body += fileContent
} else if let paramValue = param["value"] {
body += "\r\n\r\n\(paramValue)"
}
}
// }//do
let request = NSMutableURLRequest(url: NSURL(string: "http://——----docUpload/MediaUpload/")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
request.httpMethod = "PUT"
request.allHTTPHeaderFields = headers
// request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
}
catch {
} //new
}
I have seen many examples and tried but unable to implement it myself. please check my code and help me in this.

One option is to encode the image in Base64, which you can then include as a string in your json. Although this answer refers to javascript, it explains the pluses and minuses of this approach in general.
For syntax check this answer, which lays out all possible options you might need, but the code below should provide you with the file content that you can add to the body of your request.
if let image = UIImage(named:"imageNameHere"),
let imageData = UIImagePNGRepresentation(image) {
let fileContent = imageData.base64EncodedString(options: .lineLength64Characters)
}

Related

Having issues with a quick POST request for a token

So I'm trying to do a quick and dirty post request to get a token but I keep
getting this error. All I want to do for right now is print the JSON so I know I can at least test the app.
<NSHTTPURLResponse: 0x600002990600> { URL: https://development-290808.ew.r.appspot.com/token } { Status Code: 422, Headers {
"Alt-Svc" = (
"h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
);
"Content-Length" = (
172
);
"Content-Type" = (
"application/json"
);
Date = (
"Wed, 16 Dec 2020 00:10:14 GMT"
);
Server = (
"Google Frontend"
);
"x-cloud-trace-context" = (
"a71f62144e6ce9a6c7046d700a6bad7a;o=1"
);
} }
{
detail = (
{
loc = (
body,
username
);
msg = "field required";
type = "value_error.missing";
},
{
loc = (
body,
password
);
msg = "field required";
type = "value_error.missing";
}
);
}
With this code
func getToken() {
let parameters = ["username" : "Zach", "password" : "Password"]
guard let url = URL(string: "https://development-290808.ew.r.appspot.com/token") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, 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()
}
}
And because stack overflow doesn't like it when you post mostly code and little txt, here I am adding more text so I can post this question.
Looks like it might be an issue with the request body.. your server looks to be expecting something different. Check spelling and fields on the backend.
You are using guard statement on http body, and it does not fails, but that http body is wrong, and you are not sending any params to backend, and as error says value is missing, try without guard force unwrap it(in debug purpose) and app will crash and you will get error what is wrong that part.

CURL to URLRequest in Swift. (MUX LIVE STREAMING API)

Hello I am trying to create a live stream with mux api with a post request in my swift app.
This is what the cURL looks like. The MUX TOKEN ID & SECRET ID are defined in my app in swift:
curl https://api.mux.com/video/v1/live-streams \
-H "Content-Type: application/json" \
-X POST \
-d '{ "playback_policy": "public", "new_asset_settings": { "playback_policy": "public" } }' \
-u ${MUX_TOKEN_ID}:${MUX_TOKEN_SECRET}
This is my code in swift:
func getStreamKeys() {
let url = URL(string: "https://api.mux.com/video/v1/live-streams")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let parameters: [String: Any] = [
"playback_policy": "public",
"new_asset_settings": ["playback_policy": "public"]
]
request.httpBody = parameters.percentEncoded()
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data,
let response = response as? HTTPURLResponse,
error == nil else { // check for fundamental networking error
print("error", error ?? "Unknown error")
return
}
guard (200 ... 299) ~= response.statusCode else { // check for http errors
print("statusCode should be 2xx, but is \(response.statusCode)")
print("response = \(response)")
return
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
}
task.resume()
}
This is the response I get:
response = <NSHTTPURLResponse: 0x281c928e0> { URL: https://api.mux.com/video/v1/live-streams } { Status Code: 401, Headers {
"Cache-Control" = (
"max-age=0, private, must-revalidate"
);
"Content-Length" = (
69
);
"Content-Type" = (
"application/json; charset=utf-8"
);
Date = (
"Tue, 03 Mar 2020 22:34:45 GMT"
);
Server = (
"Mux API Server v1.89.12"
);
"x-request-id" = (
"FfjsHsz4jsEe_3oAcmYi"
);
} }
This is how the response should be:
{
"data": {
"id": "QrikEQpEXp3RvklQSHyHSYOakQkXlRId",
"stream_key": "super-secret-stream-key",
"status": "idle",
"playback_ids": [
{
"policy": "public",
"id": "OJxPwQuByldIr02VfoXDdX6Ynl01MTgC8w02"
}
],
"created_at": "1527110899"
}
}
I still need to pass -u ${MUX_TOKEN_ID}:${MUX_TOKEN_SECRET} the id and secret are constant and should be defined in the getStreamKeys. If someone can help me with it. Thanks
You'll need to add the auth to the api call as described below.
I also replaced your percentEncoded() with JSONSerialization as I do not know what you have in there.
let MUX_TOKEN_ID: String = ""
let MUX_TOKEN_SECRET: String = ""
func getStreamKeys() {
let url = URL(string: "https://api.mux.com/video/v1/live-streams")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let auth = "\(MUX_TOKEN_ID):\(MUX_TOKEN_SECRET)" // create string
let base64Auth = Data(auth.utf8).base64EncodedString() // base64encode the string
request.setValue("Basic \(base64Auth)", forHTTPHeaderField: "Authorization") // add auth to headers
request.httpMethod = "POST"
let parameters: [String: Any] = [
"playback_policy": "public",
"new_asset_settings": ["playback_policy": "public"]
]
do {
let jsonData = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
request.httpBody = jsonData
print(jsonData)
} catch let e {
print(e)
}
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data,
let response = response as? HTTPURLResponse,
error == nil else { // check for fundamental networking error
print("error", error ?? "Unknown error")
return
}
print(response)
guard (200 ... 299) ~= response.statusCode else { // check for http errors
print("statusCode should be 2xx, but is \(response.statusCode)")
print("response = \(response)")
return
}
let responseString = String(data: data, encoding: .utf8)
}
task.resume()
}
So the -u flag on curl encodes the value as base64 and passes it as the header
Authorization: Basic <some base64 string>
So in Swift, you'd have to encode the values of ${MUX_TOKEN_ID}:${MUX_TOKEN_SECRET} then pass it into the header dictionary.
Example:
let authString = "\(MUX_TOKEN_ID):\(MUX_TOKEN_SECRET)"
let encodedAuthString = Data(authString).base64EncodedString()
request.setValue("Basic \(encodedAuthString)", forHTTPHeaderField: "Authorization")

JSON data extraction in swift

I am using the following code:
let string = "https://wordsapiv1.p.mashape.com/words/?
hasDetails=examples&page=1"
let url = NSURL(string: string)
let request = NSMutableURLRequest(url: url! as URL)
request.setValue("KEY", forHTTPHeaderField: "X-Mashape-Key")
request.httpMethod = "GET"
let session = URLSession.shared
let task = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
if let resp = response as? HTTPURLResponse {
let json = try? JSONSerialization.jsonObject(with: data!, options: [])
print(json)
}
}
task.resume()
And the following is printed by the 'print(json)' line of code:
Optional({
query = {
limit = 100;
page = 1;
};
results = {
data = (
".22 caliber",
".38 caliber",
a,
"a bit",
"a cappella",
"a couple of",
"a few",
"a great deal",
"a little",
"a lot",
"a posteriori",
"a priori",
"a trifle",
aah,
abacinate,
abaft,
abandon,
abandoned,
abandonment,
abasement,
abashed,
"abatable nuisance",
abate,
abatement,
abaxial,
abbreviated,
abdicable,
abdicate,
abdominal,
"abdominal breathing",
abduct,
aberrant,
aberrate,
abhor,
abhorrent,
"abide by",
abiding,
abject,
abjectly,
abjure,
ablated,
ablative,
ablaze,
able,
"able-bodied",
ablutionary,
abnegate,
abnegation,
abnormal,
abnormally,
aboard,
abolish,
abolition,
abominable,
abominably,
abomination,
aboral,
aboriginal,
abort,
abortive,
abound,
abounding,
about,
"about-face",
above,
"above all",
aboveboard,
aboveground,
abrasive,
abreast,
abridge,
abridged,
abroach,
abroad,
abrupt,
abscessed,
abscond,
abseil,
absence,
absent,
absently,
absentminded,
absolute,
absolutely,
absoluteness,
absolve,
absolved,
absorb,
absorbed,
absorbent,
absorptance,
absorption,
abstain,
abstemious,
abstemiously,
abstinent,
abstract,
abstractive,
abstruse,
abstrusely
);
total = 21753;
};
})
The problem is that I need to get just the data that I want from this i.e. the words.
How do I now get the data from this that I want? i.e. an array of all the words returned (from ".22 caliber" to abstrusely)
I like to use the SwiftyJson cocoapod, as its much easier to read and understand than JSONDecoder (but of course, that would work too):
import SwiftyJson
let string = "https://wordsapiv1.p.mashape.com/words/?hasDetails=examples&page=1"
let url = NSURL(string: string)
let request = NSMutableURLRequest(url: url! as URL)
request.setValue("KEY", forHTTPHeaderField: "X-Mashape-Key")
request.httpMethod = "GET"
let session = URLSession.shared
var wordArray : [String] = []
let task = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
if let resp = response as? HTTPURLResponse {
let json : JSON = JSON(data!)
for word in json["results"]["data"] { //There's probably a way to cast directly to a [String] here instead but I'm not sure.
wordArray.append(word)
}
}
}
task.resume()

How to send a POST request through Swift?

I have my controller like this -
def create
if (#user = User.find_by_email(params[:email])) && #user.valid_password?(params[:password])
render json: #user.as_json(only: [:email,:authentication_token]),status: :created
else
render json:('Unauthorized Access')
end
end
When I use Postman to make this request, I choose Body, and form data and adds in the email and password. And this WORKS
How to use swift to do the same? This is what I have tried
let url = URL(string: "http://localhost:3000/api/v1/user_serialized/")
let config = URLSessionConfiguration.default
let request = NSMutableURLRequest(url: url!)
request.httpMethod = "POST"
let bodyData = "email=Test#test.com&password=Test1234"
request.httpBody = bodyData.data(using: String.Encoding.utf8);
let session = URLSession(configuration: config)
let task = session.dataTask(with: url! as URL, completionHandler: {(data, response, error) in
let json = JSON(data:data!)
debugPrint(json)
})
task.resume()
I have made a Custom HTTP class where we can sent url, parameter and we will get Data from API. Below is the class.
import Foundation
//HTTP Methods
enum HttpMethod : String {
case GET
case POST
case DELETE
case PUT
}
class HttpClientApi: NSObject{
//TODO: remove app transport security arbitary constant from info.plist file once we get API's
var request : URLRequest?
var session : URLSession?
static func instance() -> HttpClientApi{
return HttpClientApi()
}
func makeAPICall(url: String,params: Dictionary<String, Any>?, method: HttpMethod, success:#escaping ( Data? ,HTTPURLResponse? , NSError? ) -> Void, failure: #escaping ( Data? ,HTTPURLResponse? , NSError? )-> Void) {
request = URLRequest(url: URL(string: url)!)
logging.print("URL = \(url)")
if let params = params {
let jsonData = try? JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
request?.setValue("application/json", forHTTPHeaderField: "Content-Type")
request?.httpBody = jsonData//?.base64EncodedData()
//paramString.data(using: String.Encoding.utf8)
}
request?.httpMethod = method.rawValue
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 30
configuration.timeoutIntervalForResource = 30
session = URLSession(configuration: configuration)
//session?.configuration.timeoutIntervalForResource = 5
//session?.configuration.timeoutIntervalForRequest = 5
session?.dataTask(with: request! as URLRequest) { (data, response, error) -> Void in
if let data = data {
if let response = response as? HTTPURLResponse, 200...299 ~= response.statusCode {
success(data , response , error as? NSError)
} else {
failure(data , response as? HTTPURLResponse, error as? NSError)
}
}else {
failure(data , response as? HTTPURLResponse, error as? NSError)
}
}.resume()
}
}
Now you can refer below code to get how to make an API call.
var paramsDictionary = [String:Any]()
paramsDictionary["username"] = "BBB"
paramsDictionary["password"] = "refef"
HttpClientApi.instance().makeAPICall(url: "Your URL", params:paramsDictionary, method: .POST, success: { (data, response, error) in
// API call is Successfull
}, failure: { (data, response, error) in
// API call Failure
})
I think you should pass your request instead of the url to session.dataTask
here is how my code looks like:
private let url = URL(string: "http://example.com/")!
func httpPost(jsonData: Data) {
if !jsonData.isEmpty {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
URLSession.shared.getAllTasks { (openTasks: [URLSessionTask]) in
NSLog("open tasks: \(openTasks)")
}
let task = URLSession.shared.dataTask(with: request, completionHandler: { (responseData: Data?, response: URLResponse?, error: Error?) in
NSLog("\(response)")
})
task.resume()
}
}
Here is the Example of POST API for calling Login API with parameters "emailaddress" and "password" with userEmailID and Userpassword as two strings holding values for email and password respectively.
You can call this POST API anywhere in your view controller, as given below:
self.postLoginCall(url: "Your post method url") example: self.postLoginCall(url: "http://1.0.0.1/api/login.php")
func postLoginCall(url : String){
let request = NSMutableURLRequest(url: NSURL(string: url)! as URL)
request.httpMethod = "POST"
let postString = "emailaddress=\(userEmailID!)&password=\(Userpassword!)"
print(postString)
request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
guard error == nil && data != nil else { // check for fundamental networking error
print("error=\(error)")
return
}
do {
if let responseJSON = try JSONSerialization.jsonObject(with: data!) as? [String:AnyObject]{
print(responseJSON)
print(responseJSON["status"]!)
self.response1 = responseJSON["status"]! as! Int
print(self.response1)
//Check response from the sever
if self.response1 == 200
{
OperationQueue.main.addOperation {
//API call Successful and can perform other operatios
print("Login Successful")
}
}
else
{
OperationQueue.main.addOperation {
//API call failed and perform other operations
print("Login Failed")
}
}
}
}
catch {
print("Error -> \(error)")
}
}
task.resume()
}
Hello everyone I share below an example of a function to make a request in POST with SWIFT 5+.
This function allows you to send a POST request with an API entry point and parameters in the form of [[String: String]] and an Int to determine the output action.
For the output actions we call a function with Switch Case.
The operation is extremely simple. You have to put the two functions in one of your classes.
func MGSetRequestApi(endpoint: String, parameters: [[String: String]], MGSetAction: Int) -> String {
var setReturn: String!
let semaphore = DispatchSemaphore (value: 0)
var MGGetParam: String! = ""
for gate in parameters {
for (key, value) in gate {
let myParam = key + "=" + value + "&"
MGGetParam.append(contentsOf: myParam)
}
}
let postData = MGGetParam.data(using: .utf8)
var request = URLRequest(url: URL(string: endpoint)!,timeoutInterval: 10000)
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.httpBody = postData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
semaphore.signal()
return
}
print(String(data: data, encoding: .utf8)!)
setReturn = String(data: data, encoding: .utf8)!
DispatchQueue.main.async {
self.MGRequestAction(MGGetIdRq: MGSetAction, MGGetData: setReturn)
}
semaphore.signal()
}
task.resume()
semaphore.wait()
return setReturn
}
Then implement this function to manage the outputs
func MGRequestAction(MGGetIdRq: Int, MGGetData: String) {
switch MGGetIdRq {
case 1:
// Do something here
case 2:
// Do something else here
case 3:
// Do something else here again
default:
print("Set default action");
}
}
How to use this, you have two possibilities, the first one is to process what the function
MGSetRequestApi(endpoint: String, parameters: [[String: String]], MGSetAction: Int) -> String
returns (String) or to pass by the function
MGRequestAction(MGGetIdRq: Int, MGGetData: String)
which will call your Json parse function.
The MGRequestAction() function takes for parameter an Int for the choice of the action and the String of the return of the request
Now to use it do like this:
_ = MGSetRequestApi(endpoint: MY_END_POINT_API,
parameters: [["KEY_1": "VALUE 1"],
["KEY_2": "VALUE 2"],
["KEY_3": "VALUE 3"],
["KEY_4": "VALUE 4"]],
MGSetAction: 3)

Get JSON Results with POST Request with Parameters

How can I use a POST request with parameters to get JSON? I know how to do it with a simple GET request. The request url is http://gyminyapp.azurewebsites.net/api/Gym and the parameter query is
{
"SearchCircle": {
"Center": {
"Latitude": 0,
"Longitude": 0
},
"Radius": 0
},
"City": "string",
"ZipCode": 0,
"Type": "string"
}
I'm wanting to just use the search circle portion of this, which means I can ignore the City and ZipCode fields. I need to provide Latitude/Longitude, which I getting from the current user location. I also need to set the Type to "radius".
For a simple GET request using the GET version of this, I do this.
let url = NSURL(string: "http://gyminyapp.azurewebsites.net/api/Gym")
let data = NSData(contentsOfURL: url!)
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
for gym in json as! [AnyObject] {
gyms.append(gym)
}
} catch {
print("Error")
}
This is a working code, you just need to put the values of your request parameters.
let session = NSURLSession.sharedSession()
let url = "http://gyminyapp.azurewebsites.net/api/Gym"
let request = NSMutableURLRequest(URL: NSURL(string: url)!)
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let params:[String: AnyObject] = ["Type" : "string","SearchCircle" : ["Radius" : 0, "Center" : ["Latitude" : 0, "Longitude" : 0]]]
do{
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: NSJSONWritingOptions())
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let response = response {
let nsHTTPResponse = response as! NSHTTPURLResponse
let statusCode = nsHTTPResponse.statusCode
print ("status code = \(statusCode)")
}
if let error = error {
print ("\(error)")
}
if let data = data {
do{
let jsonResponse = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions())
print ("data = \(jsonResponse)")
}catch _ {
print ("OOps not good JSON formatted response")
}
}
})
task.resume()
}catch _ {
print ("Oops something happened buddy")
}
Then in the if let data = data you'd need to parse the response. I checked the response, it is JSON formatted array.
This is how I did it. Just make an NSDictionary out of params and convert to NSData, I called that postData. And then the usual, send that postData as requestBody
let parameters = [
"SearchCircle":
[ "Center" :
["Latitude" : 0,
"Longitude" : 0] ]
"Radius" : 0,
"City" : "", ...
... and so on
] ]
do
{
let postData = try NSJSONSerialization.dataWithJSONObject(parameters, options: .PrettyPrinted)
let request = NSMutableURLRequest(URL: NSURL(string: "http...")!,
cachePolicy: .UseProtocolCachePolicy,
timeoutInterval: 10.0)
request.HTTPMethod = "POST"
request.HTTPBody = postData
let session = NSURLSession.sharedSession()
let dataTask = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? NSHTTPURLResponse
print(httpResponse)
do {
// JSON serialization
self.dictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions()) as! NSDictionary
// if any data
}
catch {
}
}
})
dataTask.resume()
}
catch {
}
This is the accepted answer's code updated for Swift 4:
let url = "http://gyminyapp.azurewebsites.net/api/Gym"
let session = URLSession.shared
let request = NSMutableURLRequest(url: URL(string: url))
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let params:[String: AnyObject] = ["Type" : "string",
"SearchCircle" : ["Radius" : 0, "Center" : ["Latitude" : 0, "Longitude" : 0]]]
do{
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: JSONSerialization.WritingOptions())
let task = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
if let response = response {
let nsHTTPResponse = response as! HTTPURLResponse
let statusCode = nsHTTPResponse.statusCode
print ("status code = \(statusCode)")
}
if let error = error {
print ("\(error)")
}
if let data = data {
do{
let jsonResponse = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions())
print ("data = \(jsonResponse)")
}catch _ {
print ("OOps not good JSON formatted response")
}
}
})
task.resume()
}catch _ {
print ("Oops something happened buddy")
}
}