PHPackages                             ipunkt/laravel-json-api - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. ipunkt/laravel-json-api

AbandonedArchivedLibrary

ipunkt/laravel-json-api
=======================

JSON Api Package for Laravel

1.0.1(8y ago)415211MITPHPPHP &gt;=7.0

Since Apr 13Pushed 8y ago3 watchersCompare

[ Source](https://github.com/ipunkt/laravel-json-api)[ Packagist](https://packagist.org/packages/ipunkt/laravel-json-api)[ RSS](/packages/ipunkt-laravel-json-api/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (4)Dependencies (10)Versions (5)Used By (1)

JSON Api
========

[](#json-api)

JSON Api Package for Laravel

[![Latest Stable Version](https://camo.githubusercontent.com/44cac1742cb5c689b2746376a82176b4fc33f03fc499f2fd02cde1f1aa1976ab/68747470733a2f2f706f7365722e707567782e6f72672f6970756e6b742f6c61726176656c2d6a736f6e2d6170692f762f737461626c652e737667)](https://packagist.org/packages/ipunkt/laravel-json-api) [![Latest Unstable Version](https://camo.githubusercontent.com/ac476d485431010c92f1acd62cd9e6852c0ce7d668dd52b5e51ee2a2ff45c41c/68747470733a2f2f706f7365722e707567782e6f72672f6970756e6b742f6c61726176656c2d6a736f6e2d6170692f762f756e737461626c652e737667)](https://packagist.org/packages/ipunkt/laravel-json-api) [![License](https://camo.githubusercontent.com/635c2e6bfd043e225e1c8e9e0299ab3ef894c79e5c399f7f8e2219b35643bd75/68747470733a2f2f706f7365722e707567782e6f72672f6970756e6b742f6c61726176656c2d6a736f6e2d6170692f6c6963656e73652e737667)](https://packagist.org/packages/ipunkt/laravel-json-api) [![Total Downloads](https://camo.githubusercontent.com/54f20709ba9336aed9cf29afd8cc16b56a79c84e1be1b1b8379cdddd1841f49b/68747470733a2f2f706f7365722e707567782e6f72672f6970756e6b742f6c61726176656c2d6a736f6e2d6170692f646f776e6c6f6164732e737667)](https://packagist.org/packages/ipunkt/laravel-json-api)

Installation
------------

[](#installation)

```
composer require ipunkt/laravel-json-api
```

The package supports the package auto-discovery feature since laravel 5.5. For older laravel versions follow the instructions:

Add service provider to `config/app.php`:

```
'providers' => [
	\Ipunkt\LaravelJsonApi\LaravelJsonApiServiceProvider::class,
]
```

Add the following Facades to your `config/app.php` file:

```
'RelationshipFilterParser' => \Ipunkt\LaravelJsonApi\Services\RelationshipFilterParser\RelationshipFilterParserFacade::class,
'FilterApplier' => \Ipunkt\LaravelJsonApi\Services\FilterApplier\FilterApplierFacade::class,
```

### Middleware

[](#middleware)

We provide several middlewares `Ipunkt\LaravelJsonApi\Http\Middleware\ContentTypeGuard` and `Ipunkt\LaravelJsonApi\Http\Middleware\ETagMiddleware` and `Ipunkt\LaravelJsonApi\Http\Middleware\GetUserFromToken`.

First checks that `content-type` and `accept` header will have the correct value and exists. Second handles providing the correct `ETag` response header to support your cache infrastructure. Last one overrides the error response for the JWT Authentication middleware.

Set the necessary middleware in `app/Http/Kernel.php` in the `$routeMiddleware` section like this:

```
'jwt.auth' => \Ipunkt\LaravelJsonApi\Http\Middleware\GetUserFromToken::class,
'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,

'api-content-type' => \Ipunkt\LaravelJsonApi\Http\Middleware\ContentTypeGuard::class,
'etag' => \Ipunkt\LaravelJsonApi\Http\Middleware\ETagMiddleware::class,
```

Please follow the installation instructions documented [here](https://github.com/tymondesigns/jwt-auth/wiki/Installation) for the `tymon/auth` package.

For the api routes we need middleware groups named `api` and `secure-api`. These can be configured like this:

```
/**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
	'api' => [
		'api-content-type',
		'etag',
	],

	'secure-api' => [
		'api-content-type',
		'etag',
	],
];
```

Configuration
-------------

[](#configuration)

By default the package configures all routes itself. This is the suggested option.

You can configure the json api responses as well. There are optional response elements in the json api 1.0 standard. By default we return them all, but you can turn them off if you want to save response bytes.

Publish Configuration (optional step, but suggested):

```
php artisan vendor:publish --provider="Ipunkt\LaravelJsonApi\LaravelJsonApiServiceProvider"
```

### defaults section

[](#defaults-section)

#### max-limits

[](#max-limits)

How many results should be returned by default (no `page[limit]` query parameter set). We have `50` by default.

### routes section

[](#routes-section)

#### configure

[](#configure)

Do you want the routes being configured by the package itself? Leave it true in most cases.

#### public-route

[](#public-route)

We have public and secure routes by default in the package. Public routes do not check authentication. This is for authenticating an user or public accessible api endpoints.

Here you can configure the `prefix` for the route and the `controller` for handling requests.

#### secure-route

[](#secure-route)

Secure routes check authentication with each request. Here you need a JWT access token for accessing these resources.

Here you can configure the `prefix` for the route and the `controller` for handling requests. You have also the option to define `middleware`. A `jwt.auth` called middleware is configured by default.

### response section

[](#response-section)

#### resources

[](#resources)

Resources can have a links section. Shall the package add the self link automatically? It will be added by default, but it is not necessary in every case.

Resource items can have a self link too. This will be added automatically by the package by default. You can turn that off if you do not need it.

#### relationships

[](#relationships)

Relationships and the items itself can have a links section with the self and related link. These can all be added automatically by the package. You can turn that off, if you do not need it.

Definition
----------

[](#definition)

### Setup

[](#setup)

We suggest using the `app/Providers/AppServiceProvider` or create your own `ApiResourceServiceProvider`.

Customize your `boot` method to type hint the `\Ipunkt\LaravelJsonApi\Resources\ResourceManager` as parameter, like so:

```
public function boot(ResourceManager $resourceManager)
```

### Define a resource

[](#define-a-resource)

The `JsonApiController` handles the incoming api request. It uses the `ResourceManager` to get to know all defined resources. So define your resources like so:

```
//  define in api version 1 a resource called 'posts'
$resourceManager->version(1)
    ->define('posts', function (ResourceDefinition $resource) {
        $resource->setRepository(PostRepository::class)
            ->setSerializer(PostSerializer::class);
    });
```

Each Api has various versions, 1 at minimum.

For each version you can define resources (URL `/public/v1/posts`) and as a callback you can define various types: at least a repository for fetching the resource models and a serializer to transform the fetched model data into your wanted format.

Additionally you can define a custom request handler. There you can process the whole request yourself until returning the response. So you have full control.

The Json Api Standard has various filter options. We have a Filter Factory to support this kind of layer. A Filter Factory handles the given filter and sets it to the repository by default. So you can filter by attribute or search within a time period through request parameters. If you want to use filter you have to define a filter factory. Otherwise your filters will not be applied.

If you want to use a secure api route, you have to setup a request handler as well:

```
//  define in api version 1 a resource called 'posts'
$resourceManager->version(1)
    ->define('posts', function (ResourceDefinition $resource) {
        $resource->setRepository(PostRepository::class)
            ->setSerializer(PostSerializer::class)
            ->setRequestHandler(PostRequestHandler::class);
    });
```

### Implement a Serializer

[](#implement-a-serializer)

```
class PostSerializer extends \Ipunkt\LaravelJsonApi\Serializers\Serializer
{
	/**
	 * resource type in response, can differ from requesting resource name
	 * @var string
	 */
	protected $type = 'posts';

	/**
     * returns links
     *
     * @param Model|Post $model
     * @return array
     */
    public function getLinks($model) : array
    {
        return [
            'comments' => 'https://localhost/api/v1/posts/1/comments',
        ];
    }

    /**
     * returns attributes for model
     *
     * @param Model|Post $model
     * @return array
     */
    protected function attributes($model) : array
    {
        return [
            'title' => $model->title,
            'slug' => str_slug($model->title),
            'content' => $model->content,
            'excerpt' => substr($model->content, 0, 200),
            'words' => count(explode(' ', $model->content)), //  example to show you can return more than only concrete model attributes
        ];
    }
}
```

### Implement a Repository

[](#implement-a-repository)

Follows the repository pattern and stores default sort criteria and a mapping for parameter request to database field name.

```
class PostRepository extends \Ipunkt\LaravelJsonApi\Repositories\Repository
{
	/**
     * default sort criteria, when nothing given (can be empty)
     *
     * Format: 'fieldName' => 'asc', // or 'desc'
     *
     * @var array
     */
    protected $defaultSortCriterias = [
        'publish_datetime' => 'desc'
    ];

    /**
     * sort criterias (can be empty)
     *
     * Format: 'attributeNameInRequest' => 'field_name_in_database'
     * Example: 'date' in request will be 'publish_datetime' in sql query
     *
     * @var array
     */
    protected $sortCriterias = [
        'date' => 'publish_datetime',
    ];

    /**
     * constructor.
     * @param Model|Post $post
     * @param \Ipunkt\LaravelJsonApi\Repositories\Conditions\ConditionApplier $conditionApplier
     */
    public function __construct(Post $post, \Ipunkt\LaravelJsonApi\Repositories\Conditions\ConditionApplier $conditionApplier)
    {
        $this->model = $post;
        $this->conditionApplier = $conditionApplier;
    }
}
```

### Implement a Request Handler

[](#implement-a-request-handler)

We provide a request handler for handling retrieval requests (GET): `DefaultRequestHandler`.

The `\Ipunkt\LaravelJsonApi\Contracts\RequestHandlers\NeedsAuthenticatedUser` interface controls that your resource can be accessed via the secure route. Without you have to use the public route.

```
class PostRequestHandler extends \Ipunkt\LaravelJsonApi\Http\RequestHandlers\DefaultRequestHandler implements NeedsAuthenticatedUser
{

}
```

If you need more freedom then create a request handler yourself and inherit from `Ipunkt\LaravelJsonApi\Http\RequestHandlers\RequestHandler`. The whole configured actions will be provided by various interfaces in the namespace `Ipunkt\LaravelJsonApi\Contracts\RequestHandlers`: `HandlesCollectionRequest`, `HandlesItemRequest`, `HandlesRelationshipCollectionRequest`, `HandlesRelationshipItemRequest` and the modifiable interfaces `HandlesPostRequest`, `HandlesPatchRequest`, `HandlesDeleteRequest` and the relationship interfaces as well. Take a look yourself.

You can simplify the data modification requests by using one of the delivered traits within your own request handler. The traits can be found under `Ipunkt\LaravelJsonApi\Http\RequestHandlers\Traits`. Take a look yourself.

Error Handling in Laravel
-------------------------

[](#error-handling-in-laravel)

Simply extend your `app/Exceptions/Handler.php` in the following way:

Method `render()` should extend with this code:

```
if ($request->expectsJson() ||
	$request->headers->contains('accept', ApiRequestHandler::CONTENT_TYPE)) {
	$error = new JsonApiError($exception->getMessage());

	if ($exception->getCode() > 100) {
		$error->setCode($exception->getCode());
	}

	if ($exception instanceof ModelNotFoundException || $exception instanceof NotFoundHttpException) {
		$error->setStatusCode(404)
			->setTitle('Resource not found');
	}

	if ($exception instanceof AuthorizationException) {
		$error->setStatusCode(403)
			->setTitle('Access forbidden');
	}

	if ($exception instanceof ValidationException) {
		$validationErrors = collect();
		foreach ($exception->validator->errors()->keys() as $key) {
			$validationErrors->push([
				'pointer' => $key,
				'message' => str_replace('attributes.', '', $exception->validator->errors()->first($key)),
			]);
		}
		$error->setSource($validationErrors);
	}

	if ($exception instanceof HttpExceptionInterface) {
		$error->setStatusCode($exception->getStatusCode());
	}

	if (app()->environment('local')) {
		$error->setException($exception);
	}

	return response()->json(['errors' => [$error]], $error->getStatusCode());
}
```

Extend your special exceptions to match the correct code and status code. Code means the Exception code and status code is the http status response code.

Method `unauthenticated()` should extend with this code:

```
if ($request->expectsJson() ||
	$request->headers->contains('accept', ApiRequestHandler::CONTENT_TYPE)) {
	$error = new JsonApiError('Unauthenticated');
	$error->setStatusCode(401);

	return response()->json(['errors' => [$error]], $error->getStatusCode());
}
```

Test
----

[](#test)

We provide a trait for adding functionality for json api testing in the `tests/TestCase.php`: `\Ipunkt\LaravelJsonApi\Testing\ApiTestCaseTrait`.

This TestCase trait is optimized for testing with Laravel 5.3 or Laravel 5.4 BrowserKitTest.

### Laravel 5.4

[](#laravel-54)

Since Laravel 5.4 has a lot of convenient methods for requesting and asserting you only need the `Ipunkt\LaravelJsonApi\Testing\Concerns\PreparesRequestBody` trait. Simply add it to your `Tests\TestCase` use statements.

The `PreparesRequestBody` provides model to request body transformation methods.

If you want to provide some kind of login or secure api, then you have to add `Ipunkt\LaravelJsonApi\Testing\Concerns\ModifiesRequestHeaders` to your `Tests\TestCase` or wherever you want to store a token. This trait provides token storing and a `->headers()` method to overwrite the headers with the bearer token.

#### Example User Login

[](#example-user-login)

If you want to create a user login to test a secure api route you can do it like this:

```
namespace Tests;

use App\User;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Ipunkt\LaravelJsonApi\Testing\Concerns\ModifiesRequestHeaders;
use Ipunkt\LaravelJsonApi\Testing\Concerns\PreparesRequestBody;

abstract class TestCase extends BaseTestCase
{
	use PreparesRequestBody,
		ModifiesRequestHeaders;
	use CreatesApplication;

	/**
	 * creates a user and logs him in
	 *
	 * @return User
	 */
	protected function createUserAndLogin(): User
	{
		$user = factory(\App\User::class)->create();

		$response = $this->postJson('/public/v1/tokens', $this->createRequestModel('credentials', [
			'email' => $user->email,
			'password' => 'secret',
		]), $this->headers());

		$json = $response->decodeResponseJson();
		$token = array_get($json, 'data.id');

		$this->setToken($token); // you are loggedin

		// you can now overwrite all requests headers with calling $this->headers().

		return $user;
	}
}
```

This code creates a new user within the database, fetches a token (stored in response `data.id`) and sets it to a static variable. Afterwards you can use the `$this->headers()` method for every request to overwrite the necessary headers.

###  Health Score

29

—

LowBetter than 60% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity15

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity61

Established project with proven stability

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~48 days

Total

4

Last Release

3166d ago

Major Versions

0.0.2 → 1.0.02017-08-28

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/4946056?v=4)[Robert Kummer](/maintainers/rokde)[@rokde](https://github.com/rokde)

---

Tags

json-apilaravellaravel-package

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/ipunkt-laravel-json-api/health.svg)

```
[![Health](https://phpackages.com/badges/ipunkt-laravel-json-api/health.svg)](https://phpackages.com/packages/ipunkt-laravel-json-api)
```

###  Alternatives

[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k43.5M5.1k](/packages/larastan-larastan)[laravel/passport

Laravel Passport provides OAuth2 server support to Laravel.

3.4k85.0M529](/packages/laravel-passport)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.5k25.9M106](/packages/laravel-cashier)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[psalm/plugin-laravel

Psalm plugin for Laravel

3274.9M308](/packages/psalm-plugin-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
