RESTful API Client Interactions - php

So I am writing an API, and I am fearful that the code I am writing is going to become messy very quickly.
Some pages I need to be fetching data from several different resources from the API, and I am ending up with a whole bunch of try and catch statements everywhere. For example:
$topic_id = 100;
try
{
$topic = AwesomeAPI::get('topics/' . $topic_id);
$parts = AwesomeAPI::get('parts?topic_id=' . $topic_id);
try
{
// Get another resource here
}
catch (Exception $e)
{
// Error
}
}
catch (Exception $e)
{
return Response::error('404');
}
I am confident that this code is quite messy, and it gets even worse if I have to loop through a resource and grab another resource in the loop. Yuck.
I am wondering how to best approach client interactions with an API in a neat fashion.

As I commented before, in my opinion you should have all your API logic inside a class and therefore inside methods. So instead of writing code like the one posted, you can write something like this:
$api = new AwesomeAPI();
$topic = $api->GetTopic($topic_id);
And your AwesomeAPI class could look something like this:
public class AwesomeAPI()
{
public $topic_url = 'somewebsite.com/topics?id{0}';
function GetTopic($topicId)
{
//Some code here
$response = 'Some response (could be a JSON Document)';
return $response;
}
}
This way your code in the application will be more elegant and clear.
Hope this helps you

Related

Getting the XML from a response using the Authorize.Net PHP SDK

I have written some functions using Authorize.Net's PHP SDK's that look like the following:
public function getCustomerProfiles() {
$customerProfiles = array();
// Before we can get customer profiles, we need to get a list of all customer id's.
$customerIdListRequest = new AnetAPI\GetCustomerProfileIdsRequest();
$customerIdListRequest->setMerchantAuthentication(self::getMerchantAuth(Config::LOGIN_ID, Config::TRANSACTION_KEY));
$customerIdListController = new AnetController\GetCustomerProfileIdsController($customerIdListRequest);
$customerIdListResponse = $customerIdListController->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::SANDBOX);
if(($customerIdListResponse != null) && ($customerIdListResponse->getMessages()->getResultCode() == "Ok")) {
// TODO: Investigate warning about no method named getIds().
foreach( $customerIdListResponse->getIds() as $id ) {
// Now we can get each customer profile.
$request = new AnetAPI\GetCustomerProfileRequest();
$request->setMerchantAuthentication(self::getMerchantAuth(Config::LOGIN_ID, Config::TRANSACTION_KEY));
$request->setCustomerProfileId($id);
$controller = new AnetController\GetCustomerProfileController($request);
$response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::SANDBOX);
if(($response != null) && ($response->getMessages()->getResultCode() == "Ok")) {
// TODO: Investigate warning about no method named getProfile()
// Add it to the array.
array_push($customerProfiles, $response->getProfile()->xml);
} else {
throw new \Exception($response->getMessages()->getMessage());
}
}
} else {
throw new \Exception($customerIdListResponse->getMessages()->getMessage());
}
return $customerProfiles;
}
Currently, I'm just returning an array of objects. I'd prefer to get the raw XML response. Is this functionality available via Authorize.Net's PHP SDK? Or am I better of using something like Guzzle and making the request manually?
Looking at the source code I think it would be simple enough.
Look the execute method that is invoked by executeWithApiResponse there. See xmlResponse? Just need to store that as a class property (and add a public getter), or maybe tweak the function to take an extra argument telling it to return the raw response. Could hack it, or better yet, extend that ApiOperationBase class (note the interface IApiOperation gives you a outline to follow).
Seeing that serializer also...
$this->apiResponse = $this->serializer->deserialize( $xmlResponse, $this->apiResponseType , 'xml');
Could maybe do something more elegant with that. But not as clear as path I first described.

Created my own PHP API

