Describe a model. Get a full API.
A Laravel package that turns your Eloquent models into a JSON API. List the fields and relations clients may use, add one route line, and get search, writes, deletes and your own actions, validated and checked against your policies.
composer require lomkit/laravel-rest-apiPHP 8.3+ · Laravel 13.30+ · MIT license
class ProductResource extends Resource
{
public static string $model = Product::class;
public function fields(): array
{
return [
ID::make('id'),
Integer::make('category_id'),
Text::make('name')->creationRules('required'),
Integer::make('price'),
];
}
public function relations(): array
{
return [
BelongsTo::make('category', CategoryResource::class),
];
}
}
Rest::resource('products', ProductsController::class);
Routes it registers
- GET/api/products
- POST/api/products/search200
- POST/api/products/mutate
- POST/api/products/actions/{action}
- POST/api/products/metrics/{metric}
- DELETE/api/products
POST/api/products/search
{
"search": {
"filters": [
{"field": "price", "operator": "<", "value": 100}
],
"includes": [{"relation": "category"}]
}
}
Response200 OK
{
"current_page": 1,
"data": [{
"id": 1, "category_id": 1, "name": "Desk lamp",
"price": 39, "category": {"id": 1, "name": "Lighting"}
}],
"from": 1, "last_page": 1, "per_page": 50,
"to": 1, "total": 1, "meta": {}
}
price and category are declared, so clients can filter on one and include the other.
Try a search
Clients ask for exactly the rows they need
Filters, sorts, related rows and per-row permissions travel in one JSON body. Pick options below: the request changes, and so does the answer the package gives.
Options
{
"search": {
"filters": [
{"field": "price", "operator": "<", "value": 100}
],
"includes": [{"relation": "category"}]
}
}
{
"current_page": 1,
"data": [
{
"id": 1, "category_id": 1, "name": "Desk lamp", "price": 39,
"category": {"id": 1, "name": "Lighting"}
}
],
"from": 1, "last_page": 1, "per_page": 50,
"to": 1, "total": 1, "meta": {}
}
Four products in two categories. Without a sort, rows come by key, highest first. A page holds 50 rows unless the request sends a limit the resource allows.
Beyond search
Every resource gets the same endpoints
Write rows with their relations, run your own actions, compute metrics, describe the resource, delete rows, and restore them when the model uses soft deletes. Each one checks the same declarations and the same policies.
Count and total related rows
count, exists, min, max, avg and sum over a relation, computed in SQL next to each row.
public function relations(): array
{
return [
HasMany::make('products', ProductResource::class),
];
}
{
"search": {
"aggregates": [
{"relation": "products", "type": "count"},
{"relation": "products", "type": "max", "field": "price"}
]
}
}
{
"current_page": 1,
"data": [
{"id": 1, "name": "Lighting", "products_count": 2, "products_max_price": 129}
],
"from": 1,
"last_page": 1,
"per_page": 50,
"to": 1,
"total": 1,
"meta": {}
}
Safe by default
Nothing is written until every check passes
Your Laravel policies and validation rules run on every request, in a fixed order, before anything is written. Pick a request and watch where it stops.
- Entry checksviewAny on every resource the request reaches, before validation.
- ValidationDeclared fields and rules only, keys read inside the perimeter.
- Row checksIn the transaction, the policy of every row, before the first write.
- WriteEvery entry is written, or the transaction rolls back.
{
"mutate": [
{"operation": "update", "key": 1, "attributes": {"cost": 20}}
]
}
{"message": "This action is unauthorized."}
The policy refuses viewAny: the request stops before validation, even with an invalid payload, and before any query.
For your frontend
Your interface asks the API what it may do
The details endpoint describes a resource for the signed-in user: fields, operators, rules, page sizes, actions and permissions. Build lists and forms from it instead of copying your rules into JavaScript.
- One request per screen: a list, a form or an action dialog asks only for the parts it shows. Read more
- Each row of a search can say whether the user may update or delete it, with the message of your policy. Read more
- Turn on Laravel Precognition and forms validate as the user types: the same checks, nothing written. Read more
Artworks
Point at a part of this screen to see the key of the details it comes from.
{"data": {
"fields": [
{
"name": "title", "label": "Title", "type": "text",
"nullable": false, "select": true, "sort": true,
"filter": {"operators": [
"=", "!=", "like", "not like", "ilike", "not ilike", "in", "not in"
]},
"create": true, "update": true,
"rules": {"all": ["string", "max:120"], "create": ["required"], "update": ["filled"]},
"meta": {}
}
],
"limits": [10, 25, 50],
"meta": {}
}}
Documented
The API documents itself
Your declarations already say what each endpoint accepts. The package turns them into an OpenAPI document through Scramble, and ships a skill so coding agents know the same rules.
Product
- GETGet Product details
- POSTSearch Product
- POSTMutate Product
- DELETEDelete Product
/docs/api
Search Product
POST /api/products/search · body ProductSearch · 200 ProductPaginated
search.filters: one condition per filterable field
id=, !=, in, not inname=, !=, like, not like, ilike, not ilike, in, not inprice=, !=, >, >=, <, <=, between, not between, in, not in
Includes, aggregates, scopes, instructions, actions and metrics get their schemas too, with the 401, 403, 404 and 422 responses.
$ composer require dedoc/scramble:^0.13.48
$ php artisan scramble:export
A skill for coding agents
The package ships a laravel-rest-api skill for Laravel Boost: resources, payloads, limits, authorization and the conventions to keep, for the version you installed.
$ composer require laravel/boost --dev
$ php artisan boost:install
As your app grows
Everything else a real API needs
Your models are ready. Give them an API.
Three steps, and the rules you already wrote in Laravel.
- 1 Install the package
composer require lomkit/laravel-rest-api - 2 Expose the models you pick
php artisan rest:quick-start - 3 Send your first search
POST /api/products/search
Laravel Rest Api is MIT licensed and maintained by Lomkit.