繁体   English   中英

无法通过 Amadeus 使用 guzzle 发布请求 API

[英]Unable to POST request using guzzle with the Amadeus API

描述
我正在尝试将 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”传递,并将数据作为正文传递。

$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)

请花点时间看看,非常感谢帮助。

POST 调用是否真的使用 HTTP 客户端(如 Postman 或 Insomnia)工作?

我注意到您正在传递一组$options并将其嵌套在 Guzzle 选项中。 生成的调用将如下所示:

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

那行不通,您将需要以这种方式解压缩它们:

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

注意点...以解压缩选项数组。 另请注意,您将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选项而不是 POST 请求的body

当您探索任何 Amadeus Self Service API 时,我建议您查看门户,因为它会帮助您了解如何进行 http 调用。

在您的情况下: https ://developers.amadeus.com/self-service/category/air/api-doc/flight-offers-search/api-reference

另一个帮助可能是查看编码示例:

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

$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(但失眠没问题)

class 的常量:

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();
    }';

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM