I'm using Behat to test a REST API my team has developed. When a particular resource is created the API returns a 201 and a Location header in the response.
The API was developed using using Symfony5 and it's using the Symfony HttpKernel as the client:
$kernel->handle($request);
I would like to assert through my behat test that it returns a 201 and the headers contains the Location. However the client is automatically following the Location header and as such I can't verify that.
Is there a way to turn off following redirects using the existing kernel component? I've not been able to find a way to do this.
You can create your own context and check the Response
<?php declare(strict_types=1);
namespace App\Tests\Features\Context;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Kernel;
final class HttpContext
{
private Kernel $kernel;
private Response $response;
public function __construct(Kernel $kernel)
{
$this->kernel = $kernel;
}
/**
* #When I request :method to :uri
*/
public function iRequest(string $method, string $uri): void
{
$this->request($method, $uri);
}
/**
* #Then the location header should be :location
*/
public function assertLocationHeader(string $location): void
{
// make your assertion
dd($this->response->headers->get('location'), $location);
}
private function request(string $method, string $uri): void
{
$request = Request::create($uri, $method, [], [], [], [], null);
$this->response = $this->kernel->handle($request);
$this->kernel->terminate($request, $this->response);
}
}
Related
I'm trying to add Paypal's smart buttons to my website.
I followed the tutorial here:
https://developer.paypal.com/docs/checkout/integrate/
Anyway, this is the code in my payment.html file:
<!-- End of Body content -->
</body>
<script src="https://www.paypal.com/sdk/js?client-id=sb¤cy=ILS&locale=he_IL&vault=true"></script>
<script>
paypal.Buttons({
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '49.99'
}
}]
});
},
onApprove: function(data, actions) {
return actions.order.capture().then(function(details) {
alert('Transaction completed by ' + details.payer.name.given_name);
// Call your server to save the transaction
return fetch('../paypal.php', {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
orderID: data.orderID
})
});
});
}
}).render('#pay');
</script>
This is my paypal.php file:
<?php
namespace Sample;
require __DIR__ . '/vendor/autoload.php';
//1. Import the PayPal SDK client that was created in `Set up Server-Side SDK`.
use Sample\PayPalClient;
use PayPalCheckoutSdk\Orders\OrdersGetRequest;
class GetOrder
{
// 2. Set up your server to receive a call from the client
/**
*You can use this function to retrieve an order by passing order ID as an argument.
*/
public static function getOrder($orderId)
{
// 3. Call PayPal to get the transaction details
$client = PayPalClient::client();
$response = $client->execute(new OrdersGetRequest($orderId));
/**
*Enable the following line to print complete response as JSON.
*/
// echo json_encode($response->result);
print "Status Code: {$response->statusCode}\n";
print "Status: {$response->result->status}\n";
print "Order ID: {$response->result->id}\n";
print "Intent: {$response->result->intent}\n";
print "Links:\n";
foreach($response->result->links as $link)
{
print "\t{$link->rel}: {$link->href}\tCall Type: {$link->method}\n";
}
// 4. Save the transaction in your database. Implement logic to save transaction to your database for future reference.
print "Gross Amount: {$response->result->purchase_units[0]->amount->currency_code} {$response->result->purchase_units[0]->amount->value}\n";
// To print the whole response body, uncomment the following line
// echo json_encode($response->result, JSON_PRETTY_PRINT);
}
}
if (!count(debug_backtrace()))
{
$request_body = file_get_contents('php://input');
$json = json_decode($request_body,true);
$id=$json["orderID"];
GetOrder::getOrder($id, true);
}
and this is my paypal_loader.php file:
<?php
namespace Sample;
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
ini_set('error_reporting', E_ALL); // or error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
class PayPalClient
{
/**
* Returns PayPal HTTP client instance with environment that has access
* credentials context. Use this instance to invoke PayPal APIs, provided the
* credentials have access.
*/
public static function client()
{
return new PayPalHttpClient(self::environment());
}
/**
* Set up and return PayPal PHP SDK environment with PayPal access credentials.
* This sample uses SandboxEnvironment. In production, use LiveEnvironment.
*/
public static function environment()
{
$clientId = getenv("CLIENT_ID") ?: "myclientidhere";
$clientSecret = getenv("CLIENT_SECRET") ?: "mysecrethere";
return new SandboxEnvironment($clientId, $clientSecret);
}
}
I get the javascript alert ("transaction completed by....") on the payment.html after using the sandbox account to pay and the payment is actually being completed the problem is when I try to verify it on the server side the response I'm getting from the paypal.php is:
<br />
<b>Fatal error</b>: Uncaught BraintreeHttp\HttpException: {"error":"invalid_client","error_description":"Client Authentication failed"} in C:\xampp\htdocs\firstGear\schoolcontrol\vendor\braintree\braintreehttp\lib\BraintreeHttp\HttpClient.php:185
Stack trace:
#0 C:\xampp\htdocs\firstGear\schoolcontrol\vendor\braintree\braintreehttp\lib\BraintreeHttp\HttpClient.php(97): BraintreeHttp\HttpClient->parseResponse(Object(BraintreeHttp\Curl))
#1 C:\xampp\htdocs\firstGear\schoolcontrol\vendor\paypal\paypal-checkout-sdk\lib\PayPalCheckoutSdk\Core\AuthorizationInjector.php(37): BraintreeHttp\HttpClient->execute(Object(PayPalCheckoutSdk\Core\AccessTokenRequest))
#2 C:\xampp\htdocs\firstGear\schoolcontrol\vendor\paypal\paypal-checkout-sdk\lib\PayPalCheckoutSdk\Core\AuthorizationInjector.php(29): PayPalCheckoutSdk\Core\AuthorizationInjector->fetchAccessToken()
#3 C:\xampp\htdocs\firstGear\schoolcontrol\vendor\braintree\braintreehttp\lib\BraintreeHttp\HttpClient.php(64): PayPalCheckoutSdk\Core\AuthorizationInjector->inject(Object(PayPalChecko in <b>C:\xampp\htdocs\firstGear\schoolcontrol\vendor\braintree\braintreehttp\lib\BraintreeHttp\HttpClient.php</b> on line <b>185</b><br />
I tripled check my client_id and client_secret, and can't figure out for hours now where's the problem in the code as it's pretty much copy pasted from paypal's website.
Would appreciate your help, thanks in advance.
I am trying to get data included in a JWT Token with Angular 6.
I can do the login action, and return the token with Lumen 5.6 - tymondesigns/jwt-auth
But then, when I print it in JS, I get:
iat: 1531073200
iss: "https://api.kz-api.test/auth/login"
jti: "taCmXQoo0jWs4y7t"
nbf: 1531073200
prv: "87e0af1ef9fd15812fdec97153a14e0b047546aa"
sub: 1
I thought I should have the user object in ‘sub’ array as it identifies the subject of the JWT, but I can only find 1….
What’s wrong with my code:
/**
* Authenticate a user and return the token if the provided credentials are correct.
*
* #return mixed
*/
public function authenticate()
{
// Find the user by email
$user = User::where('email', $this->request->input('email'))->first();
if (!$user) {
return response()->json('login.wrong_email', HttpResponse::HTTP_UNAUTHORIZED);
}
$credentials = Input::only('email', 'password');
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json('login.wrong_password', HttpResponse::HTTP_UNAUTHORIZED);
}
return response()->json(compact('token'), HttpResponse::HTTP_ACCEPTED);
}
I am trying to setup a RESTFUL web service using FOSRestBunble, but I have some problem making POST calls, here's my setup:
app/config/routing.yml
rest:
type: rest
resource: "routing_rest.yml"
prefix: /api
app/config/routing_rest.yml
Rest_User:
type: rest
resource: "#AppBundle/Resources/config/routing_rest.yml"
AppBundle/Resources/config/routing_rest.yml
rest_application:
type: rest
resource: "AppBundle:Rest"
name_prefix: api_
AppBundle/Controller/RestController.php
class RestController extends FOSRestController
{
public function testrestAction(Request $request)
{
$r = [
'is' => 'TEST'
];
return $r;
}
public function getArticleAction()
{
$r = [
'is' => 'GET'
];
return $r;
}
public function postArticleAction()
{
$r = [
'is' => 'POST'
];
return $r;
}
}
I also made PUT and DELETE test methods. so when I do some test call
GET /api/testrest
{
"is": "TEST"
}
GET /api/article
{
"is": "GET"
}
POST /api/article
No route found for "POST /api/article": Method Not Allowed (Allow: GET, HEAD) (405 Method Not Allowed)
PUT and DELETE are also fine. Am I missing some configuration?
second problem: if I make a API folder inside Controller folder, I change the namespace for RestController to "namespace AppBundle\Controller\API;" and I update "AppBundle/Resources/config/routing_rest.yml" to
resource: "AppBundle:API:Rest"
then I got this message:
Can't locate "AppBundle:API:Rest" controller in /var/www/ws/app/config/routing_rest.yml (which is being imported from "/var/www/ws/app/config/routing.yml").
any help appreciated
1-option, run app/console debug:router (or bin/console debug:router if v > 2.8), to list generated routes;
2-option, add RouteResource annotation to class (eg. article), rename postArticleAction to postAction and check POST /api/articles is responding or not;
3-option, add article url explicitly with #POST annotation, eg. /** #Post("article") */
It seems that Laravel 5 by default applies the CSRF filter to all non-get requests. This is OK for a form POST, but might be a problem to an API that POSTs DELETEs etc.
Simple Question:
How can I set a POST route with no CSRF protection?
Go to app/Http/Middleware/VerifyCsrfToken.php and then enter your routes(for which you want to disable csrf token) in the $except array.
for example:
class VerifyCsrfToken extends BaseVerifier
{
protected $except = [
'/register'
];
}
You can exclude URIs from CSRF by simply adding them to the $except property of the VerifyCsrfToken middleware (app/Http/Middleware/VerifyCsrfToken.php):
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
'api/*',
];
}
Documentation: http://laravel.com/docs/5.1/routing#csrf-protection
My hack to the problem:
CSRF is now a "middleware" registered globally in App\Http\Kernel.php. Removing it will default to no CSRF protection (Laravel4 behavior).
To enable it in a route:
Create a short-hand key in your app/Providers/RouteServiceProvider.php :
protected $middleware = [
// ....
'csrf' => 'Illuminate\Foundation\Http\Middleware\VerifyCsrfToken',
];
You can now enable it to any Route:
$router->post('url', ['middleware' => 'csrf', function() {
...
}]);
Not the most elegant solution IMO...
just listen to this. Just before 30 minute i was facing this same problem. Now it solved. just try this.
Goto App -> HTTP-> Kernel
open the kernel file.
there you can see : \App\Http\Middleware\VerifyCsrfToken::class,
just disable this particular code using //
Thatz it! This will work!
So that you can remove the middleware from the API calling (if you want so..)
I want to test my controller which works on subdomain www.username.domain.com
The problem is when I dispatch in ControllerTestCase it throws Zend_Controller_Dispatcher_Exception
routes.php:
$userRouter = new Zend_Controller_Router_Route_Hostname(':user.domain.com'));
$router->addRoute('user', $userRouter->chain(new Zend_Controller_Router_Route('',
array('controller' => 'user'))));
UserControllerTest:
require_once 'AbstarctControllerTestCase.php';
class UserControllerTest extends AbstarctControllerTestCase
{
public function setUp()
{
$this->cleardb();
parent::setUp();
}
public function testRoute()
{
$this->dispatch('www.username.domain.com');
$this->assertController('user');
}
}
AbstarctControllerTestCase:
abstract class AbstarctControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
public function setUp()
{
$this->bootstrap = array($this, 'appBootstrap');
parent::setUp();
}
public function appBootstrap()
{
chdir(dirname(dirname(dirname(dirname(__FILE__)))));
require 'application/test/controllerunit/routes.php';
Zend_Session::start();
}
(...)
}
Result:
PHPUnit 3.3.17 by Sebastian Bergmann.
F
Time: 1 second
There was 1 failure:
1) testRoute(UserControllerTest)
Failed asserting last controller used was "user"
When I dispatch normal URI like /login it work well but the problem is dispatching URLs with hostnames.
Any ideas?
Thank you all.
Did you try setting the $_SERVER variable in setup?
e.g.
$_SERVER['SERVER_NAME'] = 'www.username.domain.com';
and then call dispatch as per usual.
See - http://php.net/manual/en/reserved.variables.server.php
Define $_SERVER['HTTP_HOST'] before calling dispatch() .
There is already a ticket with the same concern under http://framework.zend.com/issues/browse/ZF-11680