Skip to content

Adds support for Provider HTTP Handling #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: trunk
Choose a base branch
from

Conversation

JasonTheAdams
Copy link
Member

Waiting on: #46

This introduces an HTTP system to the Providers framework so models can send requests to the Provider API.

This is built to not depend on a specific HTTP Client (e.g. Guzzle), but instead is happy to work with any PSR-18 compatible Client. It also uses the HTTPlug set of packages to improve auto-discovery of said client.

When we go to implement this into the WordPress system, this will allow us to make our own client that uses (and navigate the quirks of) the WP request functions.

@JasonTheAdams JasonTheAdams mentioned this pull request Aug 7, 2025
13 tasks
Copy link
Member

@felixarntz felixarntz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JasonTheAdams Overall this looks like a great start - it gives me really clean software vibes which I love 😆

A few points of feedback on the interfaces and DTOs mostly. The high level approach looks awesome.


declare(strict_types=1);

namespace WordPress\AiClient\Providers\Contracts;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should live under Providers\Http\Contracts as well as it's directly related to the HTTP requests infrastructure.

*
* @since n.e.x.t
*/
interface AuthenticationInterface extends WithJsonSchemaInterface
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As proposed in #46, I think this should be renamed to RequestAuthenticationInterface.

Authentication can be for many things. But what this interface is for is specifically to authenticate a HTTP request (different from e.g. validating incoming authentication credentials in a platform).

This also further underlines the direct connection to the HTTP request layer.

*
* @throws InvalidArgumentException If the method is empty.
*/
public function __construct(string $method, string $uri, array $headers = [], ?string $body = null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my notes in #46, alternative to ?string $body we need to allow providing ?array $data. A few reasons:

  • For GET requests setting a $body does not make sense. We need to support setting key value pairs that would be used in query parameters.
    • In other words, this would technically alter the $uri under the hood.
  • For POST requests setting a $body works, but passing key value pairs or raw PHP array data would still be more intuitive. The correct formatting for the request could be handled at the transport layer.
    • In other words, this would technically transform the array data into a $body string, encoding it accordingly.

Having a $body class property does make sense to me. But how you provide data is a different consideration. It definitely should be possible to provide a raw body as string, but other options are relevant too.

*
* @throws InvalidArgumentException If the method is empty.
*/
public function __construct(string $method, string $uri, array $headers = [], ?string $body = null)
Copy link
Member

@felixarntz felixarntz Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should support something like an ?array $options parameter here.

There is far more to a request than these 4 (or 5) fields. For example, where would you be able to set a timeout (quite critical for some use-cases), or how to handle redirects, or what the user agent should be?

Related to my comment regarding $body and $data, I think another useful option to include would be an enum in what shape $data is provided. Here's an idea:

  • We combine $body and $data into one variable $data, which can be either a string or array. That already makes sense since you should only ever provide one or the other.
  • We have a data_format option and a related RequestDataFormatEnum which can be one of:
    • BODY (this would automatically be implied if $data is a string)
    • QUERY_PARAMS (this would automatically be implied if $data is an array and the method is GET)
    • BODY_PARAMS (if $data is an array, this would mean it would be sent as URL-encoded params in the body)
    • JSON (if $data is an array, this would mean it would be sent as JSON-encoded data in the body)

WDYT?

throw new InvalidArgumentException('URI cannot be empty.');
}

$this->method = strtoupper($method);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should introduce a simple RequestMethodEnum for this :)

Comment on lines +133 to +155
/**
* Gets the reason phrase.
*
* @since n.e.x.t
*
* @return string The reason phrase.
*/
public function getReasonPhrase(): string
{
return $this->reasonPhrase;
}

/**
* Checks if the response indicates success.
*
* @since n.e.x.t
*
* @return bool True if status code is 2xx, false otherwise.
*/
public function isSuccessful(): bool
{
return $this->statusCode >= 200 && $this->statusCode < 300;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my notes on #46, maybe these are a bit too opinionated to include here?

  1. What's reasonPhrase supposed to be?
  2. Whether a request is considered successful if between 200-299 or only if 200 exactly doesn't always have a clear answer, it depends on the specific environment and use-case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants