Api Platform Client add double quote to url - symfony

I'm using api platform 2.6.8
Description
I have created this test:
<?php
namespace App\Tests\Api;
use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
use Symfony\Component\HttpFoundation\Request;
class PwaTest extends ApiTestCase
{
public function testPwaReachability(): void
{
$client = ApiTestCase::createClient();
$client->setDefaultOptions([
'base_uri' => 'http://caddy'
]);
$client->request(Request::METHOD_GET, '/admin', [
'headers' => [
'Accept' => 'text/html',
],
]);
self::assertResponseIsSuccessful();
}
}
When I run the test php vendor/bin/phpunit --filter testPwaReachability I got a 404 with message
No route found for "GET http://caddy:8083/admin&quot
For some reason the api platform client ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Client added a double quote at the end of my url &quot
How to reproduce
Download 2.6.8 release
Launch docker docker compose up
Intall test dependencies: docker compose exec php composer require --dev symfony/test-pack symfony/http-client justinrainbow/json-schema
Create the test as in description
Run the test as in description
Why Api platform add a double quote to my url ?
Edit
I modify my test as below and I get a 200:
<?php
namespace App\Tests\Api;
use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
class PwaTest extends ApiTestCase
{
public function testPwaReachability(): void
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://caddy/admin');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Accept: text/html',
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$r = curl_exec($ch);
curl_close($ch);
}
}

Related

Symfony 5 / Mercure > Private update. Fetch CORS

I try to integrate Mercure to symfony 5 project. And there are two trouble.
I try to send update to private, but it's not work, but if try to send to not private everything works.
Command that run mercure:
./bin/mercure --jwt-key='homesphere_secret_token' --addr='localhost:3000' --allow-anonymous --cors-allowed-origins='*'
.env file
MERCURE_PUBLISH_URL=http://localhost:3000/.well-known/mercure
MERCURE_JWT_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdfX0.P0f5r123SLTru4DiE4X9q0EIoKahds-nI8jpo8uKKQQ
MERCURE_SECRET_KEY=homesphere_secret_token
Backend that gives url and jwt token
$user = $this->getUser();
$hubUrl = $this->getParameter('mercure.default_hub');
$link = new Link('mercure', $hubUrl);
$token = JWT::encode([
'mercure' => [
'publish' => [sprintf("/chat/%s", $user->getId())],
],
], $this->getParameter('mercure_secret_key'));
Update code
$message = $serializer
->serialize(['message' => $message], 'json');
$update = new Update(
sprintf("/chat/%s", $user->getId()),
$message,
true // if false then work
);
$publisher($update);
Frontend part
const hub = new URL('http://localhost:3000/.well-known/mercure');
hub.searchParams.append('topic', '/chat/1');
const eventSource = new EventSourcePolyfill(hub.href, {
'Authorization': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiXC9jaGF0XC8xIl19fQ.yg3DodPjaPzWVIOhKMo30xXzS3L4oPckbL9pcA4tMck'
});
eventSource.onmessage = event => {
console.log(JSON.parse(event.data));
}
When frontend receives message by update then next requests start rising CORS trouble
image
could anyone help me with these, please?
Try with --cors-allowed-origins='http://localhost:8000'

Sending Guzzle request to itemize api

The situation:
I need to send the request to the api to update the account info.
The API docs say I need to do send a PUT request to the API.
I trying to do this in Laravel 5.6, although I don't think this matters.
What I have so far:
A working constructor for the Guzzle client;
A working function to retrieve account info.
What is not working:
Upon submitting the request I get a Guzzle exception
Client error: \`PUT https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/<my account id>\` resulted in a \`400 Bad Request\` response: IOException:
This is the code I have so far:
<?php
namespace App\Http\Controllers;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
class ApiController extends Controller {
private $apiKey;
private $uri;
private $client;
public function __construct() {
$this->apiKey = 'my api key';
$this->uri = 'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/my account id';
$this->client = new Client([
'base_uri' => $this->uri,
'auth' => [null, $this->apiKey]]);
}
public function accountInfo() {
$response = $this->client->request('GET','');
echo $response->getBody()->getContents();
}
public function updateAccountInfo() {
$response = $this->client->request('PUT','',[
'headers' => [
'Content-Type' => 'application/json',
],
'body' => '{"markets":"UK"}'
]);
echo $response->getBody()->getContents();
}
}
?>
400 Bad Request means: request sent by the client due to invalid syntax.
According itemize api documentation "markets" should be passed as an array of strings. And you can also use json format.
Try this:
public function updateAccountInfo() {
$response = $this->client->request('PUT', '', [
'json' => ["markets" => ["UK"]],
]);
echo $response->getBody()->getContents();
}

Firebase Dynamic Link CORS - XMLHttpRequest

I'd like to shorten my URL's using the Firebase Dynamic Link shortener. I followed the Rest API reference and the code seems to check out:
const url ="https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=MY_API_KEY";
this.request = new XMLHttpRequest();
this.request.open("GET", url, true);
this.request.setRequestHeader("Content-Type", "application/json");
this.request.setRequestHeader("Access-Control-Allow-Origin", "*");
const parameters = {
"longDynamicLink": encodeURIComponent(window.location)
};
this.request.onreadystatechange = this.updateLink;
this.request.send(parameters);
But when I execute this code, I get a CORS error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at
https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=MY_API_KEY.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
I can't seem to find a setting where I can enable Cross Origin Requests. Anyone who can tell me how to use Firebase Dynamic Links from the browser?
I solved this problem by just creating a PHP script that I can use to delegate the Firebase Rest call from client-side to server-side. This also ensures my users will never get to see my Firebase API key.
<?php
$LongDynamicLink = "MYHOST?" . urlencode($_GET["url"]);
$url = "https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=MY_API_KEY";
$data = '{
"dynamicLinkInfo": {
"dynamicLinkDomain": "MY_LINK_DOMAIN",
"link": "' . $LongDynamicLink . '",
"androidInfo": {
"androidPackageName": "ANDROID_PACKAGE_NAME"
},
"iosInfo": {
"iosBundleId": "IOS_BUNDLE_NAME"
}
}
}';
echo httpPost($url, $data);
function httpPost($url, $data)
{
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
?>
Using this code, you can call the PHP Rest API as such:
let request = new XMLHttpRequest();
request.open("GET", "MY_DOMAIN/?url=URL_I_WANT_TO_SHORTEN", true);
request.onreadystatechange = console.log(request.response);
request.send();

use get methods in telegram

I want to get the response of getChat method in symfony for telegram but how use it?
https://api.telegram.org/bottoken/getChat?chat_id=#channelName
this is the response in postman:
{
"ok": true,
"result": {
"id": -1001000737610,
"title": "کانال 💯",
"username": "gizmiztel",
"type": "channel",
"description": "ارسال سوژه👈 #alogizmiz\n\nتبلیغات👈 #gizmiz_ad\n\nاینستاگرام👈 instagram.com/_u/gizmiztel\n\nسایت👈 gizmiz.com",
"photo": {
"small_file_id": "AQADBAATOIVnGQAElEEaamARX9hoWgIAAQI",
"big_file_id": "AQADBAATOIVnGQAE21YqJKH-YwZqWgIAAQI"
}
}
}
for send message I use this kind but for get i don't know what to do:
$result = [
'method' => 'sendMessage',
'chat_id' => $chatId,
'text' => 'خطای سرور'
];
return new JsonResponse($result, Response::HTTP_OK);
You can use Guzzle or PHP Curl for get result from any HTTP client.
For using guzzle http client:
Reqire "guzzlehttp/guzzle": "version" in your package.json and run composer update command.
Then you can use it like this:
<?php
namespace Foo\BarBundle\Driver;
use GuzzleHttp\Client;
class GetResultFromTelegram
{
protected client;
public function getInfoOfChannel()
{
$baseUrl = 'https://api.telegram.org/bottoken/getChatchat_id=#channelName';
$this->client = new Client();
$res = $this->client->request('GET', $baseUrl);
// Convert response to array.
return json_decode($res->getBody(), true);
}
}

Batch requests on Symfony

I am trying to reproduce the behaviour of the facebook batch requests function on their graph api.
So I think that the easiest solution is to make several requests on a controller to my application like:
public function batchAction (Request $request)
{
$requests = $request->all();
$responses = [];
foreach ($requests as $req) {
$response = $this->get('some_http_client')
->request($req['method'],$req['relative_url'],$req['options']);
$responses[] = [
'method' => $req['method'],
'url' => $req['url'],
'code' => $response->getCode(),
'headers' => $response->getHeaders(),
'body' => $response->getContent()
]
}
return new JsonResponse($responses)
}
So with this solution, I think that my functional tests would be green.
However, I fill like initializing the service container X times might make the application much slower. Because for each request, every bundle is built, the service container is rebuilt each time etc...
Do you see any other solution for my problem?
In other words, do I need to make complete new HTTP requests to my server to get responses from other controllers in my application?
Thank you in advance for your advices!
Internally Symfony handle a Request with the http_kernel component. So you can simulate a Request for every batch action you want to execute and then pass it to the http_kernel component and then elaborate the result.
Consider this Example controller:
/**
* #Route("/batchAction", name="batchAction")
*/
public function batchAction()
{
// Simulate a batch request of existing route
$requests = [
[
'method' => 'GET',
'relative_url' => '/b',
'options' => 'a=b&cd',
],
[
'method' => 'GET',
'relative_url' => '/c',
'options' => 'a=b&cd',
],
];
$kernel = $this->get('http_kernel');
$responses = [];
foreach($requests as $aRequest){
// Construct a query params. Is only an example i don't know your input
$options=[];
parse_str($aRequest['options'], $options);
// Construct a new request object for each batch request
$req = Request::create(
$aRequest['relative_url'],
$aRequest['method'],
$options
);
// process the request
// TODO handle exception
$response = $kernel->handle($req);
$responses[] = [
'method' => $aRequest['method'],
'url' => $aRequest['relative_url'],
'code' => $response->getStatusCode(),
'headers' => $response->headers,
'body' => $response->getContent()
];
}
return new JsonResponse($responses);
}
With the following controller method:
/**
* #Route("/a", name="route_a_")
*/
public function aAction(Request $request)
{
return new Response('A');
}
/**
* #Route("/b", name="route_b_")
*/
public function bAction(Request $request)
{
return new Response('B');
}
/**
* #Route("/c", name="route_c_")
*/
public function cAction(Request $request)
{
return new Response('C');
}
The output of the request will be:
[
{"method":"GET","url":"\/b","code":200,"headers":{},"body":"B"},
{"method":"GET","url":"\/c","code":200,"headers":{},"body":"C"}
]
PS: I hope that I have correctly understand what you need.
There are ways to optimise test-speed, both with PHPunit configuration (for example, xdebug config, or running the tests with the phpdbg SAPI instead of including the Xdebug module into the usual PHP instance).
Because the code will always be running the AppKernel class, you can also put some optimisations in there for specific environments - including initiali[zs]ing the container less often during a test.
I'm using one such example by Kris Wallsmith. Here is his sample code.
class AppKernel extends Kernel
{
// ... registerBundles() etc
// In dev & test, you can also set the cache/log directories
// with getCacheDir() & getLogDir() to a ramdrive (/tmpfs).
// particularly useful when running in VirtualBox
protected function initializeContainer()
{
static $first = true;
if ('test' !== $this->getEnvironment()) {
parent::initializeContainer();
return;
}
$debug = $this->debug;
if (!$first) {
// disable debug mode on all but the first initialization
$this->debug = false;
}
// will not work with --process-isolation
$first = false;
try {
parent::initializeContainer();
} catch (\Exception $e) {
$this->debug = $debug;
throw $e;
}
$this->debug = $debug;
}

Resources