This question already has an answer here:
iOS swift Post request
(1 answer)
Closed 6 years ago.
I was wondering how to authenticate api calls in swift to a custom service I made that authenticates users with active directory. Currently my application stores an integer value, I want to post that to the service.
let thing = Int(emailTextField.text!)
// POST method goes here ...
I just authenticate my app with this piece of code.
if(isValidEmail && isValidPassword){
print("sending to server for verification")
let params = ["user" : ["email" : "\(email!)", "password" : "\(password!)"]]
let url: String = "http://localhost:3000/users/sign_in"
Alamofire.request(.POST, url, parameters: params, encoding: .JSON, headers: nil).validate().responseJSON{
response in
switch response.result{
case .Success:
if let value = response.result.value{
let jsn = JSON(value)
print("jsn: \(jsn)")
let authentication_token = jsn["authentication_token"]
if(authentication_token != nil){
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("dasboardViewController") as! DashBoardController
self.presentViewController(vc, animated: true, completion: nil)
}
}
break
case .Failure:
break
}
}
}
Make sure Alamofire is imported. I have rails server in the backend and this was tested in localhost. Also, Authentication is done using email and password instead of numbers, And it returns a json containing authentication_token field.
Related
still struggling with this d*** FB SDK :-/
Basically, I've got an app that is supposed to post content to a FB Page. To achieve that, I login using the FB sdk. Then I request authorisations as follow
LoginManager().logIn(permissions: ["pages_manage_posts", "pages_read_engagement", "pages_show_list"], viewController: controller) { result in
print("res \(result)")
switch result {
case .success:
// the pageId is in data>id
Defaults[\.facebookSwitchOn] = true
GraphRequest.init(graphPath: "me/accounts").start { (connexion, result, error) in
guard let result = result as? [String:Any],
let dataArray = result["data"] as? Array<Any>,
let data = dataArray.first as? [String:Any],
let pageId = data["id"] as? String,
let access = data["access_token"] as? String else { return }
print("\(pageId)")
Defaults[\.facebookPageId] = pageId
Defaults[\.facebookPageAccessToken] = access
}
completion(true)
case .failed(let error):
completion(false)
MessageManager.show(.basic(.custom(title: "Oups".local(), message: error.localizedDescription, buttonTitle: nil, configuration: MessageDisplayConfiguration.alert)), in: controller)
default: ()
}
}
I save the pageId and TokenID to be able to perform a POST request as follow
GraphRequest
.init(graphPath: "\(pageId)/photos",
// parameters: ["source" : image, "caption" : text, "access_token" : token, "published" : false],
parameters: ["caption" : contentDescription, "url" : "https://www.cdiscount.com/pdt2/9/2/8/1/700x700/889698377928/rw/figurine-funko-pop-deluxe-game-of-thrones-daen.jpg", "access_token" : token],
httpMethod: .post)
.start { (connexion, result, error) in
completion(Result.success(true))
}
However, I get a weird error telling that publish_actions has been deprecated.
I logged the request using Charles, and here it is https://ibb.co/89wPgKx.
Now here is the debug from the GraphAPI explorer :
curl -i -X POST \ "https://graph.facebook.com/v7.0/104226051340555/photos?caption=test%20message%20from%20Graph%20API%20for%20photo&url=https%3A%2F%2Fwww.cdiscount.com%2Fpdt2%2F9%2F2%2F8%2F1%2F700x700%2F889698377928%2Frw%2Ffigurine-funko-pop-deluxe-game-of-thrones-daen.jpg&access_token=<access token sanitized>"
Basically, it is the same request excepting the fact that parameters in the explorer are URL parameters and they are encapsulated in a json.
I can't understand why the graph explorer request succeeds while the SDK request fails.
I'm totally stuck :-/
Thanks for your help.
This question already has an answer here:
Why is retrieving the data from this URL returning nil?
(1 answer)
Closed 3 years ago.
I need to upload a file to an FTP server, check if a folder exists and, if not, create it. I found FileProvider by Amir Abbas Mousavian. I got everything installed and have implemented the following code:
let credential = URLCredential(user: "user", password: "password", persistence: .permanent)
let ftpProvider = FTPFileProvider(baseURL: URL(string:"cflm.org")!, mode: .active, credential: credential, cache: nil)
ftpProvider?.delegate = self as! FileProviderDelegate
ftpProvider?.contentsOfDirectory(path: "/", completionHandler: {
contents, error in
for file in contents {
print("Name: \(file.name)")
print("Size: \(file.size)")
print("Creation Date: \(file.creationDate)")
print("Modification Date: \(file.modifiedDate)")
}
})
When I run the code, the completionHandler for contentsOfDirectory never fires. Does anyone know what I'm doing wrong or have some other way I can do the FTP functions I need to?
Your closure is not being called because ftpProvider is nil, a quick look at the source code tells us that the url sent to the init needs to contain the protocol. So add "ftp" or "ftps" to your url.
And wrap the init in a guard statement
guard let ftpProvider = FTPFileProvider(baseURL: URL(string:"ftp://cflm.org")!, mode: .active, credential: credential, cache: nil) else {
return //or some error handling
}
//... rest of code
I have followed this tutorial to implement a login with custom provider on an Azure mobile app. The backend works perfectly but when I try to login to my new custom controller I'm not able to do it. It's possible to implement it with Xamarin and also with java Android but is no way to do it with Objective C or Swift.
The object MSClient on Microsoft Azure mobile SDK only has two login implementations.
I have tried both but without luck, the callback always returns an empty client.
I also have tried to store the token created by own API use it for login call but without luck again.
Here is my Swift code:
let client = MSClient(applicationURLString: "https://myApp.azurewebsites.net")
client.login(withProvider: "custom", urlScheme: "myApp", parameters: ["username": "pau", "password": "123456"], controller: self, animated: true) {user, error in
print("USER", user)
print("ERROR", error)
}
We found a solution, it's really easy but the msclient documentation is not clear enough. You just need to pass whatever you need (i.e: username,password) as dictionary in token parameter.
Client.msClient.login(withProvider: "auth", token: params, completion: {user, error in
print("USER", user)
print("ERROR", error)
print("USER ID", user?.userId)
print("TOKEN", user?.mobileServiceAuthenticationToken)
if let user: MSUser = user {
guard let username: String = user.userId else { return }
guard let token: String = user.mobileServiceAuthenticationToken else { return }
Client.username = username
Client.msClient.currentUser = user
completion(true)
}else {
completion(false)
}
})
I am trying to upload an image from my app to my heroku backend and then pass that to Stripe for verification. Here is my swift code to upload and pass the image:
#IBAction func registerAccountButtonWasPressed(sender: UIButton) {
let dob = self.dobTextField.text!.components(separatedBy: "/")
let URL = "https://splitterstripeservertest.herokuapp.com/account/create"
var imageData = UIImageJPEGRepresentation(photoID,1)
let params = ["year": UInt(dob[2])! as UInt] as [String : Any]
let manager = AFHTTPSessionManager()
let operation = manager.post(URL, parameters: params, constructingBodyWith: { (formData: AFMultipartFormData!) -> Void in
formData.appendPart(withFileData: imageData!, name: "file", fileName: "photoID.jpg", mimeType: "image/jpeg")
}, success: { (operation, responseObject) -> Void in
print(responseObject!)
}) { (operation, error) -> Void in
self.handleError(error as NSError)
}
}
I've deleted the list of params above out and left one for readability.
Is there a way to then receive this file and upload it to stripe without having to save it by passing the file parameter? like so:
Stripe::FileUpload.create(
{
:purpose => 'identity_document',
:file => params[file]
},
{:stripe_account => params[stripe_account]}
)
Also in the stripe docs it says to upload the file to 'https://uploads.stripe.com/v1/files' but then shows code to put in your backend, does Stripe::FileUpload.create do the uploading to stripe for me?
Any insight on either would be great thanks.
You need to first upload the file to Stripe's API using the "create file upload" call. You can then use the file upload's ID (file_...) to update the account's legal_entity.verification.document attribute.
(This process is explained here:
https://stripe.com/docs/connect/identity-verification#uploading-a-file
https://stripe.com/docs/connect/identity-verification#attaching-the-file)
Since the file is provided by the user, you have two choices for creating the file upload:
have your app upload the file to your backend server, then on your backend, use the file to create the file upload
create the file upload directly from the app (using your publishable API key), and send the resulting file_upload's ID (file_...) to your backend
Here's an example for creating file uploads client-side, using jQuery: https://jsfiddle.net/captainapollo/d8yd3761/.
You could do the same thing from your iOS app's code. Basically all you need to do is send a POST request to https://uploads.stripe.com/v1/files with an Authorization header with value Bearer pk_... (where pk_... is your publishable API key) and type multipart/form-data, with the file's contents as the request's body. This blog post should be helpful for sending multipart/form-data requests using Swift: http://www.kaleidosblog.com/how-to-upload-images-using-swift-2-send-multipart-post-request
Thanks to #Ywain I was able to come up with this solution for IOS Swift 4. I created the file upload directly from the app and retrieved the file_upload's ID to send to my backend to attach to the Connect Account. I did this by importing Alamofire and SwiftyJSON.
let heads = ["Authorization": "Bearer \(stripePublishableKey)"]
let imageData = image!.jpegData(compressionQuality: 1.0)
let fileName = "\(NSUUID().uuidString).jpeg"
Alamofire.upload(multipartFormData: { multipart in
multipart.append(imageData!, withName: "file", fileName: fileName, mimeType: "image/jpeg")
multipart.append(("identity_document").data(using: .utf8)!, withName :"purpose")
}, to: fileUrl!, method: .post, headers: heads) { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { answer in
let value = JSON(answer.value!)
let FileID = value["id"].stringValue
// Use fileID and Connect Account ID to create params to send to backend.
let params: [String: Any] = [
"acct_id": ConnectID!,
"fileID": FileID,
]
print("statusCode: \(String(describing: answer.response?.statusCode))")
}
case .failure(let encodingError):
print("multipart upload encodingError: \(encodingError)")
}
}
The procedure to upload a video to Vimeo starts out very similarly as the one defined for Youtube, but only up to a point. Below I describe the steps that worked, and outline the last video-upload step which does not:
The Vimeo-upload dance begins when we pass the following parameters to trigger user authentication:
let authPath:String = "\(url_vauth)?response_type=\(response_type)&client_id=\(client_id)&redirect_uri=\(redirect_uri)&state=\(state)&scope=upload"
if let authURL:NSURL = NSURL(string: authPath) {
let request = NSURLRequest(URL: authURL)
webView.loadRequest(request) // opens a webpage in a webUIView
// once credentials are entered, google redirects back with the above uri + a temporary code
// we will exchange later for a token
// within AppDelegate, we have defined a way to handle this uri, which is to call
// processOAuthStep1Response(url)
Then, we process the returned response to extract an authorization code:
let components = NSURLComponents(URL: url, resolvingAgainstBaseURL: false)
var auth_code:String!
// the block below extracts the text that follows "code" in the return url
if let queryItems = components?.queryItems {
for queryItem in queryItems { // step through each part of url
if queryItem.name.lowercaseString == "code" {
auth_code = queryItem.value
break
} // end of if queryItem.name.lowercaseString
} // end of for
} // if let queryItems
With this authorization code, we then generate a token:
let getTokenPath:String = url_token
let grant_type = "authorization_code"
let header_plain = "\(client_id):\(client_secret)"
let string_plain = header_plain.dataUsingEncoding(NSUTF8StringEncoding)
let string_base64 = (string_plain?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0)))! as String
let headers = ["Authorization": "basic \(string_base64)"] // note that string_base64 really needs to be in base64!
//print ("...header is: \(string_base64)")
let tokenParams = ["grant_type": grant_type, "code": receivedCode, "redirect_uri": redirect_uri, "scope": "public"]
let request = Alamofire.request(.POST, getTokenPath, parameters: tokenParams, encoding: .URL, headers: headers)
We use this token to generate a ticket:
request(.POST, url_getticket, parameters: ticketParams , encoding: .URL, headers: headers).responseJSON { response in
//print(response)
switch response.result {
case .Success(let data):
let json = JSON(data)
print (json)
let myticket = json["ticket_id"].stringValue
//let usage = json[("upload_quota")].stringValue
let htmlform = json[("form")].stringValue
let uploadlink = json[("upload_link_secure")].stringValue
print("......ticket is \(myticket)")
print("......form is \(htmlform)")
print("......upload link is \(uploadlink)")
case .Failure(let error):
print("Request failed with error: \(error)")
} // end of switch
Finally (and this is where things stop to a screeching halt) we are supposed to use this ticket to make a POST request to Vimeo. The problem is that this ticket is embedded in an html form that actually makes the upload request to Vimeo...Not very useful for the iOS platform where I'm trying to implement this. Ideally, I'd like implementing with Alamofire via an upload call like so:
let headers = ["Authorization": "Bearer \(token)"]
upload(
.POST,
"https://1511923767.cloud.vimeo.com/upload?ticket_id=#######&video_file_id=####&signature=####&v6=1&redirect_url=https%3A%2F%2Fvimeo.com%2Fupload%2Fapi%3Fvideo_file_id%3D498216063%26app_id%3D70020%26ticket_id%####%26signature%######",
headers: headers,
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(data: videodata, name: "video", fileName: "bagsy.m4v", mimeType: "application/octet-stream")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
dispatch_async(dispatch_get_main_queue()) {
let percent = (Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
//progress(percent: percent)
print ("................\(percent)")
}
}
upload.validate()
upload.responseJSON { response in
print(response)
callback(true)
}
case .Failure(_):
callback(false)
}
})
Needless to say, the chunk of code above does not work. Any guidance would be most appreciated.
Consider using the official Vimeo iOS Upload SDK. We made it public about 2 weeks ago. It's a Swift library that handles upload of video files to Vimeo servers. It does so using a background-configured NSURLSession (so uploads continue regardless of whether your app is in the foreground or background). Let us know if you have any questions. Note: I'm one of the authors of the library and I work at Vimeo.
The VimeoUpload README is pretty robust and should communicate all that you need to know. Lettuce know if you have additional questions though, or feel free to make a pull request.
The ticket is never manually used in an upload. You should always use the url, or html provided by the API.
If you see HTML, it's because you are not providing the "type" parameter. We default to a simple POST upload system as described here: https://developer.vimeo.com/api/upload/videos#simple-http-post-uploading
If you provide "type=streaming", Vimeo returns a "complete_url", which you must call after performing the streaming upload as described here: https://developer.vimeo.com/api/upload/videos#resumable-http-put-uploads