how to retrieve post response variable outside in reactphp - asynchronous

My code is as follows:
require __DIR__.'/vendor/autoload.php';
use Psr\Http\Message\ResponseInterface;
$loop = React\EventLoop\Factory::create();
$client = new React\Http\Browser($loop);
$data = [
'name' => [
'first' => 'Alice',
'name' => 'Smith',
],
'email' => 'alice#example.com',
'userid' => 'alice',
];
$client->post(
'https://httpbin.org/post',
[
'Content-Type' => 'application/json',
],
json_encode($data)
)->then(function (ResponseInterface $response) {
$response = (string) $response->getBody();
return $response;
});
**echo $response;**
$loop->run();
I am able to get the response inside then function(). but I cannot retrieve the response value outside.
I like to send multiple asynchronous POST requests and collect each responses and echo all of them at once.
How can I access the response variable from outside of post()->then()?

I could get the response when I need a response with deferred and promise method.
First, I assigned the request and response method to $promise.
And I was able to simply get the response with $deferred->resolve();
require __DIR__.'/vendor/autoload.php';
use Psr\Http\Message\ResponseInterface;
$loop = React\EventLoop\Factory::create();
$client = new React\Http\Browser($loop);
$deferred = new React\Promise\Deferred();
$promise = $deferred->promise();
$data = [
'name' => [
'first' => 'Alice',
'name' => 'Smith',
],
'email' => 'alice#example.com',
'userid' => 'alice',
];
$promise = $client->post(
'https://httpbin.org/post',
[
'Content-Type' => 'application/json',
],
json_encode($data)
)->then(function (ResponseInterface $response) {
$response = (string) $response->getBody();
return $response;
});
echo $deferred->resolve();
$loop->run();

Related

How can I pass my UploadedFile data via http guzzle request?

I have two different website : my application and my backoffice (in Laravel)
I create an API route to store a document on my application. I made a request with Guzzle on my backoffice to store a document.
My guzzle http request on backoffice website :
public static function storeDocument($token, $request)
{
$client = new \GuzzleHttp\Client([
'Content-Type' => 'multipart/form-data'
]);
$headers = [
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json',
];
$datas = [
'document' => $request->file('document'),
'doc_name' => $request->doc_name ?? '',
];
$request = $client->post(env('API_URL') . '/api/document/store/', ['headers' => $headers, 'form_params' => $datas]);
$result = json_decode($request->getBody()->getContents());
return $result;
}
And there is my API route method on application website :
public function store(Request $request) {
$validator = Validator::make($request->all(), [
'document' => 'bail|required|mimes:pdf,doc,docs,csv,txt|max:2048',
'doc_name' => 'bail|string|max:80|nullable',
]);
if($validator->fails()){
return response()->json($validator->errors());
};
$document = $request->document;
$fileName = '';
if(isset($request->doc_name)) {
$fileName = $request->doc_name . '.' . $document->extension();
} else {
$fileName = $document->getClientOriginalName();
}
$result = Storage::putFileAs(
'documentations',
$document,
$fileName,
'public'
);
if($result) {
return response()->json(['success' => 'Le fichier a bien été enregistré'], 201);
} else {
return response()->json(['error' => $errors], 400);
};
}
It seems that my datas aren't sent correctly because storeDocument() gives me an error : 'This field is required'. So it looks like it can't find $request->document which is required...
And with Insomnia I have no error, my file is correctly save.
I want to specify that I pass correct datas to storeDocument.
That is the result of $request->file('document') :
Illuminate\Http\UploadedFile {#1354 ▼
-test: false
-originalName: "test.pdf"
-mimeType: "application/pdf"
-error: 0
#hashName: null
path: "/tmp"
filename: "phpPOxtfN"
basename: "phpPOxtfN"
pathname: "/tmp/phpPOxtfN"
extension: ""
realPath: "/tmp/phpPOxtfN"
aTime: 2022-08-25 14:30:14
mTime: 2022-08-25 14:30:13
cTime: 2022-08-25 14:30:13
inode: 4856076
size: 48632
perms: 0100600
owner: 33
group: 33
type: "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
}
I'm stuck since several hours on this, does anyone has any idea to help me?
Thanks ;)
EDIT: I finally found that I have to pass 'multipart' instead of 'form_params' on my http request.
Moreover I found that I have to use fopen or file_get_contents to send raw datas...
So my storeDocument function looks like this now :
public static function storeDocument($token, $request)
{
$client = new \GuzzleHttp\Client([
'Content-Type' => 'multipart/form-data'
]);
$headers = [
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json',
];
$datas = [
[
'name' => 'document',
'contents' => file_get_contents($request->file('document')),
],
[
'name' => 'doc_name',
'contents' => $request->doc_name ?? '',
]
];
$request = $client->post(env('API_URL') . '/api/document/store/', ['headers' => $headers, 'multipart' => $datas]);
$result = json_decode($request->getBody()->getContents());
return $result;
}
But it still doesn't work...
Continue searching...

