Query parameters customisation
asamofal opened this issue · comments
Hi! I have to work with 3d party API that expects such request:
POST /consignments/label_direct?printer_id=123&consignment_ids[]=1&consignment_ids[]=2
I tried these ways:
protected function defaultQuery(): array
{
return [
'printer_id' => $this->printerId,
'consignment_ids' => [$this->consignmentId],
];
}
and
public function resolveEndpoint(): string
{
return "/consignments/label_direct?printer_id=$this->printerId&consignment_ids[]=$this->consignmentId";
}
But they both give me the same result:
/consignments/label_direct?printer_id=1393&consignment_ids%5B0%5D=51872349
The issue lies in that index: %5B0%5D
(with 0 placed between encoded brackets). That amazing API throws 500 in my face because of it. Any chance for me to customize a query in such way as that API require me?
Alright, I've worked out the details and found a solution.
Guzzle constructs the query string using the http_build_query
function, which includes indexes for arrays. Fortunately, Saloon supports PSR request modification at both the Connector and Request levels. In my request, I simply modify the PSR request and use regex to remove the numbers within the square brackets.
public function handlePsrRequest(RequestInterface $request, PendingRequest $pendingRequest): RequestInterface
{
return $request->withUri(
$request->getUri()->withQuery(
preg_replace(
'/[[\d]+]/',
'[]',
rawurldecode($request->getUri()->getQuery())
)
)
);
}
@Sammyjo20 Thanks for this level of flexibility :)
@asamofal Thank you, that helped me a lot!
Further information in the documentation: Modifying the PSR-7 Request
Thank you for posting the issue and letting me know - I've had a few people mention this actually and I was wondering if we needed to have a conversation around potentially changing Saloon's implementation. I'm not quite sure if there's a way to do it without a breaking change.
I guess the issue is that different APIs have different standards for "multiple" query parameters. I'll check RFC and see if it's defined somewhere!
Update: I found this Stack Overflow answer: https://stackoverflow.com/questions/24059773/correct-way-to-pass-multiple-values-for-same-parameter-name-in-get-request
@Sammyjo20 Yeah, the http_build_query
PHP function has an option encoding_type
that refers to two RFCs:
RFC 1738 and RFC 3986. However, I didn't find anything about multiple values in query strings there. So, I think it depends just on the specific implementation.
I'm not sure how common this problem is. I mean, is there any sense in adding a method to modify the process of building a query string? It sounds too specific, considering you can do whatever you need in just handlePsrRequest
.
I have met all kinds of required calls for multiple values like:
consignment_ids[]=1&consignment_ids[]=2
consignment_ids[0]=1&consignment_ids[1]=2
consignment_ids=1&consignment_ids=2
and of course, when you send it in a different way, everything breaks 🤦♂️ So even if there is any standard, it's not kept by API creators.
Not sure if the library accepts it, but maybe instead of an array with parameters and values we could just pass custom built query as a string?
Yep I believe Saloon does accept providing the query string in the resolveBaseUrl
and resolveEndpoint
methods. I don't think this gets parsed, I think it just gets joined with the other query parameters. Might be worth trying that as it may be a nicer workaround.
I just spent quite a while trying to figure this out myself – the API I'm working with requires query param arrays in key=foo,bar,baz
format. Implementing the fix in handlePsrRequest
was pretty straightforward:
public function handlePsrRequest(RequestInterface $request, PendingRequest $pendingRequest): RequestInterface
{
$query = $pendingRequest->query()->all();
$uri = $request->getUri();
$uri = $uri->withQuery(Query::build($query));
$request = $request->withUri($uri);
return $request;
}
I think it might be helpful to have some mention of this issue in the Query Parameters
section of the Requests documentation. It wasn't immediately obvious to me how to make a docs PR, but I'd be happy to do so if that would be helpful.
Edit: nevermind, figured out how to edit the docs. PR here: Sammyjo20/saloon-docs#60
My pleasure! Thanks for making such a great library :)
Thanks man, I'm glad you find it useful :D