Does REST API uses url encoding? - rest

Does RESTful APIs provides url encoding as default or do I have to encode it using other methods? I am using following code:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"xmlRequest=" . $input_xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300);
$data = curl_exec($ch);
curl_close($ch);

There is no 'standard REST'. So it's often very difficult to say something specific, because in some ways it's just an idea.
But if you restrict REST to HTTP apis, generally the 'best practice' is that you use url encoding, where this is expected/needed by HTTP and don't use url encoding where it's unexpected.
To get a better answer, rephrase the question with a specific example that made you wonder about this.

Related

Send HTTP streaming request in perl

I want to send xml request using HTTP streaming protocol . where transfer-encoding is "chunked". Currently i am using LWP::UserAgent to send the xml transaction.
my $userAgent = LWP::UserAgent->new;
my $starttime = time();
my $response = $userAgent->request(POST $url,
Content_Type => 'application/xml',
Transfer_Encoding => 'Chunked',
Content => $xml);
print "Response".Dumper($response);
But i am getting http status code 411 Length Required. Which means "client error response code indicates that the server refuses to accept the request without a defined "
How we can handle this while sending a request in chunked ?
LWP::UserAgent's API isn't designed to send a stream, but it is able to do so with minimal hacking.
use strict;
use warnings qw( all );
use HTTP::Request::Common qw( POST );
use LWP::UserAgent qw( );
my $ua = LWP::UserAgent->new();
# Don't provide any content.
my $request = POST('http://stackoverflow.org/junk',
Content_Type => 'application/xml',
);
# POST() insists on adding a Content-Length header.
# We need to remove it to get a chunked request.
$request->headers->remove_header('Content-Length');
# Here's where we provide the stream generator.
my $buffer = 'abc\n';
$request->content(sub {
return undef if !length($buffer); # Return undef when done.
return substr($buffer, 0, length($buffer), ''); # Return a chunk of data otherwise.
});
my $response = $ua->request($request);
print($response->status_line);
Using a proxy (Fiddler), we can see this does indeed send a chunked request:
There's no point in using a chunked request if you already have the entire document handy like in the example you gave. Instead, let's say wanted to upload the output of some external tool as it produced its output. To do that, you could use the following:
open(my $pipe, '-|:raw', 'some_tool');
$request->content(sub {
my $rv = sysread($pipe, my $buf, 64*1024);
die $! if !defined($rv);
return undef if !$rv;
return $buf;
});
But i am getting http status code 411 Length Required.
Not all servers understand a request with a chunked payload even though this is standardized in HTTP/1.1 (but not in HTTP/1.0). For example nginx only supports chunking within a request since version 1.3.9 (2012), see Is there a way to avoid nginx 411 Content-Length required errors?. If the server does not understand a request with chunked encoding there is nothing you can do from the client side, i.e. you simply cannot use chunked transfer encoding then. If you have control over the server make sure that the server actually supports it.
I've also never experienced browsers send such requests, probably since they cannot guarantee that the server will support such request. I've only seen mobile apps used where the server and app is managed by the same party and thus support for chunked requests can be guaranteed.

PayPal IPN stopped sending mc_shipping and custom fields