Problem using wp_remote_post to parse JSON response from external API

I am using wp_remote_post() to post products to a third party site. First I get these products via API from a site called Mercado Libre. But when I carry out the mass publication, the products are published without a name, without a price, and without respecting the parameters provided. They only have the name "Product".
function publish_products_in_woocommerce()
{
$respuesta = wp_remote_get('https://api.mercadolibre.com/sites/MLA/search?q=Motorola%20G6', array(
'headers' => array(
'Authorization' => 'Bearer APP_USR-2778915669536100-052221-0f3a39361bdcea9bc3de0df8ab619f66-370993848'
)
));
$respuesta = json_decode($respuesta['body'], true);
print_r($respuesta);
foreach ($respuesta['results'] as $value) {
$product_data = array(
'name' => $value['title'],
'status' => 'draft',
'type' => 'simple',
'regular_price' => $value['price'],
'description' => $value['title'],
'short_description' => $value['title'],
'categories' => [
[
'id' => $value['category_id'],
]
],
'images' => [
[
'src' => $value['thumbnail']
]
]
);
$woocommerce_api_ck = 'ck_b2a0f58d07590e8283302eca04fbc1b66a9ff653';
$woocommerce_api_cs = 'cs_b4d91662590be47416f663fc9f0d1c49f600e394';
$url = 'http://nuevo.labisbal.com.ar/wp-json/wc/v3/products';
wp_remote_post('http://nuevo.labisbal.com.ar/wp-json/wc/v3/products', array(
'headers' => array(
'Authorization ' => 'Basic ' . base64_encode($woocommerce_api_ck . ':' . $woocommerce_api_cs),
),
'body' => $ProductToWooCommerce = json_encode($product_data),
'method' => 'POST',
'timeout' => 145,
'blocking' => false,
'sslverify' => false,
'stream' => true,
'data_format' => 'json'
));
print_r($ProductToWooCommerce);
if (wp_remote_retrieve_response_message($respuesta) === 'Created') {
echo 'The product has been created';
}
}
}
publish_products_in_woocommerce();
?>
It's strange because when I display the json already converted (using json_encode) the data is displayed correctly... (using print_r)
I take a look at this and the issue is on how you sent the data to the API, when you use wp_remote_post you need to send the body as an array, and the method handles that information for you, so you don't need to convert it to JSON.
Below is a small test plugin that saves products using the WC REST API, the plugin adds a new endpoint to your site to trigger the scrapper https://yoursite.com/wp-json/wpapi/v1/fetch, I hope that helps.
Note: Please double check the code, is not fully tested.
<?php
/**
* Plugin Name: A WC API test
* Plugin URI: https://enriquechavez.co
* Description: Just a test.
* Version: 1.0.0
* Requires at least: 5.2
* Requires PHP: 7.4
* Author: Enrique Chavez
* Author URI: https://enriquechavez.co/
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Update URI: https://example.com/my-plugin/
* Text Domain: my-basics-plugin
* Domain Path: /languages
*/
add_action('rest_api_init', function () {
register_rest_route('wpapi/v1', 'fetch', [
'methods' => WP_REST_Server::READABLE,
'callback' => 'fetch_ml_products',
'permissions_callback' => '__return_true',
]);
});
function fetch_ml_products(WP_REST_Request $request)
{
$ml_api = 'https://api.mercadolibre.com/sites/MLM/search?q=Motorola%20G6&limit=5';
$wc_ck = 'ck_1f2e32852403a1701c1adxxxxxxxxxxxxxxxxxxx';
$wc_cs = 'cs_6fd5feedd2a25b73eebc9xxxxxxxxxxxxxxxxxxx';
$request = wp_safe_remote_get($ml_api);
if (is_wp_error($request)) {
return $request;
}
$response = json_decode(wp_remote_retrieve_body($request));
$new_products = [];
foreach ($response->results as $product) {
$wc_api_url = 'https://wp.test/wp-json/wc/v3/products/';
$request_data = [
'headers' => [
'Authorization' => 'Basic ' . base64_encode($wc_ck . ':' . $wc_cs),
],
'body' => [
'name' => $product->title,
'status' => 'draft',
'regular_price' => $product->price,
],
'sslverify' => false,
];
$request = wp_remote_post($wc_api_url, $request_data);
if (is_wp_error($request)) {
// TODO: validate the error.
print_r($request);
die('Something is wrong');
}
$new_products[] = json_decode(wp_remote_retrieve_body($request));
}
return $new_products;
}

