Quickbooks create a TimeActivity - swift

How can I make a POST request to create a time activity for my company on Quickbooks from a mobile app? I've got authorisation working fine, now I just need to know how to create items. For the HTTPBody of the request, what should I enter?

let url = NSURL(string:”Some Fancy URL“)
let request = NSMutableURLRequest(URL: url!)
var err: NSError?
var bodyData = “myBodyKey=myBodyValue“ as NSString
request.HTTPMethod = "POST"
request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding)!
This is (a way) of setting the HTTPBody of a request
In regards to Quickbooks, they have a api documentation regarding the time activity.
They explain here how to send a JSON Create Request.
And use as example
{
"TxnDate":"2013-01-28",
"NameOf":"Vendor",
"VendorRef":{
"value":"61"
},
"CustomerRef":{
"value":"60"
},
"DepartmentRef":{
"value":"3"
},
"ItemRef":{
"value":"4"
},
"ClassRef":{
"value":"100100000000000321202"
},
"BillableStatus":"Billable",
"Taxable":true,
"HourlyRate":251,
"BreakHours":1,
"BreakMinutes":0,
"StartTime":"2013-01-28T08:00:00-08:00",
"EndTime":"2013-01-28T17:00:00-08:00",
"Description":"Single activity time sheet",
"domain":"QBO",
"sparse":false
}
As A data you would need to create a dictionary and encode this as json.

Related

How can I pass parameters in an HTTP Post request in Swift?

