Handling Json response with alamofire - swift

I'm working on a IOS login application , but I don't know how to handle the Json response from the server , I want to write a Boolean function that depends on the server response :
this is the server response if the username and the password are right :
SUCCESS: {
users = (
{
email = test;
id = 1;
money = 200;
password = test;
username = test;
}
);
}
And if the username and password are wrong :
SUCCESS: {
users = (
);
}
this is my backend code written in NodeJs:
app.get('/login/:username/:password',(req,res)=>{
let user = req.params;
var sql = "SELECT * FROM users WHERE username = ? And password = ? ";
mysqlConnection.query(sql,[user.username,user.password],
function(err, rows){
if(!err){
res.send(JSON.stringify({"users" : rows}));
}
else {
console.log(err)
}
}
This is my swift function :
class func login(username : String , password : String, _ completion: #escaping (Bool) -> ()) {
let url = "http://127.0.0.1:3000/login/"+username+"/"+password
Alamofire.request(url).responseJSON{response in
switch response.result
{
case .failure:
print(response)
completion(false)
case .success:
//I want to handle the response here
//return true if the username and password are right
//return wrong if not
print(response)
completion(true)
}
}
}

Use above code:-
func CallAPI(){
let parameters: [String: Any] = [
"Username": "Admin",
"Password": "123456",
"Language_Code": "EN"]
Alamofire.request("Your API Url", method: .post, parameters: parameters, encoding: JSONEncoding.default)
.responseJSON { response in
if((response.result.value) != nil) {
let ResultJson = JSON(response.result.value!)
print("ResultJson==",ResultJson)
let UserCount = ResultJson["users"].count
if UserCount > 0 {
// Do with your above code
let Email = ResultJson["users"]["email"].stringValue
let id = ResultJson["users"]["id"].intValue
let money = ResultJson["users"]["money"].intValue
let password = ResultJson["users"]["password"].stringValue
let username = ResultJson["users"]["username"].stringValue
}
}
}
}

In both case you are getting SUCCESS so you can take users as a key and check weather it's containing any element or not like if the username and the password are right you will get
(
{
email = test;
id = 1;
money = 200;
password = test;
username = test;
}
)
But if the username and password are wrong you will get empty value for users key so in that case you can use
if usersDict.count == 0 {
//username and password are wrong
} else {
//username and the password are right
}

Related

Adding Additional Customer Information to Cloud Function to Create Stripe Customer

I'm trying to add additional information to my cloud function so that way my Stripe customer has all of the data saved in the Firebase Database. However, my question is how can I implement the constants in my cloud function correctly so the information uploads correctly? Without the fullname, username, and profileImage in my cloud function and my registration function in the functions section, it creates the Stripe customer. How do I structure the constants for those three fields so they can upload as well? Or should I create an email and password registration screen, so I can create the stripeID, then create another screen for additional information to add to the reference? Thank you!
Cloud Function:
exports.createStripeCustomer = functions.https.onCall( async (data, context) => {
const email = data.email
const uid = context.auth.uid
const fullname = context.auth.uid.fullname
const username = context.auth.uid.username
const profileImage = context.auth.uid.profileImage
if (uid === null) {
console.log('Illegal access attempt due to unauthenticated attempt.')
throw new functions.https.HttpsError('internal', 'Illegal access attempt')
}
return stripe.customers.create({
email : email,
fullname : fullname,
username : username,
profileImage : profileImage
}).then( customer => {
return customer["id"]
}).then( customerId => {
admin.database().ref("customers").child(uid).set(
{
stripeId: customerId,
email: email,
fullname: fullname,
username: username,
profileImage: profileImage,
id: uid
}
)
}).catch( err => {
throw new functions.https.HttpsError('internal', 'Unable to create Stripe customer.')
})
})
AuthService Function:
static func createCustomer(credentials: CustomerCredentials, completion: #escaping(DatabaseCompletion)) {
guard let imageData = credentials.profileImage.jpegData(compressionQuality: 0.3) else { return }
let filename = NSUUID().uuidString
let storageRef = STORAGE_REF.reference(withPath: "/customer_profile_images/\(filename)")
storageRef.putData(imageData, metadata: nil) { (meta, error) in
if let error = error {
debugPrint(error.localizedDescription)
return
}
storageRef.downloadURL { (url, error) in
guard let profileImageUrl = url?.absoluteString else { return }
Auth.auth().createUser(withEmail: credentials.email, password: credentials.password) { (result, error) in
if let error = error {
debugPrint(error.localizedDescription)
return
}
guard let uid = result?.user.uid else { return }
let values = ["email" : credentials.email,
"fullname" : credentials.fullname,
"username" : credentials.username,
"uid" : uid,
"profileImageUrl" : profileImageUrl] as [String : Any]
CustomerDataService.saveCustomerData(uid: uid, fullname: credentials.fullname, email: credentials.email,
username: credentials.username, profileImagUrl: profileImageUrl)
REF_CUSTOMERS.child(uid).setValue(values, withCompletionBlock: completion)
}
}
}
}
Registration Function:
#objc func handleCreateAccount() {
guard let profileImage = profileImage else {
self.simpleAlert(title: "Error", msg: "Please select a profile image.")
return
}
guard let email = emailTextField.text?.lowercased() , email.isNotEmpty ,
let fullname = fullnameTextField.text , fullname.isNotEmpty ,
let username = usernameTextField.text?.lowercased() , username.isNotEmpty ,
let password = passwordTextField.text , password.isNotEmpty ,
let confirmPassword = confirmPasswordTextField.text , confirmPassword.isNotEmpty else {
self.simpleAlert(title: "Error", msg: "Please fill out all fields.")
return
}
if password != confirmPassword {
self.simpleAlert(title: "Error", msg: "Passwords don't match, please try again.")
return
}
showLoader(true, withText: "Registering Account")
let credentials = CustomerCredentials(email: email, fullname: fullname, username: username,
password: password, profileImage: profileImage)
AuthService.createCustomer(credentials: credentials) { (error, ref) in
if let error = error {
Auth.auth().handleFireAuthError(error: error, vc: self)
self.showLoader(false)
return
}
Functions.functions().httpsCallable("createStripeCustomer").call(["email": credentials.email,
"fullname": credentials.fullname,
"username": credentials.username,
"profileImage": credentials.profileImage]) { result, error in
if let error = error {
Auth.auth().handleFireAuthError(error: error, vc: self)
self.showLoader(false)
return
}
}
self.showLoader(false)
guard let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return }
guard let tab = window.rootViewController as? MainTabController else { return }
tab.setupNavigationControllers()
self.handleDismissal()
}
}
To complete what I was trying to accomplish, I created a screen for customers to create an e-mail and password. This way the StripeID could be created, and then I created another screen to add the full name, username and profile image, and updated the database reference.

Parse responseJSON to ObjectMapper

I'm currently making a migration from Android to iOS, better said Java to Swift, I got a generic response in JSON, but I'm not able to use it as an object and show it in the storyboard. I'm really new to Swift so I've been stuck for a while.
I've tried ObjectMapper and also JSON decode with no result at all.
I declared this response as I used in Java(Android)
class ResponseObjectMapper<T,R>: Mappable where T: Mappable,R:Mappable{
var data:T?
var message:String!
var error:R?
required init?(_ map: Map) {
self.mapping(map: map)
}
func mapping(map: Map) {
data <- map["data"]
message <- map["message"]
error <- map["error"]
}
}
class UserMapper :Mappable{
var email:String?
var fullName:String?
var id:CLong?
var phoneNumber:String?
var token:CLong?
required init?(_ map: Map) {
}
func mapping(map: Map) {
email <- map["email"]
fullName <- map["fullName"]
id <- map["id"]
phoneNumber <- map["phoneNumber"]
token <- map["token"]
phoneNumber <- map["phoneNumber"]
}
}
In my Android project I use the Gson dependency and I was able to use my JSON as an object
class ErrorMapper:Mappable{
var message:String?
var code:Int?
required init?(_ map: Map) {
}
func mapping(map: Map) {
message <- map["message"]
code <- map["code"]
}
}
This is the Alamofire that gave me the JSON.
func login(params: [String:Any]){Alamofire.request
("http://192.168.0.192:8081/SpringBoot/user/login", method: .post,
parameters: params,encoding: JSONEncoding.default, headers:
headers).responseJSON {
response in
switch response.result {
case .success:
let response = Mapper<ResponseObjectMapper<UserMapper,ErrorMapper>>.map(JSONString: response.data)
break
case .failure(let error):
print(error)
}
}
}
If I print the response with print(response) I got
SUCCESS: {
data = {
email = "vpozo#montran.com";
fullName = "Victor Pozo";
id = 6;
phoneNumber = 099963212;
token = 6;
};
error = "<null>";
message = SUCCESS;
}
and if I use this code I can got a result with key and value but I don't know how to use it as an object
if let result = response.result.value {
let responseDict = result as! [String : Any]
print(responseDict["data"])
}
console:
Optional({
email = "vpozo#gmail.com";
fullName = "Victor Pozo";
id = 6;
phoneNumber = 099963212;
token = 6;
})
I would like to use it in an Object, like user.token in a View Controller, probably I'm really confused, trying to map with generic attributes.
Type 'ResponseObjectMapper<UserMapper, ErrorMapper>' does not conform to protocol 'BaseMappable'
First of all you will need a Network Manager which uses Alamofire to make all your requests. I have made generalized one that looks something like this. You can modify it as you want.
import Foundation
import Alamofire
import SwiftyJSON
class NetworkHandler: NSObject {
let publicURLHeaders : HTTPHeaders = [
"Content-type" : "application/json"
]
let privateURLHeaders : HTTPHeaders = [
"Content-type" : "application/json",
"Authorization" : ""
]
enum RequestType {
case publicURL
case privateURL
}
func createNetworkRequestWithJSON(urlString : String , prametres : [String : Any], type : RequestType, completion:#escaping(JSON) -> Void) {
let internetIsReachable = NetworkReachabilityManager()?.isReachable ?? false
if !internetIsReachable {
AlertViewManager.sharedInstance.showAlertFromWindow(title: "", message: "No internet connectivity.")
} else {
switch type {
case .publicURL :
commonRequest(urlString: baseURL+urlString, parameters: prametres, completion: completion, headers: publicURLHeaders)
break
case .privateURL:
commonRequest(urlString: baseURL+urlString, parameters: prametres, completion: completion, headers: privateURLHeaders)
break
}
}
}
func commonRequest(urlString : String, parameters : [String : Any], completion : #escaping (JSON) -> Void , headers : HTTPHeaders){
print("urlString:"+urlString)
print("headers:")
print(headers)
print("parameters:")
print(parameters)
let url = NSURL(string: urlString)
var request = URLRequest(url: url! as URL)
request.httpMethod = "POST"
request.httpHeaders = headers
request.timeoutInterval = 10
let data = try! JSONSerialization.data(withJSONObject: parameters, options: JSONSerialization.WritingOptions.prettyPrinted)
let json = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
if let json = json {
print("parameters:")
print(json)
}
request.httpBody = json!.data(using: String.Encoding.utf8.rawValue)
let alamoRequest = AF.request(request as URLRequestConvertible)
alamoRequest.validate(statusCode: 200..<300)
alamoRequest.responseJSON{ response in
print(response.response?.statusCode as Any )
if let status = response.response?.statusCode {
switch(status){
case 201:
print("example success")
SwiftLoader.hide()
case 200 :
if let json = response.value {
let jsonObject = JSON(json)
completion(jsonObject)
}
default:
SwiftLoader.hide()
print("error with response status: \(status)")
}
}else{
let jsonObject = JSON()
completion(jsonObject)
SwiftLoader.hide()
}
}
}
}
After this when ever you need to make a request you can use this function. This will take in parameters if any needed and once the request is complete it will execute a call back function in which you can handle the response. The response here will be of SWIFTYJSON format.
func makeNetworkRequest(){
let networkHandler = NetworkHandler()
var parameters : [String:String] = [:]
parameters["email"] = usernameTextField.text
parameters["pass"] = passwordTextField.text
networkHandler.createNetworkRequestWithJSON(urlString: "http://192.168.0.192:8081/SpringBoot/user/login", prametres: parameters, type: .publicURL, completion: self.handleResponseForRequest)
}
func handleResponseForRequest(response: JSON){
if let message = response["message"].string{
if message == "SUCCESS"{
if let email = response["data"]["email"].string{
//Do something with email.
}
if let fullName = response["data"]["fullName"].string{
//Do something with fullName.
}
if let id = response["data"]["id"].int{
//Do something with id.
}
if let phoneNumber = response["data"]["phoneNumber"].int64{
//Do something with phoneNumber.
}
if let token = response["data"]["token"].int{
//Do something with token.
}
}else{
//Error
}
}
}
Hope this helps. Let me know if you get stuck anywhere.

How to fetch user work experience from Facebook and display it as a list in UITextView

How do I grab data from facebook to display as a list in UITextView?
I've tried grabbing gender and name from facebook but have no success with age and work experience.
Here's a sample of my code:
// fetches additional user profile like age and gender
func fetchProfile() {
let parameters = ["fields": "gender"]
FBSDKGraphRequest(graphPath: "me", parameters: parameters).startWithCompletionHandler { (connection, result, error) in
if error != nil {
print(error)
return
}
if let gender = result["gender"] as? String {
self.usrGender.text = gender
}
}
let params = ["fields": "description"]
FBSDKGraphRequest(graphPath: "work-experience-id", parameters: params).startWithCompletionHandler { (connection, result, error) in
if error != nil {
print (error)
return
}
if let work = result["description"] as? String {
print(work)
}
}
}
It the results I've obtained from the log for 'work experiences' were as follows:
Some of the aliases you requested do not exist: work-experience-id, com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorCode=803, com.facebook.sdk:FBSDKGraphRequestErrorParsedJSONResponseKey={
body = {
error = {
code = 803;
"fbtrace_id" = BO6mfzy68oj;
message = "(#803) Some of the aliases you requested do not exist: work-experience-id";
type = OAuthException;
};
};
code = 404;
}}