How can I Unit Test GraphQL file Upload with API Platform?

In addition to my other tests against my GraphQL API Platform backend, I am attempting to test file uploads. I'm not quite sure whether the ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Client class has the ability to facilitate this test, or if Symfony\Component\HttpFoundation\File\UploadedFile should be used to provide the test file as it is for a REST operation.
Here is roughly where I am at in terms of putting together this test. (With some irrelevant parts removed for simplification)
public function testCreateMediaObject(): void {
$file = new UploadedFile('fixtures/files/logo.png', 'logo.png');
$client = self::createClient();
$gql = <<<GQL
mutation UploadMediaObject(\$file: Upload!) {
uploadMediaObject(input: {file: \$file}) {
mediaObject {
id
contentUrl
}
}
}
GQL;
$response = $client->request('POST', '/api/graphql', [
'headers' => ['Content-Type' => 'application/json'],
'json' => [
'query' => $gql,
'variables' => ["file" => null],
'map' => ['0' => ['variables.file']],
'0' => $file,
]
]);
dd($response);
}
The response I get seems to indicate that the file isn't being included as expected. Something like...
Variable "$file" of non-null type "Upload!" must not be null.
Or.. if I try to attach the file by simply assigning it directly in the variables property...
$response = $client->request('POST', '/api/graphql', [
'headers' => ['Content-Type' => 'application/json'],
'json' => [
'query' => $gql,
'variables' => ["file" => $file],
]
]);
then...
Variable "$file" got invalid value []; Expected type Upload; Could not get uploaded file, be sure to conform to GraphQL multipart request specification. Instead got: []
In my most recent attempt, I changed things up quite a bit after sifting through the graphql code...
$formFields = [
'operations' => '{ "query": "mutation ($file: Upload!) { uploadMediaObject(input: {file: $file}) { mediaObject { id contentUrl } } }", "variables": { "file": null } }',
'map' => "{'0': ['variables.file']}",
'0' => DataPart::fromPath(__DIR__.'/../../fixtures/files/logo.png'),
];
$formData = new FormDataPart($formFields);
$response = $client->request('POST', '/api/graphql', [
'headers' => $formData->getPreparedHeaders()->toArray(),
'body' => $formData->bodyToString(),
]);
The problem with this last attempt is that the server isn't seeing any body parameters. So I receiving the exception
'GraphQL multipart request does not respect the specification.'
Which is found in /api-platform/core/src/GraphQl/Action/EntrypointAction.php within the parseMultipartRequest method.
After a few hours of debugging I found this solution:
$formData = new FormDataPart();
$file = new UploadedFile('src/DataFixtures/files/test.txt', 'test.txt');
$response = $this->$client->request('POST', 'api/graphql', [
'headers' => $formData->getPreparedHeaders()->toArray(),
'extra' => [
'parameters' => [
'operations' => '{ "query": "mutation UploadMediaObject($file: Upload!) { uploadMediaObject(input: {file: $file}) { mediaObject { id contentUrl } } }", "variables": { "file": null } }',
'map' => '{ "0": ["variables.file"] }',
'0' => #$file,
],
'files' => [
$file,
],
],
]);
Refrence:
https://github.com/jaydenseric/graphql-multipart-request-spec
https://api-platform.com/docs/core/graphql/

