How to test the client in the absence of API? - php

I decided to write a client that sends http requests to the API. There are 3 types of requests: GET, POST, PUT. We need to write unit tests using phpunit, which will allow us to test the functionality without writing an API. My first thought was to use a mock object. Having read enough literature, I can’t understand in any way how to do this. As I understand it, I need to make a stub for the API wherever my requests go. Please tell me in which direction to move in order to solve the problem.
<?php
namespace Client;
class CurlClient implements iClient
{
private $domain;
public function __construct($domain = "http://example.com")
{
$this->domain = $domain;
}
public function getAllComments()
{
$ch = curl_init($this->domain.'/comments');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$comments = curl_exec($ch);
$comments = json_decode($comments);
curl_close($ch);
return $comments;
}
public function addNewComment($data)
{
$ch = curl_init($this->domain.'/comment');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_exec($ch);
$statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$statusCode = (string)$statusCode;
$statusCode = (int)$statusCode[0];
curl_close($ch);
return $statusCode == 2 ? true : false;
}
public function updateComment($id, $data)
{
$ch = curl_init($this->domain.'/comment/'.$id);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_exec($ch);
$statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$statusCode = (string)$statusCode;
$statusCode = (int)$statusCode[0];
curl_close($ch);
return $statusCode == 2 ? true : false;
}
}

Here is a simple mock example using phpunit. phpunit's mocking capabilities are extensive, for more info phpunit documentation - test doubles
<?php
use PHPUnit\Framework\TestCase;
// Use the getMockBuilder() method that is provided by the
// PHPUnit\Framework\TestCase class to set up a mock object
// for the CurlClient object.
class CurlClientTest extends TestCase
{
public function testAddNewComment()
{
// Create a mock for the CurlClient class,
// only mock the update() method.
$client = $this->getMockBuilder(CurlClient::class)
->setMethods(['addNewComment'])
->getMock();
$map = [
['hello', true],
[123, false]
];
$client->method('addNewComment')->will($this->returnValueMap($map));
$this->assertEquals(true, $client->addNewComment('hello'));
$this->assertEquals(false, $client->addNewComment(123));
}
}

Related

I am trying to hit a certain local MPESA Payment API but am getting an error

I am trying to get a response from MPESA payment API using laravel but I am getting an error . My code is as below
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class MPESA_AUTH extends Controller
{
public function Authorize(){
$url = 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
$CONSUMER_KEY= 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$CONSUMER_SECRET= 'xxxxxxxxxxxx';
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
$credentials = base64_encode($CONSUMER_KEY,$CONSUMER_SECRET);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Authorization: Basic '.$credentials)); //setting a custom header
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$curl_response = curl_exec($curl);
$curl_json=json_decode($curl_response);
return $curl_json;
}
}
The error am getting is as below
The Base controller uses Illuminate\Routing\Controller trait which has an 'authorize()' function. Your function declaration is clashing with it.
Change your controller method name to anything else(other than 'authorize') and you should be good to go
You should use a different function name in place of "Authorize". This is because "authorize" in controllers is a preserved name used in the parent class Controller.

Laravel curl in middleware gets added to response

I have a service, that needs to authenticate via another service.
For this I setup a Middleware that extracts the Authorization header out of my initial request, and then creates a curl request to the Auth Service with the header set.
public function handle($request, Closure $next) {
$authHeader = $request->header('Authorization');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://api.user.eventmanager.app/getAccess");
curl_setopt($ch,CURLOPT_HTTPHEADER,array(
'Authorization: ' . $authHeader,
'Origin: http://api.asdf.rerere.app'
));
$result = curl_exec($ch);
if($result) {
curl_close($ch);
return $next($request);
} else {
curl_close($ch);
return response("Invalid Token or expired Token", 401);
}
}
The request returns the requested ressource as expected, but also adds in the User object in the response (the one I get via the curl request, I want to do further checking with the user object in the middleware, but I dont want it returned to the inital request).
Here is what my controller for the response I want looks like:
public function show($id)
{
$event = Event::with('timeTableEntries', 'venue', 'bands')->find($id);
if(!$event) {
return $this->respondNotFound('Event does not exist!');
}
return $this->respond([
'data' => $this->eventTransformer->transform($event)
]);
}
Somehow the User Object from the curl ends up in my respons.
Any idea why this happens?
You're not returning transfer on your curl options, which stops the response from outputting and returns the string instead.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
as per http://php.net/manual/en/function.curl-setopt.php

return value from closure without reference

