laravel 无法通过Amadeus API使用Guzzle来POST请求

pu3pd22g  于 2022-11-26  发布在  其他
关注(0)|答案(3)|浏览(207)

说明

我正在尝试将Amadeus自助服务API集成到Laravel环境中。我可以通过GET请求成功获取内容,但无法通过POST请求获取内容。我已经设置了异常,以显示由特定的guzzle引发的错误。
下面是api引用,其中包含我想发布到的数据和端点。https://developers.amadeus.com/self-service/category/air/api-doc/flight-offers-search/api-reference

如何复制

这是我从Client.php调用的方法,并通过调用POST方法传递数据。

public function __construct() {
    throw_if(static::$instance, 'There should be only one instance of this class');
    static::$instance = $this;
    $this->client = new Client([
        'base_uri' => 'https://test.api.amadeus.com/',
    ]);
}

public function get($uri, array $options = []) {
    $this->authenticate();
    return $this->client->request('GET', $uri, [
        $options, 
        'headers' => [
            'Authorization' => 'Bearer '.$this->access_token,
        ],
    ]);
}

public function post($uri, array $options = []) {
    $this->authenticate();
    return $this->client->request('POST', $uri, [
        $options, 
        'headers' => [
            'Authorization' => 'Bearer '.$this->access_token,
        ],
    ]);
}

调用POST方法后,我将“X-HTTP-Method-Override”作为“GET”传递,并将数据作为body传递。

$requests_response = $client->post('v2/shopping/flight-offers', [
    'headers' => [
        'X-HTTP-Method-Override' => 'GET',
    ],
    'body' => [
        [
            "currencyCode" => "USD",
            "originDestinations" => [
                [
                    "id" => "1",
                    "originLocationCode" => "RIO",
                    "destinationLocationCode" => "MAD",
                    "departureDateTimeRange" => [
                        "date" => "2022-11-01",
                        "time" => "10:00:00",
                    ],
                ],
                [
                    "id" => "2",
                    "originLocationCode" => "MAD",
                    "destinationLocationCode" => "RIO",
                    "departureDateTimeRange" => [
                        "date" => "2022-11-05",
                        "time" => "17:00:00",
                    ],
                ],
            ],
            "travelers" => [
                ["id" => "1", "travelerType" => "ADULT"],
                ["id" => "2", "travelerType" => "CHILD"],
            ],
            "sources" => ["GDS"],
            "searchCriteria" => [
                "maxFlightOffers" => 2,
                "flightFilters" => [
                    "cabinRestrictions" => [
                        [
                            "cabin" => "BUSINESS",
                            "coverage" => "MOST_SEGMENTS",
                            "originDestinationIds" => ["1"],
                        ],
                    ],
                    "carrierRestrictions" => [
                        "excludedCarrierCodes" => ["AA", "TP", "AZ"],
                    ],
                ],
            ],
        ],
    ],
]);

其他上下文

下面是我在日志中发现的错误。

local.ERROR: Guzzle error {"response":{"GuzzleHttp\\Psr7\\Stream":"
    {
        \"errors\": [
            {
                \"code\": 38189,
                \"title\": \"Internal error\",
                \"detail\": \"An internal error occurred, please contact your administrator\",
                \"status\": 500
            }
        ]
    }
"}}

local.ERROR: Server error: POST https://test.api.amadeus.com/v2/shopping/flight-offers resulted in a 500 Internal Server Error response:
{
"errors": [
"code": 38189,
(truncated...)
"exception":"[object] (GuzzleHttp\\Exception\\ServerException(code: 500): Server error: POST https://test.api.amadeus.com/v2/shopping/flight-offers resulted in a 500 Internal Server Error response:

"errors": [
"code": 38189,
(truncated...)
at C:\\xampp\\htdocs\\Application\\vendor\\guzzlehttp\\guzzle\\src\\Exception\\RequestException.php:113)

请抽出时间来看一看,帮助实在是感激不尽。

piwo6bdm

piwo6bdm1#

POST调用实际上是否使用HTTP客户端(如Postman或Insomnia)工作?
我注意到你传递了一个$options数组,并将其嵌套在Guzzle选项中。

$this->client->request('POST', $uri, [
   ['headers' => '...', 'body' => ['...']],
   'headers' => ['...']
]);

这行不通,您需要按照以下方式打开 Package :

public function post($uri, array $options = []) {
   $this->authenticate();
   return $this->client->request('POST', $uri, [
       ...$options, 
       'headers' => [
           'Authorization' => 'Bearer '.$this->access_token,
       ],
   ]);
}

请注意...这个点,它是用来解压缩options数组的,还要注意,headers键设置了两次(一次在post方法定义中,一次在options参数中),所以实际上只使用了一次(顺便问一下,为什么要使用X-HTTP-Method-Override头文件?)
如果您想在POST函数参数中传递所有头和体,另一个解决方案是:

public function post($uri, array $options = []) {
   $this->authenticate();
   return $this->client->request('POST', $uri, [
       'json' => $options['json'], // I would suggest 'json' because it looks like the API is looking for a JSON body, if that doesn't work go with 'body' 
       'headers' => [
           'Authorization' => 'Bearer '.$this->access_token,
           ...$options['headers']
       ],
   ]);
}

如果这样做不起作用,您可以尝试另一种方法,即使用Guzzle json选项而不是body来处理POST请求。

j0pj023g

j0pj023g3#

也许有点晚了,但这个例子对我很有效:

$options = [
        'headers' => [
            'Authorization' => sprintf('Bearer %s', $this->getApiToken()),
            'content-type'        => 'application/vnd.amadeus+json',
            'X-HTTP-Method-Override' => 'GET',
        ],
        'body' => '{
                "currencyCode": "XPF",
                "originDestinations": [
                    {
                                  "id": 1,
                        "originLocationCode": "PPT",
                        "originRadius": null,
                        "alternativeOriginsCodes": [],
                        "destinationLocationCode": "CDG",
                        "alternativeDestinationsCodes": [],
                        "departureDateTimeRange": {
                            "date": "2022-12-22",
                            "dateWindow": "I2D"
                        },
                        "includedConnectionPoints": [],
                        "excludedConnectionPoints": []
                    }
                ],
                "travelers": [
                    {
                        "id": "1",
                        "travelerType": "ADULT",
                        "associatedAdultId": null
                    }
                ],
                "sources": [
                    "GDS"
                ]
            }'
    ];

    try {
    ...
        $response = $this->httpClient->post(self::AMADEUS_API_URL_FLIGHT_OFFER, $options);

        $body = $response->getBody();
        ...

注意:不要忘记内容类型,它不是很明显,在第一眼看到的文档,但没有它不工作与Guzzle对我来说(但与失眠没有问题)
类的常量:

private const AMADEUS_API_CLIENT_GRANT_TYPE = 'client_credentials';

private const AMADEUS_API_URL_AUTH = '/v1/security/oauth2/token';

private const AMADEUS_API_URL_FLIGHT_OFFER = '/v2/shopping/flight-offers';

身份验证:

/**
     *
     */
    public function authenticate()
    {
        if (!is_null($this->getApiToken())) {
            return $this->getApiToken();
        }

        $options = [
            'form_params' => [
                'client_id' => $this->apiId, //setted in the parent construct
                'client_secret' => $this->apiKey, //setted in the parent construct
                'grant_type' => self::AMADEUS_API_CLIENT_GRANT_TYPE,
            ]
        ];

        try {

            $response = $this->httpClient->post(self::AMADEUS_API_URL_AUTH, $options);
        } catch (ClientExceptionInterface $exception) {
            ...
        }

        if ($response->getStatusCode() != Response::HTTP_OK) {
            
            throw new ApiException($errorMessage, [$response->getReasonPhrase()], $response->getStatusCode());
        }

        $body = $response->getBody();
        //custom serializer, AmadeusAuthenticationResponse is a mapping based on Amadeus authentication response
        $authenticationResponse = $this->serializer->convertSerializationToData($body->getContents(), AmadeusAuthenticationResponse::class);

        $this->setApiToken($authenticationResponse->getAccessToken());

        return $this->getApiToken();
    }';

相关问题