In Swift Express using Bright Futures, How To Handle Asynchronous Operations?

I'm trying to create a basic asynchronous example in SwiftExpress using BrightFutures, and failing. Here's what I've got:
class FileSystem {
class func read(fileURL:NSURL, convert:(NSData?) -> Action<AnyContent>) -> Future<Action<AnyContent>, AnyError> {
let promise = Promise<Action<AnyContent>, AnyError>()
Queue.global.async {
let fileData = NSData(contentsOfURL:fileURL)
let action = convert(fileData)
promise.success(action)
}
return promise.future
}
}
Here's the server:
import Express
import TidyJSON
import BrightFutures
import Result
let app = express()
app.views.register(JsonView())
// Parameters: JSON object {"filePath" : "<filePath>"}
app.post("/readFile") { request -> Future<Action<AnyContent>, AnyError> in
//check if JSON has arrived
guard let json = request.body?.asJSON(),
let jsonDict = json.object,
let filePath = jsonDict["filePath"],
let filePathString = filePath.string else {
return future {
var response = [
"status": "error",
"message" : "Invalid request"
]
return Result(value: Action.render(JsonView.name, context: response))
}
}
print("json: \(json)")
print("json: \(json.object)")
let url = NSURL(fileURLWithPath: filePathString)
return FileSystem.read(url, convert: { data -> Action<AnyContent> in
var response = [String:AnyObject]()
var status:String
if data == nil {
status = "error"
response["message"] = "Could not read file"
}
else {
status = "ok"
response["result"] = data!
}
response["status"] = status
return Action.render(JsonView.name, context: response)
}).onSuccess { action in
print("action: \(action)")
}
}
app.all("/*") { request in
return Action.ok("Got a unknown request.")
}
app.listen(9999).onSuccess { server in
print("Express was successfully launched on port", server.port)
}
app.run()
When I connect to this using Postman, I get a `{}' in response. I can set breakpoints, and I know the code is executing, and I know I have an error (it can't find the file-- intentional on my part), just can't see why the response doesn't have the error status and message. Ideas?
Problem solved! A single line was wrong:
var response = [String:AnyObject]()
needed to be:
var response = [String:String]()

Firebase does not create a Facebook account User UID using the Facebook App User ID

I am developing an iOS app in swift that requires a user to create an account by connecting their Facebook account. A month ago, when I was testing by signing up with my own Facebook account, the User UID created by Firebase was in the format "facebook:(facebook app id)". This was what I wanted.
However, lately whenever a user creates a new acconut by connecting their Facebook account with my app, Firebase creates a User UID using a random string. For example: "E9FaL87wRmOKfhen2S6yszhCwtx1". Could this be because of the new Firebase update? Should I go through the migration process?
Here is my code for account creation:
#IBAction func facebookAuthAction(sender: AnyObject) {
let facebookLogin = FBSDKLoginManager()
facebookLogin.logInWithReadPermissions(nil, fromViewController: nil, handler: {(facebookResult, facebookError) -> Void in
if facebookError != nil {
print("Facebook login failed. Error \(facebookError)")
} else if facebookResult.isCancelled {
print("Facebook login was cancelled.")
} else {
let accessToken = FBSDKAccessToken.currentAccessToken().tokenString
FIREBASE_REF.authWithOAuthProvider("facebook", token: accessToken, withCompletionBlock: { error, authData in
if error != nil {
print("Login failed. \(error)")
} else {
print("Logged in! \(authData)")
NSUserDefaults.standardUserDefaults().setValue(authData.uid, forKey: "uid")
FIREBASE_REF.childByAppendingPath("users").observeEventType(.Value, withBlock: {snapshot in
if snapshot.hasChild(authData.uid) == false {
self.createNewFBUser(authData.uid)
}
})
self.performSegueWithIdentifier("loginSegue", sender: self)
}
})
}
})
}
func createNewFBUser(uid: String) {
var emailAddress:String = ""
var firstName:String = ""
var lastName:String = ""
var pictureURL:String = ""
let parameters = ["fields": "email, first_name, last_name, picture.type(large)"]
FBSDKGraphRequest(graphPath: "me", parameters: parameters).startWithCompletionHandler {(connection, result, error) -> Void in
if error != nil {
print(error)
return
}
if let email = result["email"] as? String {
emailAddress = email
}
if let first_name = result["first_name"] as? String {
firstName = first_name
}
if let last_name = result["last_name"] as? String {
lastName = last_name
}
if let picture = result["picture"] as? NSDictionary, data = picture["data"] as? NSDictionary, url = data["url"] as? String {
pictureURL = url
}
let newUser = [
"provider": "facebook",
"firstName": firstName,
"lastName": lastName,
"email": emailAddress,
"picture": pictureURL
]
FIREBASE_REF.childByAppendingPath("users").childByAppendingPath(uid).setValue(newUser)
}
}
When you upgrade your project to the new Firebase Console, your users are migrated to the new authentication back-end.
Newly created users after the upgrade will get a uid in the new format. See this post on the firebase-talk group for more information about the change and when it will also be applied to existing (non-upgraded) Firebase apps.
Note that Firebase has recommended against depending on the format of the uid for years. It is best to treat it as an opaque string that identifies the user.