Я хочу задать вопрос о том, как лучше реализовать REST с одной конечной точкой.
Я хочу создать API отдыха, но хочу, чтобы у него была только одна конечная точка, например: graphql
, где у вас есть только лайки: host/graphql
.
Я уже делал этот пример в laravel
где нужно поставить ключ и метод для перехода к определенному API.
Тело выглядит так (пример вызова API продукта с единственной конечной точкой).
Звонок получить весь товар:
{
"key":"product/all",
"method":"GET"
}
Вот и получилось (product / {id}):
{
"key":"product",
"method":"GET",
"payload":"{"id":"1"}"
}
Это также отлично работает с публикацией, помещением и удалением.
Вот код единственной конечной точки (я использую php laravel
в качестве примера, потому что быстро сделать API):
public function bridge(Request $request)
{
$host = "http://127.0.0.1:8000/api/";
if ($request->has("payload")) {
$bounds = html_entity_decode($request->payload);
$payload = json_decode($bounds, true);
}
if (strtoupper($request->method) == "POST") {
try {
$url = $host . $request->key;
$request = Request::create($url, 'POST', []);
$response = Route::dispatch($request);
return $response;
} catch (Throwable $th) {
$data["data"] = [];
$data["success"] = false;
$data["code"] = 500;
$data["message"] = $th->getMessage();
return $data;
}
} else if (strtoupper($request->method) == "PUT") {
try {
$url = $host . $request->key . "https://codereview.stackexchange.com/" . $payload['id'];
$request = Request::create($url, 'PUT', []);
$response = Route::dispatch($request);
return $response;
} catch (Throwable $th) {
$data["data"] = [];
$data["success"] = false;
$data["code"] = 500;
$data["message"] = $th->getMessage();
return $data;
}
} else if (strtoupper($request->method) == "DELETE") {
try {
$url = $host . $request->key . "https://codereview.stackexchange.com/" . $payload['id'];
$request = Request::create($url, 'DELETE', []);
$response = Route::dispatch($request);
return $response;
} catch (Throwable $th) {
$data["data"] = [];
$data["success"] = false;
$data["code"] = 500;
$data["message"] = $th->getMessage();
return $data;
}
} else {
$url = $host . $request->key;
try {
if ($request->has("payload")) {
$url = $host . $request->key . "/" . $payload['id'];
}
$request = Request::create($url, 'GET');
$response = Route::dispatch($request);
return $response;
} catch (Throwable $th) {
$data["data"] = [];
$data["success"] = false;
$data["code"] = 500;
$data["message"] = $th->getMessage();
return $data;
}
}
}
Как видите там. Он вызывает API дважды «мост» и «ключевой» API.
Минусы тут:
- запрос звонка дважды;
- вы можете поместить только одну переменную / {id} (или несколько, если вы ее объявите).
Плюсы:
- это только одна конечная точка, поэтому будет легко создать помощник api во внешнем интерфейсе (возможно, XD).
Вы можете показать мне лучший способ сделать это? Расскажите мне свои советы и мысли или, может быть, покажите какой-нибудь код (любой язык подойдет).
1 ответ
У меня есть только несколько замечаний по поводу придирчивости:
- Не повторяйся (СУХОЙ)
- Объявить
$url = $host . $request->key
безусловно в начале вашего метода (скажем, после$host
). Затем добавьте к нему текст, если / когда необходимо$url .= "https://codereview.stackexchange.com/" . $payload['id'];
. strtoupper($request->method)
выполняется в каждом условном выражении. Лучше изменить строку один раз. Вы также проверяете одни и те же данные для разных строк, вот чтоswitch-case
блоки предназначены для.- Вместо того, чтобы писать
$data
(не описательное имя переменной) снова и снова, полностью опускайте объявление переменной и записывайте данные непосредственно вreturn
. Я регулярно рекомендую не объявлять одноразовые переменные, если они существенно не уменьшают ширину кода или не улучшают читаемость.
- Объявить
else if
должно бытьelseif
в PHP, чтобы соответствовать стандарту кодирования PSR-12.- Все созданные вами исключения обрабатываются одинаково, поэтому кажется гораздо более чистым вариантом обернуть весь ваш блок переключателя в один
try-catch
блокировать. - Возможно, вы захотите увидеть полезную нагрузку при возникновении исключения; если да, используйте
"data" => $payload ?? []
в ответ.
Ваш код может быть переписан как:
public function bridge(Request $request)
{
$host = "http://127.0.0.1:8000/api/";
$url = $host . $request->key;
if ($request->has("payload")) {
$payload = json_decode(html_entity_decode($request->payload), true);
}
try {
switch (strtoupper($request->method)) {
case "POST":
return Route::dispatch(Request::create($url, 'POST', []));
case "PUT":
$url .= "https://codereview.stackexchange.com/" . $payload['id'];
return Route::dispatch(Request::create($url, 'PUT', []));
case "DELETE":
$url .= "https://codereview.stackexchange.com/" . $payload['id'];
return Route::dispatch(Request::create($url, 'DELETE', []));
default:
if ($request->has("payload")) {
$url .= "/" . $payload['id'];
}
return Route::dispatch(Request::create($url, 'GET'));
}
} catch (Throwable $th) {
return [
"data" => $payload ?? [],
"success" => false,
"code" => 500,
"message" => $th->getMessage(),
];
}
}