I've been using PayPal IPN for years, and on Sept 13, 2016, my IPN listener started having problems. It looks like the mc_shipping field isn't being returned at all now, and custom field is coming back empty (though I am sending the user's ID).
Here is the code I use to contact PayPal:
$ch = curl_init('https://www.paypal.com/cgi-bin/webscr');
$myemail = "molly#thetripclip.com";
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
if( !($res = curl_exec($ch)) ) {
$error = "CURL ERROR";
$text = "Got " . curl_error($ch) . " when processing IPN data";
include ("log_ipn_error.php");
curl_close($ch);
exit;
}
curl_close($ch);
Here is what I'm getting back from PayPal:
cmd=_notify-validate&mc_gross=4.95&protection_eligibility=Eligible&address_status=confirmed&item_number1=03&payer_id=[removed for security reasons]&address_street=[address removed for security reasons]&payment_date=09%3A04%3A13+Sep+14%2C+2016+PDT&payment_status=Completed&charset=windows-1252&address_zip=59422&first_name=[name removed for security reasons]&mc_fee=0.44&address_country_code=US&address_name=[name removed for security reasons]&notify_version=3.8&custom=&payer_status=unverified&business=molly%40thetripclip.com&address_country=United+States&num_cart_items=1&mc_handling1=0.00&address_city=Choteau&verify_sign=AuRlNZvMOhdn8iDWY5YoMB9iRTDzAIjG.3f9vIDCnjWeCMq94kt.qaLM&payer_email=[customer email removed for security reasons]&btn_id1=16432817&contact_phone=[phone no removed for security reasons]&txn_id=95R75212V2997631V&payment_type=instant&last_name=[name removed for security reasons]&address_state=MT&item_name1=5+Trip+Clip+Activities&receiver_email=[my email address]&payment_fee=0.44&quantity1=1&receiver_id=FSRPNTT2JQ9LE&txn_type=cart&mc_gross_1=4.95&mc_currency=USD&residence_country=US&transaction_subject=&payment_gross=4.95&ipn_track_id=73e7cbaf7590a
I've found one other person asking a similar question (with no answer), but I can't find anything from PayPal saying that they are changing the IPN fields.
I have been experiencing this same issue with multiple paypal accounts for about 1 month now. This appears to be an issue with paypal according to a response I received from their support site.
Thank you for contacting Merchant Technical Support.
Unfortunately, the problem you're experiencing is being caused by some technical issues with the PayPal system. Our engineers are currently working diligently on a solution to this problem. I am going to assign this ticket to our internal engineering ticket so that when the problem is resolved, you will be notified of its completion right away.
I would suggest anyone else with a similar issue submit a ticket at https://www.paypal-techsupport.com/ in hopes they resolve this issue quickly

Dropbox API Token Verification

This question follows on from my previous one. I thought I would perform a basic token authentication by calling the get_space_usage API function. I tried
$headers = array("Authorization: Bearer token",
"Content-Type:application/json");
$ch = curl_init('https://api.dropboxapi.com/2/users/get_space_usage/');
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
curl_setopt($ch,CURLOPT_POST,true);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
The documentation does not in fact indicate that it is necessary to provide a Content-Type header. However, without that header I get the message
Bad HTTP "Content-Type" header: "application/x-www-form-urlencoded". Expecting one of "application/json",...
Putting in that header but supplying no POST fields produces another error
request body: could not decode input as JSON
Just providing some dummy post data curl_setopt($ch,CURL_POSTFIELDS,json_encode(array('a'=>1))); does not do anything to remedy the situation. What am I doing wrong?
The documentation doesn't indicate that a Content-Type header is expected, because, since this endpoint doesn't take any parameters, no body is expected, and so there's no content to describe via a Content-Type header. Here's a working command line curl example, per the documentation:
curl -X POST https://api.dropboxapi.com/2/users/get_space_usage \
--header "Authorization: Bearer <ACCESS_TOKEN>"
Translating this to curl in PHP would involve making sure PHP also doesn't send up a Content-Type header. By default though, it apparently sends "application/x-www-form-urlencoded", but that isn't accepted by the API. If you do set a "application/json", the API will attempt to interpret the body as such, but won't be able to do so, since it isn't valid JSON, and so fails accordingly.
It's apparently not easy (or maybe not possible) to omit the Content-Type header with curl in PHP, so the alternative is to set "application/json", but supply valid JSON, such as "null". Here's a modified version of your code that does so:
<?php
$headers = array("Authorization: Bearer <ACCESS_TOKEN>",
"Content-Type: application/json");
$ch = curl_init('https://api.dropboxapi.com/2/users/get_space_usage');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, "null");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>

