Własny endpoint REST API
Własny endpoint REST API
Ten artykuł opisuje jak zarejestrować endpointy REST API w utworzonej przez ciebie aplikacji do systemu Ready.
Przykładowa klasa endpointu
<?php
namespace ReadyApp\TestRestApi;
use ApiRequest;
use PgManager;
use Ready\App\RestApi\AbsRestEndpoint;
use Ready\App\RestApi\Custom\EndpointConfig;
use Ready\App\RestApi\Custom\UriVariable;
use Symfony\Component\HttpFoundation\Response;
use ReadyApi\Rest\RestApiEndpointInterface;
class GetOneUser extends AbsRestEndpoint implements RestApiEndpointInterface {
/**
* @return EndpointConfig
* @throws \Exception
*/
public function getConfiguration(): EndpointConfig {
$config = new EndpointConfig('GET', '/users/{usr_id}');
$config->setUriVariable('usr_id', UriVariable::INTEGER);
return $config;
}
/**
* @param ApiRequest $request
* @param array $uriVariables
*
* @return void
* @throws \Exception
*/
public function processRequest(ApiRequest $request, array $uriVariables): void {
$db = PgManager::getInstance();
$user = $db->select('users', 'usr_id, usrnam', 'usr_id = '.$uriVariables['usr_id'], FALSE, PGSQL_ASSOC);
$this->prepareResponseDataArray($user[0] ?? [], Response::HTTP_OK);
}
}
W pigułce
W nowym standardzie pisania aplikacji 2.0, każdy endpoint to oddzielna klasa, która implementuje interfejs RestApiEndpointInterface
.
Implementacja interfejsu:
- public function getConfiguration(): EndpointConfig - Dostarcza konfiguracje endpointu czyli opisuje nazwę metody http, uri oraz zmienne w uri wraz z ich walidacją. (Do zaimplementowania przez developera)
getConfiguration()
Definiujemy TYLKO nazwę metody, uri i zmienne w uri
public function processRequest(ApiRequest, array $uriVariables): void - Wykonuje logikę biznesową potrzebną do obsłużenia requesta. (Do zaimplementowania przez developera).
public function getResponse(): Response - Zwraca response po przetworzeniu requesta. (Wystarczy rozszerzyć klasę endpointu o
AbsRestEndpoint
, która to zwiera implementacje metodygetResponse()
)
Rejestracja klasy za pomocą ready-cli:
./ready-cli config:register \\Namespace\\Wraz\\Z\\Nazwą\\Klasy
Czyli dla przykładu powyżej rejestracja będzie wyglądać tak:
./ready-cli config:register \\ReadyApp\\TestRestApi\\GetOneUser
Escape'owanie backslash'y
Zwróć uwagę, że podczas rejestracji znak backslash '\' jest escape'owany na '\\'
Autoload'ing klasy
Upewnij się, że podawany namespace jest w pliku composer.json w standardzie PSR-4 lub znajduje się w katalogu public_html/apps/edokumenty/scripts/my/catalog/structure
z namespace'm namespace ReadyApp\my\catalog\structure;
Następnie trzeba przegenerować config.
./ready-cli config:compile
EndpointConfig szczegółowe omówienie
Klasa dzięki, której dodamy konfiguracje endpointu. Sama klasa waliduje konfiguracje, którą jej się dostarcza, więc np: jeśli zapomnisz zadeklarować wszystkich zmiennych podanych w uri to zostaniesz o tym poinformowany 😃
Utworzenie obiektu
$config = new EndpointConfig($httpMethod, $uri);
$httpMethod
- nazwę metody http np: 'GET'
Dostępne metody to:
- 'GET',
- 'POST',
- 'PATCH',
- 'PUT',
- 'DELETE',
- 'OPTIONS'
$uri
- uri endpointu np: '/catTypes/{cat_tp}/cats/{cat_id}'
Zmienne podajemy otoczone wyłącznie nawiasami klamrowymi np: {cat_id}
Powyższy przykład ($uri) wygeneruje nam URL, do którego możemy odwołać się np:https://my/ready/domain/api.php/REST/custom/catTypes/1/cats/1
Ustawianie zmiennych z Uri
Każdą zmienną w uri trzeba zadeklarować przy pomocy metody setUriVariable($varName, $pattern)
Dla przykładu poniżej MUSIMY zadeklarować zmienne {cat_tp}
oraz {cat_id}
/**
* @return EndpointConfig
* @throws \Exception
*/
public function getConfiguration(): EndpointConfig {
$config = new EndpointConfig('GET', '/catTypes/{cat_tp}/cats/{cat_id}');
$config->setUriVariable('cat_tp', UriVariable::STRING);
$config->setUriVariable('cat_id', UriVariable::INTEGER);
}
$varName
- nazwa zmiennej z uri np: 'cat_id'
Nazwa zmiennej musi się pokrywać z nazwą zmiennej podanej w uri.
$pattern
- regex używany do walidacji zmiennej. np: '[A-Z]+'
Możliwe jest użycie predefiniowanych typów, które są przyjaznym aliasem na regex, który
reprezentują.
Typ | Regex |
---|---|
UriVariable::INTEGER | [0-9]+ |
UriVariable::STRING | [A-Za-z0-9]+ |
UriVariable::EMAIL | [a-z_-.0-9]+@[a-z_-.0-9]+.[a-z]{2,3} |
Pełny schemat URL
Endpointy po zajerestrowaniu i przegenerowaniu konfiguracji dostępne są pod adresem:
https://my/ready/domain
/api.php/REST/custom/my/{uri}
my/ready/domain
- nazwa domeny na którym znajduje się system ready./my/{uri}
- uri podane w konstruktorze klasyEndpointConfig
np:/users/{usr_id}
Generowanie response'a w Funkcji processRequest() - szczegółowe omówienie
Procesowanie requesta zawsze musi się zakończyć się wygenerowaniem response'a. Ponieważ nasza klasa endpointu dziedziczy po AbsRestEndpoint
to mamy dostęp do funkcji pomocniczych, które wygenerują response zgodnie z naszymi oczekiwaniami.
prepareCustomResponse()
Użyj jeśli chcesz aby twój zwracany JSON miał unikalną strukturę.
public function processRequest(ApiRequest $request, array $uriVariables): void {
$data = [
[
"id" => 1,
"name" => "Barbara Cacko",
"email" => "bcacko@edokumenty.eu"
],
[
"id" => 2,
"name" => "Jan Nowak",
"email" => "jnowak@edokumenty.eu"
]
];
$links = [
"first" => "https://my/ready/domain/api.php/REST/custom/users?page=1",
"last" => "https://my/ready/domain/api.php/REST/custom/users/?page=5",
"prev" => "https://my/ready/domain/api.php/REST/custom/users?page=2",
"next" => "https://my/ready/domain/api.php/REST/custom/users/?page=4"
];
$meta = [
"current_page" => 3,
"last_page" => 5,
"per_page" => 2,
"total" => 10
];
$responseBody = [
'data' => $data,
'links' => $links,
'meta' => $meta
];
$headers = [
'myCustom' => 'header'
];
$this->prepareCustomResponse($responseBody, Response::HTTP_OK, $headers);
}
Tak będzie wyglądać JSON w response body
{
"data": [
{
"id": 1,
"name": "Barbara Cacko",
"email": "bcacko@edokumenty.eu"
},
{
"id": 2,
"name": "Jan Nowak",
"email": "jnowak@edokumenty.eu"
}
],
"links":{
"first": "https://my/ready/domain/api.php/REST/custom/users?page=1",
"last": "https://my/ready/domain/api.php/REST/custom/users/?page=5",
"prev": "https://my/ready/domain/api.php/REST/custom/users?page=2",
"next": "https://my/ready/domain/api.php/REST/custom/users/?page=4"
},
"meta":{
"current_page": 3,
"last_page": 5,
"per_page": 2,
"total": 10
}
}
prepareResponse()
Użyj jeśli chcesz zwrócić identyfikator obiektu. Przydatne dla endpoint'ów typu POST/PUT/PATCH/
public function processRequest(ApiRequest $request, array $uriVariables): void {
$data = [
'dctpid' => 4,
'dscrpt' => 'Przykładowa notatka'
];
include_once('./classes/eDokumentyApi/EDokApi.inc');
$localApi = new EDokApi();
$doc_id = $localApi->createDocument($data);
$headers = [
'myCustom' => 'header'
];
$this->prepareResponse('doc_id', $doc_id, Response::HTTP_OK, $headers);
}
Tak będzie wyglądać JSON w response body
{
"data": {
"doc_id": "11"
}
}
prepareResponseDataArray()
Użyj jeśli chcesz zwrócić dane w formacie tablicy obiektów. Przydatne dla endpoint'ów typu GET
public function processRequest(ApiRequest $request, array $uriVariables): void {
$db = PgManager::getInstance();
$data = $db->select('my_register', 'field_1, field_2', 'is_del = FALSE', FALSE, PGSQL_ASSOC);
$headers = [
'myCustom' => 'header'
];
$this->prepareResponseDataArray($data, Response::HTTP_OK, NULL, $headers);
}
Tak będzie wyglądać JSON w response body
{
"data": [
{
"field_1": "1",
"field_2": "Dummy data"
},
{
"field_1": "2",
"field_2": "Bla ble"
},
{
...
}
]
}
prepareNotFoundResponse()
Użyj jeśli nie znaleziono szukanego obiektu. Zwraca kod 404. Przydatne dla endpoint'ów typu GET/PATCH/DELETE
public function processRequest(ApiRequest $request, array $uriVariables): void {
$this->prepareNotFoundResponse();
}
Tak będzie wyglądać JSON w response body
{
"data": []
}
prepareEmptyResponse()
Zwraca puste response body. domyślnie ustawia kod 204, ale można ustawić inny. Przydatne dla endpoint'ów typu DELETE
public function processRequest(ApiRequest $request, array $uriVariables): void {
$this->prepareEmptyResponse();
}
Tak będzie wyglądać JSON w response body (Tak nie będzie go wcale 😃 )
Klika przykładowych wywołań getConfiguration()
Przykład nr 1
public function getConfiguration(): EndpointConfig {
return new EndpointConfig('POST', '/documents');
}
Przykład wygeneruje nam URL https://my/ready/domain/api.php/REST/custom/documents
Przykład nr 2
public function getConfiguration(): EndpointConfig {
$config = new EndpointConfig('GET', '/documents/{dctptp}/{doc_id}/features');
$config->setUriVariable('dctptp', UriVariable::STRING);
$config->setUriVariable('doc_id', UriVariable::INTEGER);
return $config;
}
Przykład wygeneruje nam URL https://my/ready/domain/api.php/REST/custom/documents/Note/1/features
Zwróć uwagę, że:
Note
to{dctptp}
1
to{doc_id}
Przykład nr 3
public function getConfiguration(): EndpointConfig {
$config = new EndpointConfig('PUT', '/notifications/{msg_id}');
$config->setUriVariable('msg_id', '[1-9][0-9]*'); // można podawać swój regex
return $config;
}
Przykład wygeneruje nam URL https://my/ready/domain/api.php/REST/custom/documents/notifications/10
Zwróć uwagę, że:
10
to{msg_id}