Sunday, January 10, 2010

Paypal PDT

I thought I would follow up my previous post with one that points out some good practices, and potential pitfalls when using really simple interfaces.  The DS Volatility Trends Web site is going to use the Paypal PDT option, where a user will be redirected back to the DS Volatility Trends Web site after payment is complete. The API is VERY simple.  You tell Paypal which page to redirect to, and it redirects to that page with a single get paramer: tx.  You then use this parameter, and your user key to get more information about the tx and to verify it for security purposes.  Here is the output of the response for a first test, run against the sandbox, with user keys omitted:


SUCCESS
mc_gross=5.00
protection_eligibility=Eligible
address_status=confirmed
payer_id=
address_street=1+Main+St
payment_date=09%3A30%3A43+Jan+09%2C+2010+PST
payment_status=Completed
charset=windows-1252
address_zip=95131
first_name=Test
mc_fee=0.45
address_country_code=US
address_name=Test+User
subscr_id=
payer_status=verified
business=
address_country=United+States
address_city=San+Jose
payer_email=
txn_id=8NJ4974863519050H
payment_type=instant
last_name=User
address_state=CA
receiver_email=
payment_fee=0.45
receiver_id=
txn_type=subscr_payment
item_name=DS+Volatility+Trends+Newsletter
mc_currency=USD
residence_country=US
transaction_subject=
payment_gross=5.00



Here is a sample after I inserted a custom value:

SUCCESS
mc_gross=5.00
protection_eligibility=Ineligible
address_status=confirmed
payer_id=
address_street=1+Main+St
payment_date=09%3A06%3A15+Jan+10%2C+2010+PST
payment_status=Pending
charset=windows-1252
address_zip=95131
first_name=Test
address_country_code=US
address_name=Test+User
subscr_id=
custom=12631431526791
payer_status=verified
business=
address_country=United+States
address_city=San+Jose
payer_email=
txn_id=0LG419336A6914908
payment_type=echeck
last_name=User
address_state=CA
receiver_email=
receiver_id=
pending_reason=echeck
txn_type=subscr_payment
item_name=DS+Volatility+Trends+Newsletter
mc_currency=USD
residence_country=US
transaction_subject=
payment_gross=5.00



Can you see the potential issue?  Inexperienced developers often take the first result set and start parsing it, line by line.  Some pseudo-code to represent this:

//Code has other problems besides the one being highlighted...

//Get String from stream...
String[] values = returnString.split("\n");
//now get the values of each line, assuming they are in the correct order
mcGross = values[0].split("=")[1];
protectionEligibility = values[1].split("=")[1];
//continue with all other values..


The code above would break as soon as the new variable is added, since the variable is returned in the middle of the list, all variables after 'custom' will be offset by 1 in the index.  In addition, I don't see any specific guarantee that the order will always be the same (Although that would be a good practice for Paypal to implement...).  At any rate, it is better to handle the values in an order-neutral way.  In Java, I would do this by parsing the string and creating name-value pairs in a Map.  This requires a little more code up front, but will save lots of potential errors down the road.


//Better but still needs work to be robust....


Map values = new HashMap
String[] values = returnString.split("\n");
for(int i=0; i < values.length; i++ ) {
    String[] thisValue = values[i].split("=");
    values.add(thisValue[0], thisValue[1]);
}
//Now values has ALL the values if new ones are added or the order changes,
//we don't care.  We're also sure we set the value with the right key
mcGross = values.get("mc_gross");


As you can see, with the second implementation, the code will still work just fine with the new 'custom' variable returned in the results.  The order of the variables is no longer important, and frankly, I think it is more expressive - mc_gross key is clearly being tied to the mcGross variable.