Endpoints
Endpoint contains a way to call an API endpoint (endpoint can contain multiple functions to call API endpoint).
The main goal of an endpoint is to:
- 🚀 Build and get the request using
$this->api->X()
. See Calling API section. - 🛠Create a response from request result using
$this->makeResponse
Implementation
Place your endpoints in
YourApi\Endpoints\MyEndpoint
namespace and use Endpoint suffix.
Implementation is easy. Just implement the basePath to return base URI, then create function that calls API endpoint.
Your function should accept data for building url and the request body content:
- Arguments for the URI should be like int $id or and
Entity
object. - Options for the data should use
OptionsContract
and can be null or built (). See Passing data section.
class UnitsEndpoint extends AbstractEndpoint
{
protected function basePath(): string
{
return 'units';
}
/**
* @throws InvalidJsonResponseException
*/
public function get(
int $id,
GetUnitsOptions $options = null,
): UnitsResponse {
$result = $this->api->post($this->uri($id), $options);
return $this->makeResponse(UnitsResponse::class, $result);
}
}
- You can change the base URI building by overriding uri implementation in your endpoint.
- You can use dependency injection in the __construct.
Calling API
In your endpoint use $this->api->X()
to call API.
Use $this->uri()
to get endpoints base url. You can append query data as you please:
- For adding query data use
$this->uri()->addQueryParam('key', 'myvalue')
- Add path parameter using
$this->uri($id)
. No need to add/
. - For more check JustSteveKing/uri-builder.
Passing data
For passing data you can use:
string
- object that implements
StreamInterface
- object that implements
OptionsContract
-> returns a string - object that extends
AbstractJsonOptions
for sending JSON data
We advise that you use MyOptions $options = new MyOptions()
in your function when you want default values to be sent.
Options
Options objects are ideal to for building data that can be sometimes optional. Helps to make type safe code.
- Implement
OptionsContract
- Use
__constructor
for your setting properties that can be adjusted by the consumer. - Use
nullable
properties for optional data (with combinationarray_filter
) - Implement
toBody
to build the data
JSON Options
For building JSON data you want to extend AbstractJsonOptions
and implement toArray
.
use WrkFlow\ApiSdkBuilder\Options\AbstractJsonOptions;
class PageInfoOptions extends AbstractJsonOptions
{
public function __construct(
public int $page = 1,
public int|null $perPage = 100
) {
}
public function toArray(): array
{
return [
'page_info' => [
'page' => $this->page,
'per_page' => $this->perPage,
],
];
}
}
use WrkFlow\ApiSdkBuilder\Options\AbstractJsonOptions;
class PageInfoOptions extends AbstractJsonOptions
{
public function __construct(
public int $page = 1,
public int|null $perPage = null
) {
}
public function toArray(): array
{
return array_filter([
'page' => $this->page,
'items_per_page' => $this->perPage,
]);
}
}
When using AbstractJsonOptions
you can accept multiple options in you method and then merge them for API call using MergedJsonOptions
(accepts null).
/**
* @throws InvalidJsonResponseException
*/
public function paginate(
GetUnitsOptions $options = null,
PageInfoOptions $page = new PageInfoOptions()
): UnitsResponse {
$result = $this->api->post($this->uri(), new MergedJsonOptions([$options, $page]));
return $this->makeResponse(UnitsResponse::class, $result);
}
Get request
Arguments:
- URI address to call
uri: JustSteveKing\UriBuilder\Uri
- Headers to send
headers: array<int|string,HeadersContract|string|string[]>
$response = $this->api->post($this->uri(), $options);
Post request
Arguments:
- URI address to call
uri: JustSteveKing\UriBuilder\Uri
- Data to send
options: OptionsContract|StreamInterface|string
- Headers to send
headers: array<int|string,HeadersContract|string|string[]>
$response = $this->api->post($this->uri(), $options);
Put request
To be implemented. Make PR! Edit AbstractApi
.
Delete request
To be implemented. Make PR! Edit AbstractApi
.
Custom requests
You build any request you want by creating request using $this->api->factory()->request(): PSR-7 compatible
and then
calling sendRequest
.
/**
* @param array<int|string,HeadersContract|string|string[]> $headers
*/
public function delete(
): ResponseInterface {
$request = $this->api->factory()
->request()
->createRequest('DELETE', $this->uri()->toString());
return $this->api->sendRequest($request, $headers, $body);
}
If the package misses some "general" requests, please make a PR and edit AbstractApi
.
Conventions
Methods
get
Use this for retrieving non paginated response. It can be post / get any HTTP method.
create
Create resource. It can be post / put any HTTP method.
update
Update resource It can be post / put any HTTP method.
delete
Delete resource. It can be post / put / delete any HTTP method.
paginate
Use this for endpoints that returns paginated results.
Ideal to combine with AbstractJsonItemsResponse and PaginatedResponse trait.
all
Use this if you want to provide a way to loop all entries via paginated API endpoint.
You should provide:
- Options for tweaking the request.
- Item callback.
- Callbacks for the loop lifecycle.
public function all(
Closure $onItem,
GetUnitsOptions $options = null,
?Closure $onResponse = null,
?Closure $onLoopEnd = null,
): bool;
The implementation is currently not abstracted.
Name
- Try to use the same structure and name as the api endpoint
Folder structure
It is better to store endpoints in their own folder with all responses, options and entities in the folder.
Endpoints/UsersEndpoint/
- UsersEndpoint.php
- UsersResponse.php
- UserEntity.php
- GetUsersOptions.php
- JsonToUserEntity.php (transformer)
Example
- from
/repos/{owner}/{repo}/actions/artifacts
- to
GithubApi\Endpoints\Repos\Actions\Artifacts\ArtifactsEndpoint