guzzle http post not working with form_params - post

When I try to send a Guzzle-POST, I always get a error returned:
{"errors":[{"code":"0","status":"400","title":"Bad Request","detail":"The JSON payload is malformed."}]}
As I don't see any error,inside the data-array itself, maybe it can be a wrong header information? It is an simple POST request to shopware 6 API where I try toadd a new article.
$payload= [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'form_params' =>[
"name" => "productname",
"productNumber" => "101003",
"stock" => 2,
"taxId" => "50ee15989533451095c9d7e03d9ce479",
"price" => [
[
"currencyId" => "b7d2554b0ce847cd82f3ac9bd1c0dfca",
"gross" => 15,
"net" => 10,
"linked" => false
]
]
]
];
$response = $client->request('POST', 'http://shopware6.shop.de/api/product',
$data
);
If I use Postman or RESTer or similar tools, I get a positive result, It works. So I guess I am missing sth. inside my guzzle-request (which is a copy of the origin documentation from https://shopware.stoplight.io/docs/admin-api/ZG9jOjEyMzA4NTUy-product-data )
I am using guzzle with kamermans oauth2 middleware
A simple GET-request is working too:
$response = $client->request('GET', 'http://shopware6.shop.de/api/product/{productid}',
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
]
]
);

You are missing the entire authentication in your request, which you might've omitted on purpose but I thought I should add it in the following example for the sake of completion.
Aside from that the cause for the bad request is using the key 'form_params', which is only used for Content-Type: multipart/form-data, instead of 'json' for the payload.
$response = $client->request('POST', 'http://localhost/api/oauth/token', [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'grant_type' => 'client_credentials',
'client_id' => '...',
'client_secret' => '...',
],
]);
$token = json_decode($response->getBody()->getContents(), true)['access_token'];
$payload = [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $token,
],
'json' => [
'name' => 'productname',
'productNumber' => '101003',
'stock' => 2,
'taxId' => '...',
'price' => [
[
'currencyId' => '...',
'gross' => 15,
'net' => 10,
'linked' => false,
],
],
],
];
$response = $client->request('POST', 'http://localhost/api/product', $payload);

Related

How to post nested JSON to HTTParty in Ruby on Rails

I am trying to work out the correct way to post a nested JSON object to an API using HTTParty.
I am getting a successful response using Postman to test the call:
POST: http://service.net/api
Headers: x-api-key : apikey123
Body :
{
"VehicleRequests": [{
"Id": "Vehicle1",
"Parameters": {
"Term": 60,
"CashDeposit": 10,
"DepositType": "Percentage",
"AnnualMileage": 10000
},
"PhysicalVehicle": {
"ExternalVehicleId": "12345",
"Type": "Car",
"Status": "PreOwned",
"OnTheRoadPrice": "30000",
"Mileage": "12345",
"Registration": {
"RegistrationNumber": "REGN0",
"DateRegisteredWithDvla": "01/01/2018"
}
}
}]
}
This returns:
{
"Vehicles": [
{
"Id": "Vehicle1",
"HasError": false,
"Error": null,
"FinanceQuotations": [
{
"HasError": false,
"Error": null,
"Finance": {
"Key": "HP",
"Notifications": [],
"Quote": {
.....
}
}
}
}
]
}
But i'm struggling to replicate the call from my rails app. I have a class set up which i'm calling on create
class Monthlyprice
def initialize()
#response = HTTParty.post('http://service.net/api',
:body =>{
:VehicleRequests=> [{
:Id => "Vehicle1",
:Parameters => {
:Term => 60,
:CashDeposit => 10,
:DepositType => "Percentage",
:AnnualMileage => 10000
},
:PhysicalVehicle => {
:ExternalVehicleId => "12345",
:Type => "Car",
:Status => "PreOwned",
:OnTheRoadPrice => "30000",
:Mileage => "12345",
:Registration => {
:RegistrationNumber => "REGN0",
:DateRegisteredWithDvla => "01/01/2018"
}
}
}].to_json
},
:headers => {"x-api-key" => "apikey123"})
puts(#response)
end
end
But this is returning the following error message from the API:
{"Error"=>{"UserMessage"=>"Request is invalid.", "TechnicalMessage"=>"Request Validation failed. Request had 2 error(s). 1: request.VehicleRequests[0].Id - The Id field is required.\r\n2: request.VehicleRequests[0].Parameters - The Parameters field is required.", "Code"=>"80000"}}
This is the same error that I get from the api in postman if I remove the Id and Parameters objects which suggests the contents of my VehicleRequests object is formatted incorrectly? Any advice would be great!
Can you please change the syntax like below :-
:body => {
}.to_json
that means you have to use .to_json where the body parenthesis close I think it's only syntax error.
Syntax :-
response = HTTParty.post("your request URL",
headers: {
.....
#your header content
.....
},
body: {
......
#your body content
.....
}.to_json
)
I have just edited in your code please try below code :-
#response = HTTParty.post('http://service.net/api',
:headers => {"x-api-key" => "apikey123"},
:body =>{
:VehicleRequests=> [{
:Id => "Vehicle1",
:Parameters => {
:Term => 60,
:CashDeposit => 10,
:DepositType => "Percentage",
:AnnualMileage => 10000
},
:PhysicalVehicle => {
:ExternalVehicleId => "12345",
:Type => "Car",
:Status => "PreOwned",
:OnTheRoadPrice => "30000",
:Mileage => "12345",
:Registration => {
:RegistrationNumber => "REGN0",
:DateRegisteredWithDvla => "01/01/2018"
}
}
}]
}.to_json
)
Hope this will help you :)

Yii 2 - authclient doesn't call onAuthSuccess

I am using Yii authclient to use social login. I had set everything as it is defined in docs but when I try to login with google it does not call onAuthSuccess method. When I try to login it just redirects me to returnUrl but not authenticated.
Here is my code;
config/main.php
'authClientCollection' => [
'class' => \yii\authclient\Collection::class,
'clients' => [
'google' => [
'class' => \yii\authclient\clients\Google::class,
'clientId' => *********, //changed for issue purpose
'clientSecret' => *********, //changed for issue purpose
'returnUrl' => 'http://localhost/site/landing',
],
],
]
controllers/SiteController
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'signup', 'auth'],
'rules' => [
[
'actions' => ['signup', 'auth'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
'create-storyboard' => ['post'],
],
],
];
}
/**
* {#inheritdoc}
*/
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
'auth' => [
'class' => 'yii\authclient\AuthAction',
'successCallback' => [$this, 'onAuthSuccess'],
],
];
}
public function onAuthSuccess($client)
{
(new AuthHandler($client))->handle();
}
If you set returnUrl the user is from auth provider redirected directly to the url you've set in that property.
In your case the returnUrl says google, that it should redirect user to http://localhost/site/landing. But there is nothing in your site/landing action that would call the onAuthSuccess.
You need to let user come back to site/auth and redirect them after processing response from OAuth provider. To do that remove the returnUrl from config. That will make the authclient to use default return url which is the action that started the auth process.
Then modify your onAuthSuccess to redirect users to site/landing like this:
public function onAuthSuccess($client)
{
(new AuthHandler($client))->handle();
$this->redirect(['site/landing']);
}
I had solved the problem with the help from #Michal HynĨica. The problem was in my returnUrl which means with authentication url it must follow to authenticate rather the redirecting after authentication. So all I need to do was changing it to as below.
'returnUrl' => 'http://localhost/site/auth?authclient=google'
Also don't forget to add same returnUrl to your google console's redirect url.

AuthAction in yii2