How to convert CURL command to Swift

I am learning to write my first IOS app that will query some basic OIDs from a Proliphix IP Network Thermostat. Proliphix supports several methods such as Curl; PHP and API GET & SET. Out of these methods, what would be the easiest in Swift?
Can someone tell me how to convert one of the the following methods for Swift?
Here are examples of these from the Proliphix API that can be found on a google search.
Curl
Get
curl –u hostname:password –-data OID1.1= http://192.168.1.100:8100/get
Set
curl –u hostname:password --data OID1.10.5=120 --data submit=Submit
http://192.168.1.100:8100/pdp
API GET
The URL used is /get. An API GET request is a list of OIDs where their value is not specified. A properly formatted request should provide the Content-Length header. . The entry is the encoded basic authentication word (See RFC 2617 -HTTP Authentication: Basic and Digest Access Authentication).
Request
POST /get HTTP/1.1
Authorization: Basic <credentials>
Content-Type: application/x-www-form-urlencoded
User-Agent: Jakarta Commons-HttpClient/2.0.2
Host: 192.168.111.114:8214
Content-Length: 92
OID1.10.9=&OID1.2=&OID1.1=&OID1.4=&OID1.8=&OID2.7.1=&
Response
HTTP/1.1 200 OK
Cache-control: no-cache
Server: Ubicom/1.1
Content-Length: 166
OID1.10.9=example#proliphix.com&OID1.2=SW Dev 114&OID1.1=therm_rev_2 0.1.40&OID1.4=192.168.111.114&OID1.8=00:11:49:00:00:58&OID2.7.1=NT100
API SET
The URL used is /pdp . An API SET is similar to the API GET for the request message, except that the desired value is provided at the equals sign. The response is formatted differently. The entry is the encoded basic authentication word (See RFC 2617 -HTTP Authentication: Basic and Digest Access Authentication). The last item in the request must be “submit=Submit”. Do not include an ‘&’ after the "submit=Submit".
Request
POST /pdp HTTP/1.1
Authorization: Basic <credentials>
Content-Type: application/x-www-form-urlencoded
User-Agent: Jakarta Commons-HttpClient/2.0.2
Host: 192.168.111.114:8214
Content-Length: 193
Response
HTTP/1.1 200 OK
Cache-control: no-cache
Server: Ubicom/1.1
Content-Length: 308
PHP
PHP is a web-server specific scripting language, akin to mod_perl. It integrates well into Apache and offer many web-specific libraries as part of the base system.
Get
$oids = array('OID1.4'=>'', // commonIpAddr
'OID1.10.5'=>'',
‘submit’=>’Submit’); // commonCallhomeInterval
$url = “http://192.168.1.100:8100/get”;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPGET, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$myHeader = array("Content-Type: application/x-www-form-urlencoded" ); curl_setopt($ch, CURLOPT_HTTPHEADER, $myHeader);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($oids)); $response = curl_exec($ch);
curl_close($ch);
$oids = array();
parse_str($response, $oids); // converts '.' to underscore
$localip = $oids['OID1_4'];
$interval = $oids['OID1_10_5']; // in minutes
I would say that you should use the API that Proliphix is providing.
As you can see, they provide an example, and you've already managed to figure out how to provide the correct parameters through cURL so now you "just" need to convert this to Swift.
For this you need a HTTP networking API, you could use either the NSURLSession API provided by Apple, or perhaps Alamofire, just to mention a pair.
These API's take an URL which would be /get or /pdp in your case. Then you need to tell them wether this is a GET or a POST request. If the API needs any data (like the OID parameters in your case), you'll need to provide that as well and then you need to set up eventual headers.
Then you send your request and wait for an answer, which you then react to.
Here is an example on how to do this with NSURLSession:
if let url = NSURL(string: "http://httpbin.org/post"){
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST" //Or GET if that's what you need
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") //This is where you add your HTTP headers like Content-Type, Accept and so on
let params = ["OID1.2" : "SW+Dev+114", "OID1.4" : "192.168.111.114"] as Dictionary<String, String> //this is where you add your parameters
let httpData = NSKeyedArchiver.archivedDataWithRootObject(params) //you need to convert you parameters to NSData or to JSON data if the service accepts this, you might want to search for a solution on how to do this...hopefully this will get you in the right direction :-)
request.HTTPBody = httpData
let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request, completionHandler: { (returnData, response, error) -> Void in
var strData = NSString(data: returnData, encoding: NSUTF8StringEncoding)
println("\(strData)")
}).resume() //Remember this one or nothing will happen :-)
}
Hope this gets you in the right direction. You could also do a Google search for NSURLSession or Alamofire tutorial, now that you know what to search for.