HttpClient Component Authentication

I need to to be authentificate when create a HTTP request, in the documentation
$httpClient = HttpClient::create([
'auth_basic' => ['user#gmail.com', '45#8888'],
]);
$httpClient = HttpClient::create([
// HTTP Basic authentication with only the username and not a password
'auth_basic' => ['the-username'],
// HTTP Basic authentication with a username and a password
'auth_basic' => ['the-username', 'the-password'],
// HTTP Bearer authentication (also called token authentication)
'auth_bearer' => 'the-bearer-token',
]);
So when write
$response = $httpClient->request('GET', 'https://...', [
// use a different HTTP Basic authentication only for this request
'auth_basic' => ['the-username', 'the-password'],
// ...
]);
An exception is throwed
Symfony\Component\HttpClient\Exception\ClientException: HTTP/1.1 400
Bad Request returned for "http://site.test/login_check".
Is the exeption throwed because i haven't post the field user[_token] ?
If yes how to generate it and add to the request ?
If anyone has already logged in with this component please give me the code :)
I used that and it works
Try, for Authentication and Request:
$httpClient = HttpClient::create();
$uri = 'http://test:xxxx/login_check';
$response = $httpClient->request('POST', $uri, [
'headers' => [
'Content-Type' => 'application/json',
],
'json' => [
'username' => 'jhon.doe#gmail.com',
'password' => 'jhon.doe'
],
]);
$statusCode = $response->getStatusCode();
if($statusCode == 200) {
$content = $response->getContent();
dd($content);
}
// JWT Request Http
$uri = 'http://test.xxx/api/xxxx';
$response = $httpClient->request('GET', $uri, [
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer '.TOKEN
]
]);
$statusCode = $response->getStatusCode();
$content = $response->getContent();
dd($content);
//the easiest
$httpClient->request('POST', $url, [
'auth_bearer' => $jwt,
'body' => $data,
])->getContent();

How to store and log for all http request and response in wordpress?

I want to store all outgoing http request from my wordpress site. I want to store all internal and external http request and response also request made with curl. Any help should be useful to me.
Hook into WP_Http::_dispatch_request()
function fn_log_http_request_response( $wp_http_response, $request, $url ) {
$request = [
'method' => $request['method'],
'url' => $url,
'headers' => $request['headers'],
'body' => $request['body'],
];
if($wp_http_response instanceof WP_Error) {
$response = [
'errors' => $wp_http_response->errors,
'error_data' => $wp_http_response->error_data,
];
} else {
$response = [
'status' => [
'code' => wp_remote_retrieve_response_code($wp_http_response),
'message' => wp_remote_retrieve_response_message($wp_http_response),
],
'headers' => wp_remote_retrieve_headers($wp_http_response)->getAll(),
'body' => wp_remote_retrieve_body($wp_http_response),
];
}
error_log(print_r([
'request' => $request,
'response' => $response,
], true));
return $wp_http_response;
}
// hook into WP_Http::_dispatch_request()
add_filter('http_response', 'fn_log_http_request_response', 10, 3 );
Adopted from hinnerk-a
You can also try the following plugin as well
https://wordpress.org/plugins/log-http-requests

Resources