I am using the curl option CURLOPT_HEADERFUNCTION along with a closure to perform some basic data manipulation. As per the php docs, the function / callback must return the length of the header on each call.
$headers = [];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADERFUNCTION, function($curl, $headerLine) use (&$headers) {
$headers[] = $headerLine;
return strlen($headerLine);
});
$response = curl_exec($curl);
curl_close($curl);
return $headers;
I am using references to return the value which works fine. I am just curious if there are other ways to return this value without using references or using a callback?
You can specify the callback function to be a class method:
curl_setopt($curl, CURLOPT_HEADERFUNCTION, array($this, 'someOtherFunction'));
In that other function, you can have access to anything $this has access to:
protected function someOtherFunction($curl, $headerLine)
{
$this->headers[] = $headerLine;
return strlen($headerLine);
}
* This answer assumes you're inside of a class context to begin with

Fabric Digits oauth authentication in PHP

I've got an app which works with Digits as authentication.
Client-side works perfectly, but I'm not able to make the server user authentication through oAuth.
My server is developed with Laravel, so it's PHP.
My endpoint is under https, so everything should be ready to make the call.
I solved by myself!
Here's the code that makes correctly the authentication through Digits O-Auth.
The function that makes authentication is inside an AuthManager class and I call in this way:
$obj = AuthManager::verifyUser($request->header('X-Auth-Service-Provider'),$request->header("X-Verify-Credentials-Authorization"));
And here's the function that makes the magic:
public static function verifyUser ($xAuthServiceProvider, $xVerifyCredentialsAuthorization)
{
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL, $xAuthServiceProvider);
curl_setopt($curl,CURLOPT_HTTPHEADER, array(
'Content-length: 0',
'Content-type: application/json',
'Authorization: '.$xVerifyCredentialsAuthorization,
));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$content = curl_exec($curl);
$info = curl_getinfo($curl);
curl_close($curl);
$obj = json_decode($content, true);
return $obj;
}
If you have any problem, don't hesitate to write here!
EDIT WITH EXAMPLE FUNCTION ABOUT HOW TO GET DATA FROM O-AUTH
public function authenticate (Request $request)
{
$obj = AuthManager::verifyUser($request->header('X-Auth-Service-Provider'),$request->header("X-Verify-Credentials-Authorization"));
if(isset($obj["errors"]))
{
return "error!";
}
$digits_token = $obj["access_token"]["token"];
$digitsId = $obj["id"];
/*
the variables above are returned by O-auth server-server authentication
*/
}

how to call restful zend controller usin curl in php?

<?php
require_once 'Zend/Session/Namespace.php';
class ApiController extends Zend_Rest_Controller
{
public function init()
{
$this->_helper->layout->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
}
public function indexAction()
{
$query=$this->getRequest()->getParam('query');
$this->getResponse()
->appendBody("hi");
$this->getResponse()->setHttpResponseCode(200);
}
public function getAction()
{
$query=$this->getRequest()->getParam('id');
$this->getResponse()
->appendBody($query);
}
public function postAction()
{
$this->getResponse()
->setHttpResponseCode(200)
->appendBody("From postAction() creating the requested article");
}
public function putAction()
{
$this->getResponse()
->appendBody("From putAction() updating the requested article");
}
public function deleteAction()
{
$this->getResponse()
->appendBody("From deleteAction() deleting the requested article");
}
}
Above is my REST API I am trying to call it from php curl but I don't know how to call post method.
I have also made entry in bootsrap to default module\ using rest route.
Here is a snippet of my code:
<?php
$ch = curl_init('http://apanel3.newfront.local/api');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 4);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
$curlresult = curl_exec($curl_connection);
print_r($curlresult);
?>
I am trying to call my api using following curl code. It is calling indexAction. Even thought i have set curlopt_post to true, I am not getting desired output.
I believe there are lot of examples for php curl + post. Do you know how to access your actions (make http calls generally, without curl) ?
Here is another answer to the link to the similar question.
If you are trying to access your API from another zend based application and want to use zend inbuilt method then, you should check Zend_Http_Client there is an adapter for curl if you want to specifically use curl adapter.
EDIT:
On your client side:
<?php
//
// A very simple PHP example that sends a HTTP POST to a remote site
//
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "'http://apanel3.newfront.local/api'");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "query='where post_parameter = query'");
// receive server response ...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec($ch);
curl_close($ch);
// further processing ....
if($server_output == 'OK') {
echo 'Test passed';
} else {
echo $server_output;
}
?>
On your API side for indexAction:
public function indexAction()
{
$query=$this->getRequest()->getParam('query');
if($this->getRequest()->isPost()) {
// method == post, do your processing whatever required here ....
$this->_forward('post',null,null,$query);
} elseif ($this->getRequest()->getMethod() == 'GET') {
// method == get
$this->_forward('get',null,null,$query);
}else {
// bad request response code 400
$this->getResponse()
->appendBody("not a valid request");
$this->getResponse()->setHttpResponseCode(400);
}
}
Edit:
My mistake I didn't realize you were extending Zend_Rest_Controller, your code for controller seems fine. Now you probably know about making curl request via PHP.
On how to make PUT Request please check this question

Categories