Am working on a simple Swift test app which just calls Perl script on my server. Right now I just want to send over a username and id, and get them back in a JSON response. Nothing more, am still in the learning stage.
But no matter which way I try, I cannot successfully send the two parameters in my URLRequest.
In the sample below, you'll see I try to send them in the main url, I've tried to add them as forHTTPHeaderFields, but the response I get back in my URLSessionDataDelegate is always:
data is {"userid":"","username":""}
JSON Optional({
userid = "";
username = "";
let file = File(link: "http://example.com/cgi-bin/swift.pl?username=John&userid=01", data: "hello")
uploadService.start(file: file)
And within my instance of URLSession I have tried:
// From one of my view controllers I create a File struct
// from a YouTube lesson. Eventually I want to send a file.
// So for now am using just *Hello*:
let uploadTask = UploadTask(file: file)
let url = URL(string: file.link)!
let uploadData = Data(file.data.utf8)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField:"Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("John", forHTTPHeaderField: "username")
request.addValue("01", forHTTPHeaderField: "userid")
uploadTask.task = uploadSession.uploadTask(with: request, from: uploadData)
uploadTask.task?.resume()
Every other part of the Swift test works, I get a response and data in my URSessionDelegate, and no errors. Obviously I just can't figure out how to properly send over the two parameters. For the record:
the Perl script below does work from a linux command line, or when called from a web browser.
If I hardcode the return repsonse in the perl script below, I do recieve it in the my URLSessionDelegate, so I know that I am parsing it correctly
As well, my server's error log shows that $header1 and $header2 never get initialized.
#!/usr/bin/perl -w
use strict;
use CGI;
use JSON;
my $q = new CGI;
my $header1 = $q->param("username");
my $header2 = $q->param("userid");
print $q->header('application/json');
my %out = (username=>"$header1", userid=>"$header2");
my $json = encode_json \%out;
print $json;
exit(0);
You are sending the parameters username and userid as http header values.
Your perl scrip is expecting them a query parameters.
So first create a URLComponents object, than add query items and finally create your url.
Try this:
let uploadTask = UploadTask(file: file)
var urlComponents = URLComponents(string: file.link)!
let queryItems = [URLQueryItem(name: "username", value: "John"),
URLQueryItem(name: "userid", value: "01")]
urlComponents.queryItems = queryItems
let url = urlComponents.url!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField:"Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
uploadTask.task = uploadSession.uploadTask(with: request, from:
uploadData)
uploadTask.task?.resume()
Have a look at this Post that shows how to add query parameters using an extension to URL
In these two lines:
request.addValue("John", forHTTPHeaderField: "username")
request.addValue("01", forHTTPHeaderField: "userid")
You are adding those as http headers and not url query parameters.
To add query parameters, you need to convert to URLComponents first and then convert back: https://developer.apple.com/documentation/foundation/urlcomponents
var urlComponents = URLComponents(string: file.link)!
urlComponents.queryItems = [
URLQueryItem(name: "username", value: "name"),
URLQueryItem(name: "userid", value: "id")
]
let newURL = urlComponents.url!
//use the newURL
Just create a dictionary with data
let parameterDictionary = ["username" : "John", "userid": "01"]
Then create httpBody object using
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: []) else { return }
Then simply add that body in your request parameter
request.httpBody = httpBody
I finally found the answer here on StackOverflow.
Having no experience in http methods, the short answer to my question is that if I am using "GET", I would use urlComponents.queryItems, but if I am using "POST" then my parameters would have to be in the http body itself.
But more importantly, the answer found in the link explains when and why you should use "GET" as opposed to "POST", and vice-versa.
So to anyone coming across this, definitely read the answer provided in the link.

Why response is always {"detail":"Unsupported media type \"text/plain\" in request."} in swift?

I have created a sample app in Django which deletes a question from App. And provides a correct output when consumed using POSTMAN.
class Questions(APIView):
def delete(self,request):
received_id = request.POST["id"]
print(received_id)
place = Question.objects.get(pk=received_id)
place.delete()
questions = Question.objects.all()
seriliazer = QuestionSerializer(questions,many = True)
return Response({'Orgs': seriliazer.data})
However, when I am trying to achieve it from iOS app, it's returning {"detail":"Unsupported media type "text/plain" in request."}
func deleteQuestion( id: Int){
guard let url = URL(string: "http://127.0.0.1:8000/V1/API/questions/") else {
return
}
var request = URLRequest(url: url)
let postString = "id=15"
request.httpBody = postString.data(using: String.Encoding.utf8);
request.httpMethod = "DELETE"
URLSession.shared.dataTask(with: request) { data, response, error in
let str = String(decoding: data!, as: UTF8.self)
print(str)
if error == nil {
self.fetcOrganizatinData()
}
}.resume()
}
Could not really understand where exactly the problem is ?
If the api is expecting Json, the body you are sending is not Json, it’s encoded plain text. If it should be Json you can change the body string into the Json format like:
“{\”id\”:15}”
// you may want to tell it what you’re sending
request.setValue("application/json", forHTTPHeaderField: "Accept-Encoding")
Another thing it could be is the request is missing the Accept-Encoding header which tells the api what you’re sending up where Content-Type is what the api typically sends down.
I’ve experienced header injection when I’ve sent requests through specific gateways that aren’t always right. I’d the header isn’t present, something along the way could try to help you out and add the header. This has caused me problems on the past. I still don’t know exactly where in our stack it was occurring, but adding the header fixed my problem.
You can add the header like:
request.setValue("charset=utf-8", forHTTPHeaderField: "Accept-Encoding")
DELETE request's body will be ignored, I could guess from the Is an entity body allowed for an HTTP DELETE request? post. HENCE Better to send the complete URL or in header itself,
so I made the function as below
def delete(self,request):
received_id = request.headers['id']
place = Question.objects.get(pk=received_id)
place.delete()
return HttpResponse("DELETE view is working fine ")
and swift
func deleteQuestion( id: Int){
guard let url = URL(string: "http://127.0.0.1:8000/V1/API/questions/") else {
return
}
var request = URLRequest(url: url)
//let postString = "id=\(id)"
// request.httpBody = postString.data(using: String.Encoding.utf8);
request.httpMethod = "DELETE"
request.setValue("charset=utf-8", forHTTPHeaderField: "Accept-Encoding")
request.setValue("charset=utf-8", forHTTPHeaderField: "Content-Type")
request.setValue("\(id)", forHTTPHeaderField: "id")
URLSession.shared.dataTask(with: request) { data, response, error in
let str = String(decoding: data!, as: UTF8.self)
print(str)
if error == nil {
self.fetcOrganizatinData()
}
}.resume()
}
Shortly add Content-Type application/json in your headers
Reason
this happens because the postman has some default headers usually 8.
One of them is
Content-Type text/plain
and by writing "Content-Type": "application/json" we can overwrite that rule.
So whenever you want to pass your data like JSON do that.
to learn more what is by default in postman
I recommend you to read this official documentation of postman.
It happens with me I solved this with overwriting default Content-Type

pho.to API Request Failing in Swift

Im currently trying to work with the pho.to API in my iOS application. I am experimenting with making simple requests according to the documentation, however I cannot seem to get the request to go through successfully. Inside my API client file, I have this code:
let dataStr = """
<image_process_call>
<image_url>http://developers.pho.to/img/girl.jpg</image_url>
<methods_list>
<method order="1">
<name>desaturation</name>
</method>
<method order="2">
<name>caricature</name>
<params>type=1;crop_portrait=true</params>
</method>
</methods_list>
<thumb1_size>100</thumb1_size>
</image_process_call>
"""
let encodedStr = dataStr.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: " ", with: "")
let signData = encodedStr.hmac(key: key)
let urlStr = "https://opeapi.ws.pho.to/addtask/?app_id=\(appId)&key=\(key)&sign_data=\(signData)&data=\(encodedStr.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!))"
The HMAC encoding is being done according to this Stack Overflow post. Unfortunately when making a request to this URL using URLSession I get this response:
<?xml version=\"1.0\"?>\n<image_process_response><status>SecurityError</status><err_code>614</err_code><description>Error in POST parameters: one or more parameters (DATA , SIGN_DATA or APP_ID) are empty</description></image_process_response>
I feel like my issue is more related to actually forming the request rather than something specific to the API itself. I know my code is a little messy, however I was hoping that somebody could point me in the right direction in terms of making a request like this. Thanks!
As per their documentation you can see that data sent over from POST requests are in body (In cURL calls -d specifies the body of the request)
You are sending params/data in query, which the pho.to API doesn't accept, hence the error.
Here's a sample on how you can do:
let defaultSessionConfiguration = URLSessionConfiguration.default
let defaultSession = URLSession(configuration: defaultSessionConfiguration)
// Setup the request with URL
let url = URL(string: "https://opeapi.ws.pho.to/addtask")!
var urlRequest = URLRequest(url: url)
// Convert POST string parameters to data using UTF8 Encoding
let postData = yourXMLString.data(using: .utf8)
// Set the httpMethod and assign httpBody
urlRequest.httpMethod = "POST"
urlRequest.httpBody = postData
// Create dataTask
let dataTask = defaultSession.dataTask(with: urlRequest) { (data, response, error) in
// Handle your response here
}
// Fire the request
dataTask.resume()