Constructing a Paypal OAuth

I am trying to get an access token for Paypal's RESTful web services but unfortunately not making any headway. This is my first time dealing with REST, so please be patient with me :)
Here is what I have:
Client_id and secret as provided by Paypal for a sandbox account through the paypal developer website.
The ENDpoint: https://api.sandbox.paypal.com/v1/oauth2/token
The documentation that i am referring to is : https://developer.paypal.com/webapps/developer/docs/integration/direct/make-your-first-call/
Now the juicy part of making that API call. I am developing in PHP so I am using CURL to make the calls. something like this;
const CLIENT_ID = ****..*** ;
const SECRET = ***..***;
$base64EncodedClientID = base64_encode(self::CLIENT_ID . ":" . self::SECRET);
$headers = array("Authorization" => "Basic " . $base64EncodedClientId, "Accept" =>"*/*", "Content-type" => "multipart/form-data");
$params = array("grant_type"=>"client_credentials");
$url = "https://api.sandbox.paypal.com/v1/oauth2/token";
$ch = curl_init();
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_HEADER, $headers);
curl_setopt($ch,CURLOPT_POSTFIELDS,$params);
$response = curl_exec($ch);
Pretty vanilla right? Except that I do not get the JSON response that I expect from Paypal but false. This implies that my CURL request was not prepared well, perhaps I am setting the header incorrectly or the params are incorrect. Regardless, the URL is definitely accessible since I was able to access it through command line with the same credentials and got the desired JSON response.
The one glaring problem I have with the above code is that I am providing the client_id and secret as a header option. basic sense tells me that they need to be part of the POST field data However, if you look at line 89 of this Github code https://github.com/paypal/rest-api-sdk-php/blob/master/lib/PayPal/Auth/OAuthTokenCredential.php (Paypals' official PHP REST SDK), it clearly states that the credentials are being set in the header field.
Where am I messing up ?
With curl you don't need to manually generate the base64 encoded value for the Authorization header just use the CURLOPT_USERPWD option and pass the clientID and secret as the user:pwd.
curl_setopt($curl, CURLOPT_USERPWD, $clientId . ":" . $clientSecret);
here is a sample - look for the get_access_token() method:
https://github.com/paypal/rest-api-curlsamples/blob/master/execute_all_calls.php
Had the exact same problem you ran into. The issue is that PayPal accepts the content-type application/x-www-form-urlencoded. Your code is attempting to send multipart/form-data. CURL by default sends application/x-www-form-urlencoded, but you are passing your data as an array. Instead, you should be passing the data like a url encoded string since this is what application/x-www-form-urlencoded data looks like:
$params = "grant_type=client_credentials";
Your headers have the same problem. Pass it as an array of strings instead of a dictionary. For instance:
$headers = ["Authorization Basic " . $base64EncodedClientId];
Also, you don't need those other two headers you passed in. The 'Accept' header does nothing since you are accepting everything, and the Content-type is wrong for one, and two is defaulted to 'application/x-www-form-urlencoded' by CURL so unless you need to override that, there is no need.