Skip to content

Commit cafc029

Browse files
authored
Improve documentation (#33)
Signed-off-by: Bruno Gaspar <brunofgaspar1@gmail.com>
1 parent 3679d82 commit cafc029

11 files changed

Lines changed: 362 additions & 66 deletions

File tree

docs/1.basics/1.resources.md

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@ class ProductResource extends Resource
3737
}
3838
```
3939

40+
## Static Construction
41+
42+
Use `Resource::make()` to serialize a model into a JSON:API array without going through a controller or response object. This resolves the resource from the container and calls `toArray()`:
43+
44+
```php
45+
use App\Http\Resources\ProductResource;
46+
use App\Models\Product;
47+
48+
$product = Product::find(1);
49+
$data = ProductResource::make($product);
50+
// Returns: ['type' => 'products', 'id' => '1', 'attributes' => [...], ...]
51+
```
52+
53+
This is useful for embedding resource data inside jobs, events, or notifications where you do not need a full HTTP response.
54+
4055
## Type and ID Resolution
4156

4257
By default, the toolkit resolves:
@@ -49,6 +64,8 @@ By default, the toolkit resolves:
4964
Override `resolveId()` on your resource for full control. This takes precedence over the global resolver:
5065

5166
```php
67+
use BlueBeetle\ApiToolkit\Resources\Resource;
68+
5269
class ProductResource extends Resource
5370
{
5471
protected string $type = 'products';
@@ -144,7 +161,7 @@ The `self()` link is automatically merged with any additional links from `links(
144161

145162
## OpenAPI Schema
146163

147-
Define attribute types for automatic OpenAPI spec generation. The `schema()` method controls how your resource's attributes appear in the generated OpenAPI document.
164+
Define attribute types for automatic [OpenAPI spec generation](/docs/api-toolkit/latest/advanced/openapi). The `schema()` method controls how your resource's attributes appear in the generated OpenAPI document.
148165

149166
### Using String Shorthands
150167

@@ -187,15 +204,20 @@ Available shorthands:
187204
For more control, pass OpenAPI property objects directly. You can mix shorthands and full definitions:
188205

189206
```php
190-
public function schema(): array
207+
use BlueBeetle\ApiToolkit\Resources\Resource;
208+
209+
class ProductResource extends Resource
191210
{
192-
return [
193-
'name' => 'string',
194-
'description' => ['type' => 'string', 'nullable' => true],
195-
'status' => ['type' => 'string', 'enum' => ['active', 'inactive', 'draft']],
196-
'price' => ['type' => 'number', 'format' => 'float', 'minimum' => 0],
197-
'metadata' => ['type' => 'object', 'additionalProperties' => true],
198-
];
211+
public function schema(): array
212+
{
213+
return [
214+
'name' => 'string',
215+
'description' => ['type' => 'string', 'nullable' => true],
216+
'status' => ['type' => 'string', 'enum' => ['active', 'inactive', 'draft']],
217+
'price' => ['type' => 'number', 'format' => 'float', 'minimum' => 0],
218+
'metadata' => ['type' => 'object', 'additionalProperties' => true],
219+
];
220+
}
199221
}
200222
```
201223

docs/1.basics/2.responses.md

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,28 @@ class ProductController
7676
}
7777
```
7878

79+
### Merging Meta and Links
80+
81+
Calling `meta()` or `links()` multiple times merges the values rather than replacing them. This is useful when different parts of your code need to add their own metadata:
82+
83+
```php
84+
use App\Http\Resources\ProductResource;
85+
use App\Models\Product;
86+
use BlueBeetle\ApiToolkit\Http\Response;
87+
88+
class ProductController
89+
{
90+
public function show(Product $product, Response $response)
91+
{
92+
return $response->success($product, ProductResource::class)
93+
->meta(['request_id' => 'req_abc123'])
94+
->meta(['cache_hit' => false]) // merged with previous meta
95+
->links(['self' => route('api.products.show', $product)])
96+
->links(['related' => route('api.categories.show', $product->category_id)]); // merged
97+
}
98+
}
99+
```
100+
79101
### Custom Status Code and Headers
80102

81103
```php
@@ -177,16 +199,51 @@ Returns:
177199
### With Code and Source
178200

179201
```php
180-
return $response->error('Validation Failed', 'The name field is required.', 422)
181-
->code('VALIDATION_ERROR')
182-
->source(['pointer' => '/data/attributes/name']);
202+
use BlueBeetle\ApiToolkit\Http\Response;
203+
204+
class ProductController
205+
{
206+
public function update(string $id, Response $response)
207+
{
208+
return $response->error('Validation Failed', 'The name field is required.', 422)
209+
->code('VALIDATION_ERROR')
210+
->source(['pointer' => '/data/attributes/name']);
211+
}
212+
}
183213
```
184214

185215
### With Meta
186216

187217
```php
188-
return $response->error('Rate Limited', 'Too many requests.', 429)
189-
->meta(['retry_after' => 60]);
218+
use BlueBeetle\ApiToolkit\Http\Response;
219+
220+
class RateLimitedController
221+
{
222+
public function __invoke(Response $response)
223+
{
224+
return $response->error('Rate Limited', 'Too many requests.', 429)
225+
->meta(['retry_after' => 60]);
226+
}
227+
}
228+
```
229+
230+
### Chaining Code, Source, and Meta
231+
232+
All ErrorResponse methods are chainable, so you can combine them in a single expression:
233+
234+
```php
235+
use BlueBeetle\ApiToolkit\Http\Response;
236+
237+
class PaymentController
238+
{
239+
public function charge(Response $response)
240+
{
241+
return $response->error('Payment Failed', 'Card was declined.', 402)
242+
->code('CARD_DECLINED')
243+
->source(['pointer' => '/data/attributes/card_number'])
244+
->meta(['decline_code' => 'insufficient_funds', 'retry_allowed' => true]);
245+
}
246+
}
190247
```
191248

192249
## Using with QueryBuilder

docs/1.basics/3.query-builder.md

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Then in your controller, `fromResource()` picks up all of these automatically.
7474

7575
## Overriding Resource Configuration
7676

77-
Method calls take priority over resource definitions:
77+
Method calls on the QueryBuilder take priority over resource definitions. If you call `allowedFilters()`, `allowedSorts()`, `defaultSort()`, or `allowedIncludes()` on the builder, those values replace whatever the resource defines. This lets you reuse the same resource class across endpoints while customizing behavior per route.
7878

7979
```php
8080
use App\Http\Resources\ProductResource;
@@ -135,7 +135,9 @@ class ProductController
135135

136136
## Apply Without Fetching
137137

138-
Use `apply()` to apply filters, sorts, and includes without executing the query. This is useful when you need the modified query for something other than a standard response, like counting or exporting:
138+
Use `apply()` to apply filters, sorts, and includes without executing the query. This returns the QueryBuilder instance, so you can call `getQuery()` to access the underlying Eloquent builder. This is useful when you need the modified query for something other than a standard response.
139+
140+
### Counting Results
139141

140142
```php
141143
use App\Http\Resources\ProductResource;
@@ -157,3 +159,59 @@ class ProductController
157159
}
158160
}
159161
```
162+
163+
### Exporting to CSV
164+
165+
```php
166+
use App\Http\Resources\ProductResource;
167+
use App\Models\Product;
168+
use BlueBeetle\ApiToolkit\QueryBuilder;
169+
use Illuminate\Http\Request;
170+
171+
class ProductExportController
172+
{
173+
public function __invoke(Request $request)
174+
{
175+
$query = QueryBuilder::for(Product::class, $request)
176+
->fromResource(ProductResource::class)
177+
->apply()
178+
->getQuery();
179+
180+
return response()->streamDownload(function () use ($query) {
181+
$query->each(function ($product) {
182+
echo $product->name . ',' . $product->price . "\n";
183+
});
184+
}, 'products.csv');
185+
}
186+
}
187+
```
188+
189+
### Custom Response Format
190+
191+
```php
192+
use App\Http\Resources\ProductResource;
193+
use App\Models\Product;
194+
use BlueBeetle\ApiToolkit\QueryBuilder;
195+
use Illuminate\Http\Request;
196+
197+
class ProductStatsController
198+
{
199+
public function __invoke(Request $request)
200+
{
201+
$query = QueryBuilder::for(Product::class, $request)
202+
->fromResource(ProductResource::class)
203+
->apply()
204+
->getQuery();
205+
206+
return response()->json([
207+
'total' => $query->count(),
208+
'avg_price' => $query->avg('price'),
209+
'max_price' => $query->max('price'),
210+
]);
211+
}
212+
}
213+
```
214+
215+
## The getQuery() Method
216+
217+
`getQuery()` returns the underlying `Illuminate\Database\Eloquent\Builder` instance. You can call it at any time, but it is most useful after `apply()` so the builder already has all filters, sorts, and includes applied. The returned builder is a standard Eloquent builder, so you can chain any Eloquent method on it.

0 commit comments

Comments
 (0)