I'm trying to implement yii\authclient\AuthAction's successCallback.
My code looks like this:
public function actions()
{
return [
'auth' => [
'class' => 'yii\authclient\AuthAction',
'successCallback' => [$this, 'successCallback'],
],
];
}
/**
* #param \yii\authclient\ClientInterface $client
*/
public function successCallback($client)
{
$attributes = $client->getUserAttributes();
$externalUser = new AuthForm();
$externalUser->authProvider = $client->getName();
$externalUser->externalUserId = array_key_exists('id', $attributes) ? $attributes['id'] : null;
if ($externalUser->validate())
{
if ($externalUser->isRegistered())
{
$externalUser->login();
return $this->redirect(['private/index']);
}
else
{
Yii::$app->session->set( 'signup/authProvider', $externalUser->authProvider );
Yii::$app->session->set( 'signup/attributes' , $attributes );
return $this->redirect(['site/signup']);
}
}
}
How can I call successCallback? I want to call the auth method. But I am not able to do this?
Most likely this is working fine, but you did not permit for the action of auth to be accessed. Make sure you allow auth in your behaviours of your controller. Something like:
public function behaviors() {
$behaviors = parent::behaviors();
$behaviors [ 'access' ] = [
'rules' => [
[
'actions' => [ 'auth' ],
'allow' => true,
],
],
];
return $behaviors;
}
It will run successCallback when Auth server response successful.
You must config authcollection (collection config of auth server)
'components' => [
'authClientCollection' => [
'class' => 'yii\authclient\Collection',
'clients' => [
'google' => [
'class' => 'yii\authclient\clients\GoogleOpenId'
],
'facebook' => [
'class' => 'yii\authclient\clients\Facebook',
'clientId' => 'facebook_client_id',
'clientSecret' => 'facebook_client_secret',
],
// etc.
],
]
...
]
Default: Yii2 authclient support some openid, oauth, oauth2 provider:
[[\yii\authclient\clients\Facebook|Facebook]].
[[yii\authclient\clients\GitHub|GitHub]].
Google (via [[yii\authclient\clients\GoogleOpenId|OpenID]] and [[yii\authclient\clients\GoogleOAuth|OAuth]]).
[[yii\authclient\clients\LinkedIn|LinkedIn]].
[[yii\authclient\clients\Live|Microsoft Live]].
[[yii\authclient\clients\Twitter|Twitter]].
[[yii\authclient\clients\VKontakte|VKontakte]].
Yandex (via [[yii\authclient\clients\YandexOpenId|OpenID]] and [[yii\authclient\clients\YandexOAuth|OAuth]]).
There's ready to use [[yii\authclient\widgets\AuthChoice]] widget to use in views:
<?= yii\authclient\widgets\AuthChoice::widget([
'baseAuthUrl' => ['site/auth'],
'popupMode' => false,
]) ?>
For more infomation: https://github.com/yiisoft/yii2-authclient/tree/master/docs/guide
Goodluck and have fun!

From Backend to Frontend Yii2 Advanced App