Hello StackOverflow community
Currently I'm in small project, where a API is required.
I tested some SOAP WSDL and restFul API's, but none worked for me. So I created my own API. As I'm not a professional programer, I want to know if my API is unsafe.
<?php
class API{
public function __construct(){
if($_SERVER['REQUEST_METHOD'] === 'POST'){
if(!empty($_POST)){
$data_array = array();
require_once('PreparePOST.php');
foreach($_POST as $key => $value)
array_push($data_array,array($value => $key));
echo new PreparePOST($data_array);
}else{return new Exception('No Data Requested');}
}else{return new Exception('Request not allowed');}
}
}$init = new API();
?>
Some serious validation and security stuff is done after PreparePOST($data_array);
E.g. only allowed parameters and character escaping.
Notice: This is only the POST implementation the GET implementation and an API Auth Token will be available later.
What are you thinking?
Is this compete nonsense?
Where are possible security issues?
How can I improove my code?
Btw. my project is a Tool, which transmits server infos from our customers (like HD capacity and backup logs) to our server, so we evaluate all server statistically.
Thanks for you advice
KR
As you say that the PreparePOST object does validation and security it would be ideal to share that code too to identify security issues.
One thing which springs to mind right away although not a security issue is that you should throw an Exception rather than return one. Also when you are initializing your API object you don't have any way to catch the exceptions which it may throw. See the try catch block which I've put below.
Also the code isn't super readable, perhaps this would be better:
<?php
class API
{
public function __construct()
{
if($_SERVER['REQUEST_METHOD'] === 'POST')
{
if(!empty($_POST))
{
$data = array();
require_once('PreparePOST.php');
foreach($_POST as $key => $value)
{
array_push($data, array($value => $key));
}
echo new PreparePOST($data);
}
else
{
throw new Exception('No Data Requested');
}
}
else
{
throw new Exception('Request not allowed');
}
}
}
try
{
$init = new API();
}
catch(Exception $e)
{
//handle the exception here
echo $e->getMessage();
}
?>
Specific coding style is down to preference however to keep it readable and maintainable you should definitely make good use of whitespace. There's absolutely nothing gained by keeping code bunched together. In fact quite the opposite.
I wouldn't say there's a need to call your $data variable $data_array. You can see from the code that it's an array, also separate arguments to functions with a comma and a space for readability ,. (When calling array_push).

Use try/catch as if/else?

I have a class that accepts user ID when instantiated. When that ID does not exist in the database, it will throw an exception. Here it is:
class UserModel {
protected $properties = array();
public function __construct($id=null) {
$user = // Database lookup for user with that ID...
if (!$user) {
throw new Exception('User not found.');
}
}
}
My client code looks like this:
try {
$user = new UserModel(123);
} catch (Exception $e) {
$user = new UserModel();
// Assign values to $user->properties and then save...
}
It simply tries to find out if the user exists, otherwise it creates a new one. It works, but I'm not sure if it's proper? If not, please provide a solution.
No this isn't proper, try catch blocks should be used to handle code where anomalous circunstaces could happen. Here you're just checking if the user exists or not so the best way to achieve this is with a simple if else.
from wikipedia definition of programing expception:
"Exception: an abnormal event occurring during the execution of a
routine (that routine is the "recipient" of the exception) during its execution.
Such an abnormal event results from the failure of an operation called by
the routine."
As #VictorEloy and #AIW answered, exceptions are not recommended for flow control.
Complementing, in your case, I would probably stick with a static method for finding existing users that would return an instance of UserModel if it finds, or null in case it does not. This kind of approach is used in some ORM libraries like Active Record from Ruby on Rails and Eloquent from Laravel.
class UserModel {
protected $properties = array();
public static function find($id) {
$user = // Database lookup for user with that ID...
if ($user) {
return new UserModel($user); // ...supposing $user is an array with its properties
} else {
return null;
}
}
public function __construct($properties = array()) {
$this->properties = $properties;
}
}
$user = UserModel::find(5);
if (!$user)
$user = new UserModel();
It is debatable, but I'm going to say this is NOT proper. It has been discussed before. See
Is it "bad" to use try-catch for flow control in .NET?
That seems like a proper behaviour as long as it doesn’t throw when $id is null (that way, you can assume a new one is to be created).
In the case of the code that uses your class, if you’re going to be inserting it with that same ID later, just insert it with that ID to begin with without checking – it could be possible, though unlikely, that something happens between the check and the insertion. (MySQL has ON DUPLICATE KEY UPDATE for that.)

Zend Action Controller - refactoring strategy