Send Firebase Swift Push using NSURLSession HTTP Post

I set up my app so that users when they login subscribe to a topic with their user UID. Whenever a user sends a message to another user I will be calling the function below that I am hoping to trigger the push.
func sendPushNotification(toUser: String, message: String) {
let urlString = "https://fcm.googleapis.com/fcm/send"
let topic = "\topic\\(toUser)"
let url = NSURL(string: urlString)!
let paramString = "to=\(topic)"
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody = paramString.dataUsingEncoding(NSUTF8StringEncoding)!
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) in
do {
if let jsonData = data {
if let jsonDataDict = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.AllowFragments) as? [String: AnyObject] {
NSLog("Received data:\n\(jsonDataDict))")
}
}
} catch let err as NSError {
print(err.debugDescription)
}
}
task.resume()
}
Based on Firebase docs I am supposed to do this HTTP request:
Send to a single topic:
https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
"to": "/topics/foo-bar",
"data": {
"message": "This is a Firebase Cloud Messaging Topic Message!",
}
}
I am struggling to see what I pass in the paramString for the message to be sent based off of their example. Also, where do I define the Authorization:key=
Sending a message with Firebase Cloud Messaging requires that you provide your server key in the Authorization header. As the name suggests, this key should only be used in code that runs on an app server (or other infrastructure that you control). Putting the server key into the app that you ship to your users, means malicious users can use it to send messages on your behalf.
From the Firebase documentation on sending messages to topics (emphasis mine):
From the server side, sending messages to a Firebase Cloud Messaging topic is very similar to sending messages to an individual device or to a user group. The app server sets the to key with a value like /topics/yourTopic.

How to code in Xcode/Swift 'post' API to post votes to Drupal7 Fivestar module field with Voting API Services

I am a beginner. How do I code a 'Post' request to submit a vote to the Drupal 7 Fivestar module field ("field_fivestar_rating') of my content nodes? From my research, it seems to me the Fivestar accesses the Voting API. I've set up the Drupal Voting API services
This page https://www.drupal.org/node/2145873 suggests that to set votes I need to do a POST to rest/votingapi/set_votes.json with this json:
{
"votes": [
{
entity_id: 2,
value_type: "points",
tag: "vote",
value: 11
}
]
}
How do I add these parameters or adapt my below code to send eg vote 10 to node 1234 (Nid 1234) to post to the field 'field_fivestar_rating'. Thank you for any help/tips you could kindly give? Here is the code I'm trying:
// Define server side script URL
let ratingscriptUrl = "https://example.com/rest/votingapi/set_votes.json"
// Create NSURL Ibject
let myUrl = NSURL(string: ratingscriptUrl)
// Create URL Request
let request = NSMutableURLRequest(URL:myUrl!);
// Set POST request
request.HTTPMethod = "POST"
// Add parameters for voting API 'ratings' field of node
let result: Dictionary<String, AnyObject> = ["entity_id": 2, "value_type" : "points", "tag": "vote", "value": 11]
let json = JSON(result).rawString()
request.HTTPBody = json!.dataUsingEncoding(NSUTF8StringEncoding)
// Execute HTTP Request
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
// Check for error
if error != nil
{
print("error=\(error)")
return
}
Xcode brings up error message "use of unresolved identifier JSON" on this line:
let json = JSON(result).rawString()