- Имена полей в ответе задавать в
snake_case
(prr_page
,created_at
,system_name
,...) - Для времени использовать
ISO 8601
(формат: YYYY-MM-DDTHH:MM:SSZ) - Отдавать данные (сам контент, поля сущностей, массивы сущностей), помещая их в
data
- GET: /api/users — получить список пользователей;
- GET: /api/users/123 — получить указанного пользователя;
- POST: /api/users — создать нового пользователя;
- PATCH: /api/users/123 — обновить данные пользователя;
- PUT: /api/users/123 — обновить все данные указанного пользователя (используется не часто);
- DELETE: /api/users/123 — удалить пользователя.
- get - 200 (HTTP_OK)
- create - 201 (HTTP_CREATED)
- update - 202 (HTTP_ACCEPTED)
- destroy - 200 (HTTP_OK) / 204 (HTTP_NO_CONTENT)
Контент отдавать в
data
!!!
{
"data": [
{
"name": "Первая страница сайта",
"created_at": "2017-09-01T11:54:22+03:00",
},
{
"name": "Вторая страница сайта",
"created_at": "2017-05-01T11:54:23+03:00",
}
]
}
{
"data":
{
"name": "Первая статья на сайте",
"created_at": "2017-09-01T11:54:22+03:00",
"images": [
{"name":"d32d23.png"},
{"name":"ew432f.png"}
]
}
}
{
"links": {
"first": "http://laravel55.dev/api/v1/post?page=1",
"last": "http://laravel55.dev/api/v1/post?page=8",
"prev": null,
"next": "http://laravel55.dev/api/v1/post?page=2"
}
}
{
"meta": {
"total":34,
"per_page":15
}
}
Например, для вывода по центру в модалке: "Данные успошно сохранены!":
{
"message": "Данные успошно сохранены!"
}
{
"data": [
{
"name": "Первая страница сайта",
"created_at": "2017-09-01T11:54:22+03:00",
},
{
"name": "Вторая страница сайта",
"created_at": "2017-05-01T11:54:23+03:00",
}
],
"links": {
"first": "http://site.test/api/v1/post?page=1",
"last": "http://site.test/api/v1/post?page=8",
"prev": null,
"next": "http://site.test/api/v1/post?page=2"
},
"meta": {
"total":34,
"per_page":15
},
"message": "Это список сущностей!"
}
ответ должен быть с кодом 422 - ошибка валидности
{
"errors": {
"name": [
"Поле Название обязательно для заполнения.",
"Поле Название должно иметь больше 6 символов."
]
},
"message": "The given data was invalid."
}
{
"error":"Incorect route"
}
TODO ???
{
"data": {
"file": 81
},
"message": "Файл успешно загружен!"
}
const HTTP_OK = 200;
const HTTP_CREATED = 201;
const HTTP_ACCEPTED = 202;
const HTTP_NO_CONTENT = 204;
const HTTP_BAD_REQUEST = 400;
const HTTP_UNAUTHORIZED = 401;
const HTTP_PAYMENT_REQUIRED = 402;
const HTTP_FORBIDDEN = 403;
const HTTP_NOT_FOUND = 404;
const HTTP_METHOD_NOT_ALLOWED = 405;
const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918
- http://site.test/posts?filter[terms][regions][]=dnepr&filter[terms][regions][]=kiev&order['created_at']=asc&filter[price_to]=123&filter[price_from]=123&filter[user.status]=1&coll[]=user&coll[]=name&per_page=15&page=2
- http://site.test/posts?q=фраза+для+поиска&sort=stars&order=desc&page=2&per_page=100
- https://api.github.test/search/repositories?sort=created_at&order=desc
- https://api.github.test/search/repositories?q=tetris+language
- https://api.github.test/search/repositories?q=tetris+language:assembly&sort=stars&order=desc&filter[price_from]=123
Пример реализации API CRUD на Laravel для управление страницамы сайта + комментарии для документации (http://apidocjs.com/):
<?php
namespace App\Http\Controllers\Api\Admin;
use App\Http\Requests\Api\Admin\PageRequest;
use App\Models\Page;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Resources\Page as PageResource;
class PageController extends Controller
{
protected $pageModel;
/**
* PageController constructor.
* @param $pageModel
*/
public function __construct(Page $pageModel)
{
$this->pageModel = $pageModel;
}
/**
* @api {get} /api/v1/admin/page Получить страницы
* @apiVersion 1.0.0
* @apiName GetPages
* @apiGroup Page
*
* @apiParam {int} [page=1] Номер страницы
* @apiParam {int} [per_page=15] Количество элементов для вывода
* @apiParam {string} [q] Строка для поиска
*
* @apiExample Пример запроса:
* /api/v1/admin/page?page=3&q=your+search+keywords
*
*/
public function index(Request $request)
{
$pages = $this->pageModel->sortable('id')->likeSearchable()->paginate($request->per_page);
return PageResource::collection($pages);
}
/**
* @api {post} /api/v1/admin/page Сохранить страницу
* @apiVersion 1.0.0
* @apiName PostPage
* @apiGroup Page
*
* @apiParam {string} title Заголовок страницы
* @apiParam {string} [slug] URL-slug
* @apiParam {string} [body] Контент
* @apiParam {integer{0,1}} [publish=1] Статус публикации
*
*/
public function store(PageRequest $request)
{
$page = $this->pageModel->create($request->validated());
return (new PageResource($page))
->additional(['message' => trans('notifications.store.success')])
->response()
->setStatusCode(\Illuminate\Http\Response::HTTP_CREATED);
}
/**
* @api {get} /api/v1/admin/page/:id Получить страницу
* @apiVersion 1.0.0
* @apiName GetPage
* @apiGroup Page
*
*/
public function show($id)
{
$page = $this->pageModel->with('metaTag')->findOrFail($id);
return new PageResource($page);
}
/**
* @api {put} /api/v1/admin/page Обновить страницу
* @apiVersion 1.0.0
* @apiName PutPage
* @apiGroup Page
*
* @apiParam {string} title Заголовок страницы
* @apiParam {string} [slug] Slug для URL
* @apiParam {string} [body] Контент
*
*/
public function update(PageRequest $request, $id)
{
$page = $this->pageModel->findOrFail($id);
$page->update($request->validated());
return (new PageResource($page))
->additional(['message' => trans('notifications.update.success')])
->response()
->setStatusCode(\Illuminate\Http\Response::HTTP_ACCEPTED);
}
/**
* @api {delete} /api/v1/admin/page/:id Удалить страницу
* @apiVersion 1.0.0
* @apiName DeletePage
* @apiGroup Page
*
*/
public function destroy($id)
{
$this->pageModel->findOrFail($id)->delete();
return response()
->json(['message' => trans('notifications.destroy.success'),])
->setStatusCode(\Illuminate\Http\Response::HTTP_OK);
}
}
AuthServiceProvider:
public function boot()
{
$this->registerPolicies();
//Passport::routes();
Passport::routes(
function ($router) {
$router->forAuthorization();
//$router->forAccessTokens();
//$router->forTransientTokens();
//$router->forClients();
//$router->forPersonalAccessTokens();
}
);
}
<?php
namespace App\Http\FormRequests;
use Illuminate\Http\JsonResponse;
/**
* Class FormRequest
*
* @package \App\Http\FormRequests
*/
class FormRequest extends \Illuminate\Foundation\Http\FormRequest
{
/**
* Get the proper failed validation response for the request.
*
* @param array $errors
* @return \Symfony\Component\HttpFoundation\Response
*/
public function response(array $errors)
{
if ($this->expectsJson()) {
return new JsonResponse([
'errors' => $errors
], 422);
}
parent::response($errors);
}
}
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
use ExceptionTrait;
/**
* A list of the exception types that are not reported.
*
* @var array
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array
*/
protected $dontFlash = [
'password',
'password_confirmation',
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $exception
* @return void
*/
public function report(Exception $exception)
{
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
if ($request->expectsJson()) {
return $this->apiException($request, $exception);
}
return parent::render($request, $exception);
}
}
<?php
namespace App\Exceptions;
use Symfony\Component\HttpFoundation\Response;
trait ExceptionTrait
{
public function apiException($request, $e)
{
if ($this->isModel($e)) {
return $this->modelResponse($e);
}
if ($this->isHttp($e)) {
return $this->httpResponse($e);
}
return parent::render($request, $e);
}
protected function isModel($e)
{
return $e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException;
}
protected function isHttp($e)
{
return $e instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
}
protected function modelResponse($e)
{
$modelClass = explode('\\', $e->getModel());
return response([
'error' => 'Model '.end($modelClass).' not found',
], Response::HTTP_NOT_FOUND);
}
protected function httpResponse($e)
{
return response([
'error' => 'Incorrect route name',
], Response::HTTP_NOT_FOUND);
}
}
<?php
namespace App\Exceptions;
use Exception;
class RepositoryException extends Exception
{
public function render($request, Exception $exception)
{
return 'Error model';
}
}
@Barmunksu Такой же вопрос...