I've built a first-run web service on Zend Framework (1.10), and now I'm looking at ways to refactor some of the logic in my Action Controllers so that it will be easier for me and the rest of my team to expand and maintain the service.
I can see where there are opportunities for refactoring, but I'm not clear on the best strategies on how. The best documentation and tutorials on controllers only talk about small scale applications, and don't really discuss how to abstract the more repetitive code that creeps into larger scales.
The basic structure for our action controllers are:
Extract XML message from the request body - This includes validation against an action-specific relaxNG schema
Prepare the XML response
Validate the data in the request message (invalid data throws an exception - a message is added to the response which is sent immediately)
Perform database action (select/insert/update/delete)
Return success or failure of action, with required information
A simple example is this action which returns a list of vendors based on a flexible set of criteria:
class Api_VendorController extends Lib_Controller_Action
{
public function getDetailsAction()
{
try {
$request = new Lib_XML_Request('1.0');
$request->load($this->getRequest()->getRawBody(), dirname(__FILE__) . '/../resources/xml/relaxng/vendor/getDetails.xml');
} catch (Lib_XML_Request_Exception $e) {
// Log exception, if logger available
if ($log = $this->getLog()) {
$log->warn('API/Vendor/getDetails: Error validating incoming request message', $e);
}
// Elevate as general error
throw new Zend_Controller_Action_Exception($e->getMessage(), 400);
}
$response = new Lib_XML_Response('API/vendor/getDetails');
try {
$criteria = array();
$fields = $request->getElementsByTagName('field');
for ($i = 0; $i < $fields->length; $i++) {
$name = trim($fields->item($i)->attributes->getNamedItem('name')->nodeValue);
if (!isset($criteria[$name])) {
$criteria[$name] = array();
}
$criteria[$name][] = trim($fields->item($i)->childNodes->item(0)->nodeValue);
}
$vendors = $this->_mappers['vendor']->find($criteria);
if (count($vendors) < 1) {
throw new Api_VendorController_Exception('Could not find any vendors matching your criteria');
}
$response->append('success');
foreach ($vendors as $vendor) {
$v = $vendor->toArray();
$response->append('vendor', $v);
}
} catch (Api_VendorController_Exception $e) {
// Send failure message
$error = $response->append('error');
$response->appendChild($error, 'message', $e->getMessage());
// Log exception, if logger available
if ($log = $this->getLog()) {
$log->warn('API/Account/GetDetails: ' . $e->getMessage(), $e);
}
}
echo $response->save();
}
}
So - knowing where the commonalities are in my controllers, what's the best strategy for refactoring while keeping it Zend-like and also testable with PHPUnit?
I did think about abstracting more of the controller logic into a parent class (Lib_Controller_Action), but this makes unit testing more complicated in a way that seems to me to be wrong.
Two ideas (just creating an answer from the comments above):
Push commonality down into service/repository classes? Such classes would be testable, would be usable across controllers, and could make controller code more compact.
Gather commonality into action helpers.
Since you have to do this step every time a request is made, you could store that receive, parse and validate the received request in a Zend_Controller_Plugin which would be run every PreDispatch of all controllers. (Only do-able if your XML request are standardized) (If you use XMLRPC, REST or some standard way to build requests to your service, you could look forward those modules built in ZF)
The validation of the data (action specific) could be done in a controller method (which would then be called by the action(s) needing it) (if your parametters are specific to one or many actions of that controller) or you could do it with the patterns Factory and Builder in the case that you have a lot of shared params between controllers/actions
// call to the factory
$filteredRequest = My_Param_Factory::factory($controller, $action, $paramsArray) // call the right builder based on the action/controller combination
// the actual Factory
class My_Param_Factory
{
public static function factory($controller, $action, $params)
{
$builderClass = "My_Param_Builder_" . ucfirst($controller) . '_' . ucfirst($action);
$builder = new $builderClass($params);
return $builder->build();
}
}
Your builder would then call specific parameters validating classes based on that specific builder needs (which would improve re-usability)
In your controller, if every required params are valid, you pass the processing to the right method of the right model
$userModel->getUserInfo($id) // for example
Which would remove all of the dataprocessing operations from the controllers which would only have to check if input is ok and then dispatch accordingly.
Store the results (error or succes) in a variable that will be sent to the view
Process the data (format and escape (replace < with < if they are to be included in the response for example)), send to a view helper to build XML then print (echo) the data in the view (which will be the response for your user).
public function getDetailsAction()
{
if ($areRequestParamsValid === true) {
// process data
} else {
// Build specific error message (or call action helper or controller method if error is general)
}
$this->view->data = $result
}

Best practices to handle JSON data for API SDK

The company I work for has an API and I am porting that API over to PHP. Right now, the API returns to me a large JSON object and I'm trying to figure out how I should handle the data. I could have a whole bunch of "get" methods, like:
$t = new APIThing();
$t->getJSONObjects();
for ($i=0; ...) {
$t->getHeadline($i);
}
Or, I could return the JSON object and let people play with the data themselves, so that would be something like this
$t = new APIThing();
$t->getJSONObjects();
foreach ($t as $u) {
echo $u->headline;
}
So what do you think? Just expose the JSON object or wrap the whole thing up into functions?
instead of that you can have a class that gets anything from the JSON
class GETAPI {
protected $api;
function __construct(){
$this->api = new APIThing();
$this->api->getJSONObjects();
}
function getAllFromAPI($name){
foreach($this->api as $u){
echo $u->$name;
}
}
//or :
function getFromAPI($name, $index){
return $this->api[$index]->$name;
}
}
its rudimentary and could use some work, but that work over making many many get functions
than all you would have to do is something like:
$api = new GETAPI();
$api->getAllFromAPI('headline');
//or
echo $api->getFromAPI('headline', 1); // with one as the array index

Categories