I'm trying to link some controllers from frontend to backend. After some hours I don't where could be the problem.
Backend
file: main.php
'urlManager' => [
'enablePrettyUrl' => false,
'showScriptName' => false,
'baseUrl' => '/backend/web',
],
'urlManagerFrontEnd' => [
'class' => 'yii\web\urlManager',
'baseUrl' => '/frontend/web',
'enablePrettyUrl' => false,
'showScriptName' => false,
]
file: SiteController.php
public function actionIndex()
{
// User's variable
$user = \common\models\User::findIdentity(Yii::$app->user->id);
if($user->role != self::USER_ADMIN){
return $this->redirect(Url::to(Yii::$app->urlManagerFrontEnd->createUrl(['/site/index'])));
}
return $this->render('index');
}
Using this
Url::to(Yii::$app->urlManagerFrontEnd->createUrl(['/site/index']))
Returns me
/advanced/backend/web/index.php?r=site%2Findex
Any advice?
Your code is correct. urlManagerFrontEnd should return url based on baseUrl /frontend/web.
Try change baseUrl to http://yourdomain/
I did little googling and found this link.
for reference I am posting same here
I read around in the UrlManager.php and found the following:
$baseUrl = $this->showScriptName || !$this->enablePrettyUrl ? $this->getScriptUrl() : $this->getBaseUrl();
So this means when showScriptName= true and enablePrettyUrl=false $baseUrl = getScriptUrl() otherwise $baseUrl = getBaseUrl()
So it just work with prettyUrl=true and the showScriptName = false. When we set prettyUrl on true it takes $baseUrl = getBaseUrl()
Changing it to the following it resolves our problem =).
/*$baseUrl = $this->showScriptName || !$this->enablePrettyUrl ? $this->getScriptUrl() : $this->getBaseUrl();*/
$baseUrl = !$this->showScriptName || $this->enablePrettyUrl ? $this->getScriptUrl() : $this->getBaseUrl();
Now you have to set prettyurl=false and the other on true et voila
I tried this on a fresh template and then applied code you mentioned in question and got the same error as you got.
But then after the fix I did according to this post I get correct path.
This link is also helpful.
in your frontend config add this to the top to define 2 variables.
use \yii\web\Request;
$baseUrl = str_replace('/frontend/web', '/frontend/web', (new Request)->getBaseUrl());
$backEndBaseUrl = str_replace('/frontend/web', '/backend/web', (new Request)->getBaseUrl());
And set these variables as the baseUrl parameters in the components
'components' => [
'urlManager' => [
'class' => 'yii\web\urlManager',
'enablePrettyUrl' => false,
'showScriptName' => false,
//'baseUrl' => '/frontend/web',
'baseUrl'=> $baseUrl,
],
'urlManagerBackEnd' => [
'class' => 'yii\web\urlManager',
'enablePrettyUrl' => false,
'showScriptName' => false,
//'baseUrl' => '/backend/web',
'baseUrl' => $backEndBaseUrl,
],
then you can have links from the frontend to the backend by e.g.
$backendUrl= Yii::$app->urlManagerBackEnd->createUrl('//');
echo yii\helpers\Html::a('link to backend', $backendUrl);
to have the same from the backend to the frontend add this to the backend config:
use \yii\web\Request;
$baseUrl = str_replace('/backend/web', '/backend/web', (new Request)->getBaseUrl());
$frontEndBaseUrl = str_replace('/backend/web', '/frontend/web', (new Request)->getBaseUrl());
and in the components:
'urlManager' => [
'class' => 'yii\web\urlManager',
'enablePrettyUrl' => false,
'showScriptName' => false,
'baseUrl'=> $baseUrl,
],
'urlManagerFrontEnd' => [
'class' => 'yii\web\urlManager',
'enablePrettyUrl' => false,
'showScriptName' => false,
//'baseUrl' => '/backend/web',
'baseUrl' => $frontEndBaseUrl,
],
and to create links use:
$frontendUrl= Yii::$app->urlManagerFrontEnd->createUrl('//');
echo yii\helpers\Html::a('link to frontend', $frontendUrl);
forgot you can of course also link to specific pages e.g. from backend to frontend site/about:
$frontendUrl= Yii::$app->urlManagerFrontEnd->createUrl('/site/about');
echo yii\helpers\Html::a('link to frontend site about', $frontendUrl);
BTW. if you have removed the /web behavior by some htaccess you should also remove it in the variables.
use this code. it will redirect you to front end
return $this->redirect(Yii::$app->urlManager->createUrl('./../../frontend/web/'));
Use below one:
Url::to(Yii::$app->urlManagerBackEnd->createUrl('index.php/'/site/index'), true);

How to format a Google Calender API request using HTTParty

I am getting the following error when I make a request to the Google Calendar API.
{"error"=>{"errors"=>[{"domain"=>"global", "reason"=>"required", "message"=>"Missing end time."}], "code"=>400, "message"=>"Missing end time."}}
What is wrong with my formatting? I've tried a ton of different layouts and can't seem to find much information about using HTTParty to make a request to a Google API.
results = HTTParty.post("https://www.googleapis.com/calendar/v3/calendars/primary/events?key=#{Rails.application.secrets.google_api_key}",
:headers => {
"Authorization" => "Bearer #{response["access_token"]}"
},
:query => {
"end": {
"dateTime" => "2015-05-29T09:00:00-08:00",
"timeZone" => "America/Los_Angeles"
},
"start": {
"dateTime" => "2015-05-29T09:00:00-07:00",
"timeZone" => "America/Los_Angeles"
},
"summary": "TEST POST"
}
)
Thanks in advance!
Figured it out. I needed to use a :body key and also specify JSON in the header
results = HTTParty.post("https://www.googleapis.com/calendar/v3/calendars/primary/events?key=#{Rails.application.secrets.google_api_key}",
:headers => {
"Authorization" => "Bearer #{response["access_token"]}",
"Content-Type" => "application/json"
},
:body => {
"end": {
"dateTime" => "2015-05-29T09:00:00-08:00",
"timeZone" => "America/Los_Angeles"
},
"start": {
"dateTime" => "2015-05-29T09:00:00-07:00",
"timeZone" => "America/Los_Angeles"
},
"summary": "TEST POST"
}
)

Resources