Giter Club home page Giter Club logo

laravel-responder's Introduction

Latest Stable Version Packagist Downloads Software License Build Status Code Quality Test Coverage Donate

Laravel Responder is a package for building API responses, integrating Fractal into Laravel and Lumen. It can transform your data using transformers, create and serialize success- and error responses, handle exceptions and assist you with testing your responses.

Table of Contents

Introduction

Laravel lets you return models directly from a controller method to convert it to JSON. This is a quick way to build APIs but leaves your database columns exposed. Fractal, a popular PHP package from The PHP League, solves this by introducing transformers. However, it can be a bit cumbersome to integrate into the framework as seen below:

 public function index()
 {
    $resource = new Collection(User::all(), new UserTransformer());

    return response()->json((new Manager)->createData($resource)->toArray());
 }

Not that bad, but we all get a little spoiled by Laravel's magic. Wouldn't it be better if we could refactor it to:

public function index()
{
    return responder()->success(User::all())->respond();
}

The package will allow you to do this and much more. The goal has been to create a high-quality package that feels like native Laravel. A package that lets you embrace the power of Fractal, while hiding it behind beautiful abstractions. There has also been put a lot of focus and thought to the documentation. Happy exploration!

Requirements

This package requires:

  • PHP 7.0+
  • Laravel 5.1+ or Lumen 5.1+

Installation

To get started, install the package through Composer:

composer require flugger/laravel-responder

Laravel

Register Service Provider

Append the following line to the providers key in config/app.php to register the package:

Flugg\Responder\ResponderServiceProvider::class,

The package supports auto-discovery, so if you use Laravel 5.5 or later you may skip registering the service provider and facades as they will be registered automatically.


Register Facades (optional)

If you like facades, you may also append the Responder and Transformation facades to the aliases key:

'Responder' => Flugg\Responder\Facades\Responder::class,
'Transformation' => Flugg\Responder\Facades\Transformation::class,

Publish Package Assets (optional)

You may additionally publish the package configuration and language file using the vendor:publish Artisan command:

php artisan vendor:publish --provider="Flugg\Responder\ResponderServiceProvider"

This will publish a responder.php configuration file in your config folder. It will also publish an errors.php file inside your lang/en folder which can be used for storing error messages.

Lumen

Register Service Provider

Add the following line to app/bootstrap.php to register the package:

$app->register(Flugg\Responder\ResponderServiceProvider::class);

Register Facades (optional)

You may also add the following lines to app/bootstrap.php to register the facades:

class_alias(Flugg\Responder\Facades\Responder::class, 'Responder');
class_alias(Flugg\Responder\Facades\Transformation::class, 'Transformation');

Publish Package Assets (optional)

Seeing there is no vendor:publish command in Lumen, you will have to create your own config/responder.php file if you want to configure the package.

Usage

This documentation assumes some knowledge of how Fractal works.

Creating Responses

The package has a Responder service class, which has a success and error method to build success- and error responses respectively. To use the service and begin creating responses, pick one of the options below:

Option 1: Inject Responder Service

You may inject the Flugg\Responder\Responder service class directly into your controller methods:

public function index(Responder $responder)
{
    return $responder->success();
}

You can also use the error method to create error responses:

return $responder->error();

Option 2: Use responder Helper

If you're a fan of Laravel's response helper function, you may like the responder helper function:

return responder()->success();
return responder()->error();

Option 3: Use Responder Facade

Optionally, you may use the Responder facade to create responses:

return Responder::success();
return Responder::error();

Option 4: Use MakesResponses Trait

Lastly, the package provides a Flugg\Responder\Http\MakesResponses trait you can use in your controllers:

return $this->success();
return $this->error();

Which option you pick is up to you, they are all equivalent, the important thing is to stay consistent. The helper function (option 2) will be used for the remaining of the documentation.


Building Responses

The success and error methods return a SuccessResponseBuilder and ErrorResponseBuilder respectively, which both extend an abstract ResponseBuilder, giving them common behaviors. They will be converted to JSON when returned from a controller, but you can explicitly create an instance of Illuminate\Http\JsonResponse with the respond method:

return responder()->success()->respond();
return responder()->error()->respond();

The status code is set to 200 by default, but can be changed by setting the first parameter. You can also pass a list of headers as the second argument:

return responder()->success()->respond(201, ['x-foo' => true]);
return responder()->error()->respond(404, ['x-foo' => false]);

Consider always using the respond method for consistency's sake.


Casting Response Data

Instead of converting the response to a JsonResponse using the respond method, you can cast the response data to a few other types, like an array:

return responder()->success()->toArray();
return responder()->error()->toArray();

You also have a toCollection and toJson method at your disposal.

Decorating Response

A response decorator allows for last minute changes to the response before it's returned. The package comes with two response decorators out of the box adding a status and success field to the response output. The decorators key in the configuration file defines a list of all enabled response decorators:

'decorators' => [
    \Flugg\Responder\Http\Responses\Decorators\StatusCodeDecorator::class,
    \Flugg\Responder\Http\Responses\Decorators\SuccessFlagDecorator::class,
],

You may disable a decorator by removing it from the list, or add your own decorator extending the abstract class Flugg\Responder\Http\Responses\Decorators\ResponseDecorator. You can also add additional decorators per response:

return responder()->success()->decorator(ExampleDecorator::class)->respond();
return responder()->error()->decorator(ExampleDecorator::class)->respond();

The package also ships with some situational decorators disabled by default, but which can be added to the decorator list:

  • PrettyPrintDecorator decorator will beautify the JSON output;
\Flugg\Responder\Http\Responses\Decorators\PrettyPrintDecorator::class,
  • EscapeHtmlDecorator decorator, based on the "sanitize input, escape output" concept, will escape HTML entities in all strings returned by your API. You can securely store input data "as is" (even malicious HTML tags) being sure that it will be outputted as un-harmful strings. Note that, using this decorator, printing data as text will result in the wrong representation and you must print it as HTML to retrieve the original value.
\Flugg\Responder\Http\Responses\Decorators\EscapeHtmlDecorator::class,

Creating Success Responses

As briefly demonstrated above, success responses are created using the success method:

return responder()->success()->respond();

Assuming no changes have been made to the configuration, the above code would output the following JSON:

{
    "status": 200,
    "success": true,
    "data": null
}

Setting Response Data

The success method takes the response data as the first argument:

return responder()->success(Product::all())->respond();

It accepts the same data types as you would normally return from your controllers, however, it also supports query builder and relationship instances:

return responder()->success(Product::where('id', 1))->respond();
return responder()->success(Product::first()->shipments())->respond();

The package will run the queries and convert them to collections behind the scenes.


Transforming Response Data

The response data will be transformed with Fractal if you've attached a transformer to the response. There are two ways to attach a transformer; either explicitly by setting it on the response, or implicitly by binding it to a model. Let's look at both ways in greater detail.

Setting Transformer On Response

You can attach a transformer to the response by sending a second argument to the success method. For instance, below we're attaching a simple closure transformer, transforming a list of products to only output their names:

return responder()->success(Product::all(), function ($product) {
    return ['name' => $product->name];
})->respond();

You may also transform using a dedicated transformer class:

return responder()->success(Product::all(), ProductTransformer::class)->respond();
return responder()->success(Product::all(), new ProductTransformer)->respond();

You can read more about creating dedicated transformer classes in the Creating Transformers chapter.


Binding Transformer To Model

If no transformer is set, the package will search the response data for an element implementing the Flugg\Responder\Contracts\Transformable interface to resolve a transformer from. You can take use of this by implementing the Transformable interface in your models:

class Product extends Model implements Transformable {}

You can satisfy the contract by adding a transformer method that returns the corresponding transformer:

/**
 * Get a transformer for the class.
 *
 * @return \Flugg\Responder\Transformers\Transformer|string|callable
 */
public function transformer()
{
    return ProductTransformer::class;
}

You're not limited to returning a class name string, you can return a transformer instance or closure transformer, just like the second parameter of the success method.


Instead of implementing the Transformable contract for all models, an alternative approach is to bind the transformers using the bind method on the TransformerResolver class. You can place the code below within AppServiceProvider or an entirely new TransformerServiceProvider:

use Flugg\Responder\Contracts\Transformers\TransformerResolver;

public function boot()
{
    $this->app->make(TransformerResolver::class)->bind([
        \App\Product::class => \App\Transformers\ProductTransformer::class,
        \App\Shipment::class => \App\Transformers\ShipmentTransformer::class,
    ]);
}

After you've bound a transformer to a model you can skip the second parameter and still transform the data:

return responder()->success(Product::all())->respond();

As you might have noticed, unlike Fractal, you don't need to worry about creating resource objects like Item and Collection. The package will make one for you based on the data type, however, you may wrap your data in a resource object to override this.


Setting Resource Key

If the data you send into the response is a model or contains a list of models, a resource key will implicitly be resolved from the model's table name. You can overwrite this by adding a getResourceKey method to your model:

public function getResourceKey(): string {
    return 'products';
}

You can also explicitly set a resource key on a response by sending a third argument to the ยดsuccess` method:

return responder()->success(Product::all(), ProductTransformer::class, 'products')->respond();

Paginating Response Data

Sending a paginator to the success method will set pagination meta data and transform the data automatically, as well as append any query string parameters to the paginator links.

return responder()->success(Product::paginate())->respond();

Assuming there are no products and the default configuration is used, the JSON output would look like:

{
    "success": true,
    "status": 200,
    "data": [],
    "pagination": {
        "total": 0,
        "count": 0,
        "perPage": 15,
        "currentPage": 1,
        "totalPages": 1,
        "links": []
    }
}

Setting Paginator On Response

Instead of sending a paginator as data, you may set the data and paginator seperately, like you traditionally would with Fractal. You can manually set a paginator using the paginator method, which expects an instance of League\Fractal\Pagination\IlluminatePaginatorAdapter:

$paginator = Product::paginate();
$adapter = new IlluminatePaginatorAdapter($paginator);

return responder()->success($paginator->getCollection())->paginator($adapter)->respond();

Setting Cursor On Response

You can also set cursors using the cursor method, expecting an instance of League\Fractal\Pagination\Cursor:

if ($request->has('cursor')) {
    $products = Product::where('id', '>', request()->cursor)->take(request()->limit)->get();
} else {
    $products = Product::take(request()->limit)->get();
}

$cursor = new Cursor(request()->cursor, request()->previous, $products->last()->id ?? null, Product::count());

return responder()->success($products)->cursor($cursor)->respond();

Including Relationships

If a transformer class is attached to the response, you can include relationships using the with method:

return responder()->success(Product::all())->with('shipments')->respond();

You can send multiple arguments and specify nested relations using dot notation:

return responder()->success(Product::all())->with('shipments', 'orders.customer')->respond();

All relationships will be automatically eager loaded, and just like you would when using with or load to eager load with Eloquent, you may use a callback to specify additional query constraints. Like in the example below, where we're only including related shipments that hasn't yet been shipped:

return responder()->success(Product::all())->with(['shipments' => function ($query) {
    $query->whereNull('shipped_at');
}])->respond();

Including From Query String

Relationships are loaded from a query string parameter if the load_relations_parameter configuration key is set to a string. By default, it's set to with, allowing you to automatically include relations from the query string:

GET /products?with=shipments,orders.customer

Excluding Default Relations

In your transformer classes, you may specify relations to automatically load. You may disable any of these relations using the without method:

return responder()->success(Product::all())->without('comments')->respond();

Filtering Transformed Data

The technique of filtering the transformed data to only return what we need is called sparse fieldsets and can be specified using the only method:

return responder()->success(Product::all())->only('id', 'name')->respond();

When including relationships, you may also want to filter fields on related resources as well. This can be done by instead specifying an array where each key represents the resource keys for the resources being filtered

return responder()->success(Product::all())->with('shipments')->only([
    'products' => ['id', 'name'],
    'shipments' => ['id']
])->respond();

Filtering From Query String

Fields will automatically be filtered if the filter_fields_parameter configuration key is set to a string. It defaults to only, allowing you to filter fields from the query string:

GET /products?only=id,name

You may automatically filter related resources by setting the parameter to a key-based array:

GET /products?with=shipments&only[products]=id,name&only[shipments]=id

Adding Meta Data

You may want to attach additional meta data to your response. You can do this using the meta method:

return responder()->success(Product::all())->meta(['count' => Product::count()])->respond();

When using the default serializer, the meta data will simply be appended to the response array:

{
    "success": true,
    "status": 200,
    "data": [],
    "count": 0
}

Serializing Response Data

After the data has been transformed, it will be serialized using the specified success serializer in the configuration file, which defaults to the package's own Flugg\Responder\Serializers\SuccessSerializer. You can overwrite this on your responses using the serializer method:

return responder()->success()->serializer(JsonApiSerializer::class)->respond();
return responder()->success()->serializer(new JsonApiSerializer())->respond();

Above we're using Fractal's JsonApiSerializer class. Fractal also ships with an ArraySerializer and DataArraySerializer class. If none of these suit your taste, feel free to create your own serializer by extending League\Fractal\Serializer\SerializerAbstract. You can read more about it in Fractal's documentation.

Creating Transformers

A dedicated transformer class gives you a convenient location to transform data and allows you to reuse the transformer at multiple places. It also allows you to include and transform relationships. You can create a transformer using the make:transformer Artisan command:

php artisan make:transformer ProductTransformer

The command will generate a new ProductTransformer.php file in the app/Transformers folder:

<?php

namespace App\Transformers;

use App\User;
use Flugg\Responder\Transformers\Transformer;

class ProductTransformer extends Transformer
{
    /**
     * List of available relations.
     *
     * @var string[]
     */
    protected $relations = [];

    /**
     * A list of autoloaded default relations.
     *
     * @var array
     */
    protected $load = [];

    /**
     * Transform the model.
     *
     * @param  \App\Product $product
     * @return array
     */
    public function transform(Product $product): array
    {
        return [
            'id' => (int) $product->id,
        ];
    }
}

It will automatically resolve a model name from the name provided. For instance, the package will extract Product from ProductTransformer and assume the models live directly in the app folder (as per Laravel's convention). If you store them somewhere else, you can use the --model (or -m) option to override it:

php artisan make:transformer ProductTransformer --model="App\Models\Product"

Creating Plain Transformers

The transformer file generated above is a model transformer expecting an App\Product model for the transform method. However, we can create a plain transformer by applying the --plain (or -p) modifier:

php artisan make:transformer ProductTransformer --plain

This will remove the typehint from the transform method and add less boilerplate code.

Setting Relationships

The $relations and $load properties in the transformer are the equivalent to Fractal's own $availableIncludes and $defaultIncludes. In addition to the slight name change, the package uses the $relations and $load properties to map out all available relationships for eager loading, so in contrast to Fractal, you should map the relationship to their corresponding transformer:

protected $relations = [
    'shipments' => ShipmentTransformer::class,
];

You can choose to skip the mapping and just pass the strings like with Fractal, but that means the package wont be able to eager load relationships automatically.


Setting Whitelisted Relationships

The $relations property specifies a list of relations available to be included. You can set a list of relations mapped to their corresponding transformers:

protected $relations = [
    'shipments' => ShipmentTransformer::class,
    'orders' => OrderTransformer::class,
];

Setting Autoloaded Relationships

The $load property specifies a list of relations to be autoloaded every time you transform data with the transformer:

protected $load = [
    'shipments' => ShipmentTransformer::class,
    'orders' => OrderTransformer::class,
];

You don't have to add relations to both $relations and $load, all relations in $load will be available by nature.


Including Relationships

While Fractal requires you to to create a method in your transformer for every included relation, this package lets you skip this when transforming models, as it will automatically fetch relationships from the model. You may of course override this functionality by creating an "include" method:

/**
 * Include related shipments.
 *
 * @param  \App\Product $product
 * @return mixed
 */
public function includeShipments(Product $product)
{
    return $product->shipments;
}

Unlike Fractal you can just return the data directly without wrapping it in an item or collection method.


You should be careful with executing database calls inside the include methods as you might end up with an unexpected amount of hits to the database.


Using Include Parameters

Fractal can parse query string parameters which can be used when including relations. For more information about how to format the parameters see Fractal's documentation on parameters. You may access the parameters by adding a second parameter to the "include" method:

public function includeShipments(Product $product, Collection $parameters)
{
    return $product->shipments->take($parameters->get('limit'));
}

To be as decoupled from Fractal as possible the parameters (which are normally accessed using League\Fractal\ParamBag) are accessed as Laravel collections instead.


Adding Query Constraints

Just as you can specify a query constraint when including a relationship with the with method, you can also add query constraints as a "load" method on the transformer. This will automatically be applied when extracting relationships for eager loading.

/**
 * Load shipments with constraints.
 *
 * @param  \Illuminate\Database\Eloquent\Builder $query
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function loadShipments($query)
{
    return $query->whereNull('shipped_at');
}

Note: You cannot mix "include" and "load" methods because the package doesn't eager load relationships included with an "include" method.


Filtering Relationships

After a relation has been included, you can make any last second changes to it using a filter method. For instance, below we're filtering the list of related shipments to only include shipments that has not been shipped:

/**
 * Filter included shipments.
 *
 * @param  \Illuminate\Database\Eloquent\Collection $shipments
 * @return \Illuminate\Support\Collection
 */
public function filterShipments($shipments)
{
    return $shipments->filter(function ($shipment) {
        return is_null($shipment->shipped_at);
    });
}

Transforming Data

We've looked at how to transform response data of success responses, however, there may be other places than your controllers where you want to transform data. An example is broadcasted events where you're exposing data using websockets instead of HTTP. You just want to return the transformed data, not an entire response.

It's possible to simply transform data by newing up the transformer and calling transform:

return (new ProductTransformer)->transform(Product::first());

However, this approach might become a bit messy when building transformations with relationships:

return array_merge((new ProductTransformer)->transform($product = Product::first()), [
    'shipments' => $product->shipments->map(function ($shipment) {
        return (new ShipmentTransformer)->transform($shipment);
    })
]);

Yuck! Imagine that with multiple nested relationships. Let's explore a simpler way to handle this.

Building Transformations

The SuccessResponseBuilder actually delegates all of the transformation work to a dedicated Flugg\Responder\TransformBuilder class. We can use this class ourself to transform data. For instance, if the product and shipment transformers were bound to the models, we could replicate the code above in the following way:

public function index(TransformBuilder $transformation)
{
    return $transformation->resource(Product::all())->with('shipments')->transform();
}

Instead of using the success method on the Responder service, we use the resource method on the TransformBuilder with the same method signature. We also use transform to execute the transformation instead of respond as we did when creating responses. In addition to the with method, you also have access to the other transformation methods like without, only, meta and serializer.


Using toArray on the Responder service is almost the same as the code above, however, it will also include response decorators which might not be desired.


Transforming Without Serializing

When using the TransformBuilder to transform data it will still serialize the data using the configured serializer. Fractal requires the use of a serializer to transform data, but sometimes we're just interested in the raw transformed data. The package ships with a Flugg\Responder\Serializers\NoopSerializer to solve this, a no-op serializer which leaves the transformed data untouched:

return $transformation->resource(Product::all())->serializer(NoopSerializer::class)->transform();

If you think this is looking messy, don't worry, there's a quicker way. In fact, you will probably never even need to utilize the NoopSerializer or TransformBuilder manually, but it helps to know how it works. The Flugg\Responder\Transformation is a class which can be used for quickly transforming data without serializing.

Option 1: The Transformation Service

The Transformation class utilizes the TransformBuilder class to build a transformation using the NoopSerializer. You can inject the Transformation class and call make to obtain an instance of TransformBuilder which gives you access to all of the chainable methods including with, like below:

public function __construct(Transformation $transformation)
{
    $transformation->make(Product::all())->with('shipments')->transform();
}

Option 2: The transformation Helper

You can use the transformation helper function to transform data without serializing:

transformation(Product::all())->with('shipments')->transform();

Option 3: The Transformation Facade

You can also use the Transformation facade to achieve the same thing:

Transformation::make(Product::all())->with('shipments')->transform();

Transforming To Camel Case

Model attributes are traditionally specified in snake case, however, you might prefer to use camel case for the response fields. A transformer makes for a perfect location to convert the fields, as seen from the soldOut field in the example below:

return responder()->success(Product::all(), function ($product) {
    return ['soldOut' => (bool) $product->sold_out];    
})->respond();

Transforming Request Parameters

After responding with camel case, you probably want to let people send in request data using camel cased parameters as well. The package provides a Flugg\Responder\Http\Middleware\ConvertToSnakeCase middleware you can append to the $middleware array in app/Http/Kernel.php to convert all parameters to snake case automatically:

protected $middleware = [
    // ...
    \Flugg\Responder\Http\Middleware\ConvertToSnakeCase::class,
];

The middleware will run before request validation, so you should specify your validation rules in snake case as well.


Creating Error Responses

Whenever a consumer of your API does something unexpected, you can return an error response describing the problem. As briefly shown in a previous chapter, an error response can be created using the error method:

return responder()->error()->respond();

The error response has knowledge about an error code, a corresponding error message and optionally some error data. With the default configuration, the above code would output the following JSON:

{
    "success": false,
    "status": 500,
    "error": {
        "code": null,
        "message": null
    }
}

Setting Error Code & Message

You can fill the first parameter of the error method to set an error code:

return responder()->error('sold_out_error')->respond();

You may optionally use integers for error codes.


In addition, you may set the second parameter to an error message describing the error:

return responder()->error('sold_out_error', 'The requested product is sold out.')->respond();

Set Messages In Language Files

You can set the error messages in a language file, which allows for returning messages in different languages. The configuration file has an error_message_files key defining a list of language files with error messages. By default, it is set to ['errors'], meaning it will look for an errors.php file inside resources/lang/en. You can use these files to map error codes to corresponding error messages:

return [
    'sold_out_error' => 'The requested product is sold out.',
];

Register Messages Using ErrorMessageResolver

Instead of using language files, you may alternatively set error messages directly on the ErrorMessageResolver class. You can place the code below within AppServiceProvider or an entirely new TransformerServiceProvider:

use Flugg\Responder\ErrorMessageResolver;

public function boot()
{
    $this->app->make(ErrorMessageResolver::class)->register([
        'sold_out_error' => 'The requested product is sold out.',
    ]);
}

Adding Error Data

You may want to set additional data on the error response. Like in the example below, we're returning a list of shipments with the sold_out error response, giving the consumer information about when a new shipment for the product might arrive.

return responder()->error('sold_out')->data(['shipments' => Shipment::all()])->respond();

The error data will be appended to the response data. Assuming we're using the default serializer and there are no shipments in the database, the code above would look like:

{
    "success": false,
    "status": 500,
    "error": {
        "code": "sold_out",
        "message": "The requested product is sold out.",
        "shipments": []
    }
}

Serializing Response Data

Similarly to success responses, error responses will be serialized using the specified error serializer in the configuration file. This defaults to the package's own Flugg\Responder\Serializers\ErrorSerializer, but can of course be changed by using the serializer method:

return responder()->error()->serializer(ExampleErrorSerializer::class)->respond();
return responder()->success()->serializer(new ExampleErrorSerializer())->respond();

You can create your own error serializer by implementing the Flugg\Responder\Contracts\ErrorSerializer contract.

Handling Exceptions

No matter how much we try to avoid them, exceptions do happen. Responding to the exceptions in an elegant manner will improve the user experience of your API. The package can enhance your exception handler to automatically turn exceptions in to error responses. If you want to take use of this, you can either use the package's exception handler or include a trait as described in further details below.

Option 1: Replace Handler Class

To use the package's exception handler you need to replace the default import in app/Exceptions/Handler.php:

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

With the package's handler class:

use Flugg\Responder\Exceptions\Handler as ExceptionHandler;

This will not work with Lumen as its exception handler is incompatible with Laravel's. Look instead at the second option below.


Option 2: Use ConvertsExceptions Trait

The package's exception handler uses the Flugg\Responder\Exceptions\ConvertsExceptions trait to load of most of its work. Instead of replacing the exception handler, you can use the trait in your own handler class. To replicate the behavior of the exception handler, you would also have to add the following code to the render method:

public function render($request, Exception $exception)
{
    $this->convertDefaultException($exception);

    if ($exception instanceof HttpException) {
        return $this->renderResponse($exception);
    }

    return parent::render($request, $exception);
}

If you only want to return JSON error responses on requests actually asking for JSON, you may wrap the code above in a wantsJson check as seen below:

if ($request->wantsJson()) {
    $this->convertDefaultException($exception);

    if ($exception instanceof HttpException) {
        return $this->renderResponse($exception);
    }
}

Converting Exceptions

Once you've implemented one of the above options, the package will convert some of Laravel's exceptions to an exception extending Flugg\Responder\Exceptions\Http\HttpException. It will then convert these to an error response. The table below shows which Laravel exceptions are converted and what they are converted to. All the exceptions on the right is under the Flugg\Responder\Exceptions\Http namespace and extends Flugg\Responder\Exceptions\Http\HttpException. All exceptions extending the HttpException class will be automatically converted to an error response.

Caught Exceptions Converted To
Illuminate\Auth\AuthenticationException UnauthenticatedException
Illuminate\Auth\Access\AuthorizationException UnauthorizedException
Symfony\Component\HttpKernel\Exception\NotFoundHttpException PageNotFoundException
Illuminate\Database\Eloquent\ModelNotFoundException PageNotFoundException
Illuminate\Database\Eloquent\RelationNotFoundException RelationNotFoundException
Illuminate\Validation\ValidationException ValidationFailedException

You can disable the conversions of some of the exceptions above using the $dontConvert property:

/**
 * A list of default exception types that should not be converted.
 *
 * @var array
 */
protected $dontConvert = [
    ModelNotFoundException::class,
];

If you're using the trait option, you can disable all the default conversions by removing the call to convertDefaultException in the render method.


Convert Custom Exceptions

In addition to letting the package convert Laravel exceptions, you can also convert your own exceptions using the convert method in the render method:

$this->convert($exception, [
    InvalidValueException => PageNotFoundException,
]);

You can optionally give it a closure that throws the new exception, if you want to give it constructor parameters:

$this->convert($exception, [
    MaintenanceModeException => function ($exception) {
        throw new ServerDownException($exception->retryAfter);
    },
]);

Creating HTTP Exceptions

An exception class is a convenient place to store information about an error. The package provides an abstract exception class Flugg\Responder\Exceptions\Http\HttpException, which has knowledge about status code, an error code and an error message. Continuing on our product example from above, we could create our own HttpException class:

<?php

namespace App\Exceptions;

use Flugg\Responder\Exceptions\Http\HttpException;

class SoldOutException extends HttpException
{
    /**
     * The HTTP status code.
     *
     * @var int
     */
    protected $status = 400;

    /**
     * The error code.
     *
     * @var string|null
     */
    protected $errorCode = 'sold_out_error';

    /**
     * The error message.
     *
     * @var string|null
     */
    protected $message = 'The requested product is sold out.';
}

You can also add a data method returning additional error data:

/**
 * Retrieve additional error data.
 *
 * @return array|null
 */
public function data()
{
    return [
        'shipments' => Shipment::all()
    ];
}

If you're letting the package handle exceptions, you can now throw the exception anywhere in your application and it will automatically be rendered to an error response.

throw new SoldOutException();

Contributing

Contributions are more than welcome and you're free to create a pull request on Github. You can run tests with the following command:

vendor/bin/phpunit

If you find bugs or have suggestions for improvements, feel free to submit an issue on Github. However, if it's a security related issue, please send an email to [email protected] instead.

Donating

The package is completely free to use, however, a lot of time has been put into making it. If you want to show your appreciation by leaving a small donation, you can do so by clicking here. Thanks!

License

Laravel Responder is free software distributed under the terms of the MIT license. See license.md for more details.

laravel-responder's People

Contributors

acabutto avatar ahmedbally avatar brunogaspar avatar cberio avatar coziboy avatar dacoto97 avatar ductiletoaster avatar ericp1337 avatar f3rmiparad0x avatar faustbrian avatar fixmk avatar flugg avatar h4ckedneko avatar hu9osaez avatar ilcallo avatar imanghafoori1 avatar joecampo avatar laravel-shift avatar pricecurrent avatar ratno avatar rennokki avatar sachinbahukhandi avatar sojeda avatar stuartowendev avatar the94air avatar tkayfun avatar vgedzius avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-responder's Issues

Exclude Relationship

Is there currently a way to exclude a relationship from being included in the response.

Transform field names within validation failed response

Example:

DB fields for User:

id, first_name, last_name

API Response with transformed fields:

GET /api/users/1

{
    "id": 1,
    "firstName: "John"
    "lastName: "Doe"
}

API Response with errors:

POST /api/users/

{
  "status": 422,
  "success": false,
  "error": {
    "code": "validation_failed",
    "message": "The given data failed to pass validation.",
    "fields": {
      "first_name": [
        "The First Name field is required."
      ],
      "last_name": [
        "The Last Name field is required."
      ]
    }
  }
}

I would like to return same (transformed) field names in the error response.
What is the best way to do this?

Customize error format (Serializer for Errors)

One issue I have had is that my team is responsible for integrating with some services that use a slightly different error response body. We would like to maintain a standard across all of our services and so having a way to easily define the format of the ErrorResponse would be amazing.

You can only transform data containing Eloquent models.

More a feature request than a bug. Any chance of supporting collections in the future, instead of just Eloquent?

The API I'm writing enables filters some queries on collections, which require the query to have been run first.

questions about loading relations via query string.

first of all, thanks for your works.

is this intended result that lazy-loaded when load relations via query string?

// api/users?include=post
public function index(Request $request)
{
    $query = User::paginate();

    // this will lazy-loaded
    return responder()->success($query);

    // this will eager-loaded
    return responder()->success($query->load($request->include));
}

or am I missing something?

Support for polymorphic relations

Hey,

I started running into an issue with the responser and polymorphic relations.

/**
     * Call Include Method.
     *
     * @param  Scope  $scope
     * @param  string $includeName
     * @param  mixed  $data
     * @return \League\Fractal\Resource\ResourceInterface|bool
     * @throws \Exception
     */
    protected function callIncludeMethod( Scope $scope, $includeName, $data )
    {
        if ( ! $data instanceof Transformable || ! $data->relationLoaded( $includeName ) ) {
            return false;
        }

        $data = $data->$includeName;

        return app( Responder::class )->transform( $data );
    }

The problem is that it just transforms $data after accessing the $includeName property.
With polymorphic relations a 'pivot' property will be access which return a MorphPivot class.
This class can not be transformed and an exception will be thrown.

An easy fix would be to check after $data = $data->$includeName; if $data is an instance of MorphPivot. But I don't think this would be the best fix. Maybe there is a better way to handle those cases and other "pivot" cases in a better way.
If there is no transformer for a possible include, don't include it, instead of throwing an exception?

[Question] Error handling

Hi @Flugger,

I'm working on Lumen application and I was wondering if I can completely disable Whoops, looks like something went wrong. message and always receive the output like:

{
    "success": false,
    "status": 500,
    "error": {
        "code": null,
        "message": null
    }
}

I followed your guide and included the trait HandlesApiErrors, as well as added $this->transformException($exception); to my render method.

Cheers,
Evgenii

Abstract methods must be declared or implement

Hi @Flugger,

Thanks for a fantastic package!

Me using it with Laravel 5.4 and in my base test case, I'm pulling your helper trait MakesApiRequests. However, that gives me the error:

[Symfony\Component\Debug\Exception\FatalErrorException]
  Class AgentsCreateTest contains 2 abstract methods and must therefore be declared abstract or implement the remaining methods (TestCase::seeJsonSubset, T
  estCase::decodeResponseJson)

Is that something I should implement myself?

Thanks,
Evgenii

Cannot make non static method Flugg\Responder\Contracts\Transformable::transformer() static in class App\User

Hi,

I'm upgrading the old versio to 2.0. I have installed the new version, removed the old config file etc..

Now i'm trying to run phpunit but before it executes any tests i get this error:
Fatal error: Cannot make non static method Flugg\Responder\Contracts\Transformable::transformer() static in class App\User ... on line 13

Line 13 is class User extends Authenticatable implements Transformable

Any ideas?

Misspelled word inside readme.me

Hi flugger,

I've found a misspelled word inside your readme.me file regarding how to map a Transformer to a model.

The model should implement the Flugg\Responder\Contracts\Transformable instead of Flugg\Responder\Contract\Transformable (note the s at the end of the word Contracts).

Option 1 exception handler not working in Larvel 5.3

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Auth\AuthenticationException;
//use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Flugg\Responder\Exceptions\Handler as ExceptionHandler;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that should not be reported.
     *
     * @var array
     */
    protected $dontReport = [
        \Illuminate\Auth\AuthenticationException::class,
        \Illuminate\Auth\Access\AuthorizationException::class,
        \Symfony\Component\HttpKernel\Exception\HttpException::class,
        \Illuminate\Database\Eloquent\ModelNotFoundException::class,
        \Illuminate\Session\TokenMismatchException::class,
        \Illuminate\Validation\ValidationException::class,
    ];

    /**
     * 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)
    {
        return parent::render($request, $exception);
    }

    /**
     * Convert an authentication exception into an unauthenticated response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Illuminate\Auth\AuthenticationException  $exception
     * @return \Illuminate\Http\Response
     */
    protected function unauthenticated($request, AuthenticationException $exception)
    {
        if ($request->expectsJson()) {
            return response()->json(['error' => 'Unauthenticated.'], 401);
        }

        return redirect()->guest('login');
    }
}

And if I use the following exception:

<?php

namespace App\Exceptions;

use Flugg\Responder\Exceptions\ApiException;

class ModelNotFoundException extends ApiException
{
    protected $statusCode = 404;

    protected $errorCode = 'model_not_found';
}
Route::get('/', function () {

    throw new \App\Exceptions\ModelNotFoundException('Model not found!');
});

I will just get an html page with Call to undefined method App\Exceptions\Handler::renderApiErrors()

Though I'm not sure if this package is officially supported on Laravel 5.3.

version 2

Hello!

Just asking if you (@Flugger) have any estimates when the new version will be available? :)

Status code not included anymore

I have noticed that executing composer update command to latest release, v1.2.20, the status code of api calls is not included even when 'include_status_code' => true in responder.php config file...

Deeply nested includes

I don't know if its a bug or if I am not doing it well, but I have a 3-level deep model relationship, i.e., Survey that has many Items which, in turn, have many Results.
I want to respond with nested information about the 3 levels, having 'items' and 'results' methods in 'SurveyTransformer' and 'ItemTransformer', respectively, but doing things like...

...new SurveyTransformer) ->include(['items.results']) -> respond();
or
...new SurveyTransformer) ->include(['items', 'results']) -> respond();
(my tries so far) does not seem to work...

It returns the 'items' info correctly, but nothing about the 'results', only a key 'items.results' = null at the end of the items...
Can you please point me in the right direction?
Thank you very much in advance.

ValidationFailedException error structure changed.

first of all, thanks for your efforts. ๐Ÿ‘

after migrate from 1.* to 2.*, I found a undocumented changes.
I just leave this issue for others.

2.*
https://github.com/flugger/laravel-responder/blob/77c90a6991570d96377ee87b7c54a2e676369d15/src/Exceptions/Http/ValidationFailedException.php#L55-L58

{
    "status": 422,
    "success": false,
    "error": {
        "0": {
            "some_fields": [
                "messages"
            ]
        },
        "code": "validation_failed",
        "message": "The given data failed to pass validation."
    }
}

1.*
https://github.com/flugger/laravel-responder/blob/f8044cafde230602d35da1dcc5e609e3c04aeeab/src/Exceptions/Http/ValidationFailedException.php#L54-L57

{
    "success": false,
    "status": 422,
    "error": {
        "code": "validation_failed",
        "message": "The given data failed to pass validation.",
        "fields": {
            "some_fields": [
                "messages"
            ]
        }
    }
}

keep getting "Data must only contain models implementing the Transformable contract." error

Hi
I have implemented the Transformable contract (at least that's what I think!) yet I keep getting this error. I'm using Laravel 5.2 and this is how I have implemented it:

In my User.php (model) I have added these at the top:

use App\Transformers\UserTransformer;
use Illuminate\Database\Eloquent\Model;
use Flugg\Responder\Contracts\Transformable;

and these in the class:

/**
     * The path to the transformer class.
     *
     * @return string|null
     */
    public static function transformer()
    {
        return UserTransformer::class;
    }

And I have created a UserTransformer with these codes in it:

namespace App\Transformers;

use App\User;
use Flugg\Responder\Transformer;

class UserTransformer extends Transformer
{
    /**
     * Transform the model data into a generic array.
     *
     * @param  User $user
     * @return array
     */
    public function transform(User $user):array
    {
        return [
            'id' => (int) $user->id,
            'email'    => $user->email,
            'username' => $user->username
        ];
    }
}

Yet when I try to use it by this test method(in my UserController file):

public function tests(){
      $users = User::all();
      return Responder::success( $users );
    }

I get this error:
Data must only contain models implementing the Transformable contract.

Am I missing something here?
Thanks

transformPivot

Could you provide an example of how to use the transformPivot method?

Making Multiple Controller Requests in Testing causes strange behaviour

Just want to inform other heavy laravel-responder users.

If you are making multiple calls within an unit test, eg:

function test_something{
  //one request
  $this->json('PUT');
  //second request
  $this->json('PUT');
}

You will experience strange behaviour. This is due to the fact - the responder binding is singleton. Hence some previously called responder configuration (such as with,without) will overlap with subsequent calls.

The culprit:
https://github.com/flugger/laravel-responder/blob/77523246e20ce1ac1faafe20d244aa0a7819df8e/src/ResponderServiceProvider.php#L238

I didn't have enough time to make the changes and run the test. And - this issue only applies in testing environment.

As for workaround:

rebind the responder in your app service provider

    $this->app->bind('responder_test', function ($app) {
            return $app->make(Responder::class);
        });

create a new tests/bootstrap.php

function responder()
{
    return app('responder_test');
}

include dirname(__FILE__) . "/../bootstrap/autoload.php";

change your phpunit.xml

         bootstrap="tests/bootstrap.php"

That's it. Hopefully, the author will put this into the readme.

Incompatible API Middleware Exception

Hi,

I seem to have having issues on this one. I am on laravel/framework 5.4.*

Type error: Argument 2 passed to Barryvdh\\Cors\\HandleCors::addHeaders() 
must be an instance of Symfony\\Component\\HttpFoundation\\Response, instance of
Flugg\\Responder\\Http\\Responses\\ErrorResponseBuilder given

Incase you say HandleCors or third parties concern, see:

Type error: Argument 1 passed to Illuminate\\Routing\\Middleware\\ThrottleRequests::addHeaders()
must be an instance of Symfony\\Component\\HttpFoundation\\Response, instance of
Flugg\\Responder\\Http\\Responses\\ErrorResponseBuilder given

Null (empty) relationship throws error when using DataArraySerializer

This looks like an issue in Scope.php on line 318:

        return $serializer->null();

From what I can tell, SerializerAbstract::null() is available in thephpleague/fractal@dev-master but not @0.13.0, which is your current version dependency.

FatalThrowableError in Scope.php line 318:
Call to undefined method League\Fractal\Serializer\DataArraySerializer::null()
in Scope.php line 318
at Scope->serializeResource(object(DataArraySerializer), null) in Scope.php line 212
at Scope->toArray() in Transformer.php line 81
at Transformer->includeResourceIfAvailable(object(Scope), object(Client), array(), 'conversations') in Transformer.php line 61
at Transformer->processIncludedResources(object(Scope), object(Client)) in Scope.php line 363
at Scope->fireIncludedTransformers(object(ClientTransformer), object(Client)) in Scope.php line 342
at Scope->fireTransformer(object(ClientTransformer), object(Client)) in Scope.php line 278
at Scope->executeResourceTransformers() in Scope.php line 208
at Scope->toArray() in SuccessResponseFactory.php line 206
at SuccessResponseFactory->serialize(object(Item)) in SuccessResponseFactory.php line 55
at SuccessResponseFactory->make(object(Client), '200', array()) in Responder.php line 62
at Responder->success(object(Client), '200', array()) in RespondsWithJson.php line 28
at ClientController->successResponse(object(Client)) in ClientController.php line 67
at ClientController->show(object(Client))
at call_user_func_array(array(object(ClientController), 'show'), array('client' => object(Client))) in Controller.php line 80
at Controller->callAction('show', array('client' => object(Client))) in ControllerDispatcher.php line 146
at ControllerDispatcher->call(object(ClientController), object(Route), 'show') in ControllerDispatcher.php line 94
at ControllerDispatcher->Illuminate\Routing{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 52
at Pipeline->Illuminate\Routing{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 102
at Pipeline->then(object(Closure)) in ControllerDispatcher.php line 96
at ControllerDispatcher->callWithinStack(object(ClientController), object(Route), object(Request), 'show') in ControllerDispatcher.php line 54
at ControllerDispatcher->dispatch(object(Route), object(Request), 'App\Http\Controllers\API\ClientController', 'show') in Route.php line 174
at Route->runController(object(Request)) in Route.php line 140
at Route->run(object(Request)) in Router.php line 724
at Router->Illuminate\Routing{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 52
at Pipeline->Illuminate\Routing{closure}(object(Request)) in Authenticate.php line 28
at Authenticate->handle(object(Request), object(Closure))
at call_user_func_array(array(object(Authenticate), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in CreateFreshApiToken.php line 41
at CreateFreshApiToken->handle(object(Request), object(Closure))
at call_user_func_array(array(object(CreateFreshApiToken), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in VerifyCsrfToken.php line 64
at VerifyCsrfToken->handle(object(Request), object(Closure))
at call_user_func_array(array(object(VerifyCsrfToken), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in ShareErrorsFromSession.php line 49
at ShareErrorsFromSession->handle(object(Request), object(Closure))
at call_user_func_array(array(object(ShareErrorsFromSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in StartSession.php line 64
at StartSession->handle(object(Request), object(Closure))
at call_user_func_array(array(object(StartSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in AddQueuedCookiesToResponse.php line 37
at AddQueuedCookiesToResponse->handle(object(Request), object(Closure))
at call_user_func_array(array(object(AddQueuedCookiesToResponse), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in EncryptCookies.php line 59
at EncryptCookies->handle(object(Request), object(Closure))
at call_user_func_array(array(object(EncryptCookies), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 102
at Pipeline->then(object(Closure)) in Router.php line 726
at Router->runRouteWithinStack(object(Route), object(Request)) in Router.php line 699
at Router->dispatchToRoute(object(Request)) in Router.php line 675
at Router->dispatch(object(Request)) in Kernel.php line 246
at Kernel->Illuminate\Foundation\Http{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 52
at Pipeline->Illuminate\Routing{closure}(object(Request)) in Debugbar.php line 49
at Debugbar->handle(object(Request), object(Closure))
at call_user_func_array(array(object(Debugbar), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in CheckForMaintenanceMode.php line 44
at CheckForMaintenanceMode->handle(object(Request), object(Closure))
at call_user_func_array(array(object(CheckForMaintenanceMode), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 102
at Pipeline->then(object(Closure)) in Kernel.php line 132
at Kernel->sendRequestThroughRouter(object(Request)) in Kernel.php line 99
at Kernel->handle(object(Request)) in index.php line 53

[Idea] Register Transformers like Policies

I recently was playing around with the package and thought Models could be cleaned up a bit by registering transformers in the same way as policies are registered.

TransformerServiceProvider

<?php

namespace App\Providers;

use App\Models;
use App\Transformers;
use Flugg\Responder\TransformerServiceProvider as ServiceProvider;

class TransformerServiceProvider extends ServiceProvider
{
    /**
     * The transformer mappings for the application.
     *
     * @var array
     */
    protected $transformers = [
        Models\Post::class => Transformers\PostTransformer::class,
        Models\Picture::class => Transformers\PictureTransformer::class,
        Models\User::class => Transformers\UserTransformer::class,
    ];

    /**
     * Register any transformer services.
     */
    public function boot()
    {
        $this->registerTransformers();
    }
}

Old Model

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Flugg\Responder\Contracts\Transformable;

class User extends Authenticatable implements Transformable
{
    public static function transformer()
    {
        return \App\Transformers\UserTransformer::class;
    }
}

New Model (No need for interface or transform method)

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    // ...
}

The interface and transform method would no longer be required since we could just check if the model has a transformer bound to it.

Would do you think about this approach?

Relationship filter parameters unsupported

I haven't had time to test this too thoroughly, I will try and update this issue with more information when I do, but it doesn't appear that fractal's nested relationships are working correctly when used with this package. By that I mean url patterns like this:

example.com/books?include=author.stores

Getting the "author" relationship works, but getting the ".stores" portion of it does not.

Pivot transformation

Hi @Flugger,

Thanks for your package!

I got the following relationship defined in my model:

    /**
     * Get the agents for the agency.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function agents()
    {
        return $this->belongsToMany(User::class, 'agents');
    }

In my controller, I'm trying to output it by applying the transformation like so:

    public function all()
    {
        ...

        return responder()->success($agency->agents());
    }

Unfornatally it doesn't pick up the defined transformation for the user model, so I got to define it manually:

    public function all()
    {
        ...

        // force transform the agents into users
        return responder()->transform($agency->agents(), new UserTransformer)
            ->respond();
    }

Are you going to address this issue in the future releases? The issue is related only when you return pivot relationship otherwise, it works fine and picks the right transformation.

Thanks,
Evgenii

[5.4] Translator Error

I am getting an exception thrown after I upgraded to 5.4.

  [Symfony\Component\Debug\Exception\FatalThrowableError]                                                                                                     
  Type error: Argument 2 passed to Flugg\Responder\Http\ErrorResponseBuilder::__construct() must be an instance of Symfony\Component\Translation\TranslatorI  
  nterface, instance of Illuminate\Translation\Translator given, called in vendor/flugger/laravel-responder/src  
  /ResponderServiceProvider.php on line 130 

composer require - cannot install

composer require flugger/laravel-responder gives me this output:


Using version ^1.2 for flugger/laravel-responder
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - flugger/laravel-responder v1.2.1 requires league/fractal dev-master -> satisfiable by league/fractal[dev-master] but these conflict with your requirements or minimum-stability.
    - flugger/laravel-responder v1.2.0 requires league/fractal dev-master -> satisfiable by league/fractal[dev-master] but these conflict with your requirements or minimum-stability.
    - Installation request for league/fractal (locked at 0.16.0) -> satisfiable by league/fractal[0.16.0].
    - flugger/laravel-responder v1.2.10 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.11 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.12 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.13 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.14 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.15 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.16 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.17 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.18 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.19 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.20 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.21 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.22 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.4 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.5 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.6 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.7 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.8 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - flugger/laravel-responder v1.2.9 requires league/fractal ^0.14.0 -> satisfiable by league/fractal[0.14.0].
    - Conclusion: don't install league/fractal 0.14.0
    - flugger/laravel-responder v1.2.2 requires league/fractal ^0.13.0 -> satisfiable by league/fractal[0.13.0].
    - flugger/laravel-responder v1.2.3 requires league/fractal ^0.13.0 -> satisfiable by league/fractal[0.13.0].
    - Conclusion: don't install league/fractal 0.13.0
    - Installation request for flugger/laravel-responder ^1.2 -> satisfiable by flugger/laravel-responder[v1.2.0, v1.2.1, v1.2.10, v1.2.11, v1.2.12, v1.2.13, v1.2.14, v1.2.15, v1.2.16, v1.2.17, v1.2.18, v1.2.19, v1.2.2, v1.2.20, v1.2.21, v1.2.22, v1.2.3, v1.2.4, v1.2.5, v1.2.6, v1.2.7, v1.2.8, v1.2.9].


Installation failed, reverting ./composer.json to its original content.

My composer.json:

{
    "name": "laravel/laravel",
    "description": "The Laravel Framework.",
    "keywords": [
        "framework",
        "laravel",
        "boilerplate"
    ],
    "license": "MIT",
    "type": "project",
    "require": {
        "php": ">=5.6.4",
        "arcanedev/log-viewer": "~4.0",
        "arcanedev/no-captcha": "~3.0",
        "creativeorange/gravatar": "~1.0",
        "davejamesmiller/laravel-breadcrumbs": "^3.0",
        "dingo/api": "1.0.x@dev",
        "hieu-le/active": "~3.0",
        "laravel/framework": "5.4.*",
        "laravel/socialite": "^3.0",
        "laravel/tinker": "~1.0",
        "laravelcollective/html": "5.4.*",
        "prettus/l5-repository": "^2.6",
        "sentry/sentry-laravel": "^0.6.1",
        "yajra/laravel-datatables-oracle": "^7.0"
    },
    "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~5.7",
        "barryvdh/laravel-debugbar": "^2.1",
        "laravel/browser-kit-testing": "^1.0"
    },
    "autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\\": "app/"
        },
        "files": [
            "app/helpers.php"
        ]
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        },
        "classmap": [
            "tests/TestCase.php",
            "tests/BrowserKitTestCase.php"
        ]
    },
    "scripts": {
        "post-root-package-install": [
            "php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "php artisan key:generate"
        ],
        "post-install-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postInstall",
            "php artisan optimize"
        ],
        "post-update-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postUpdate",
            "php artisan optimize"
        ]
    },
    "config": {
        "preferred-install": "dist",
        "sort-packages": true
    }
}

I can't understand what's wrong. Can you please help me?

Thanks

Transforming nested relations

Hi,

I've been using your package for simple transformations on models. Now I want to go more advanced.

In my Controller I have:

    $staff = staff::with('warfs.devices', 'tags_assignment.tags')->where('staff.uuid', '=', $staff_uuid)->first();

So some warfs have a device.

I want to transform my data that i only get the warfs.id and devices.uuid

In my transformer I have

class StaffTransformer extends Transformer
{

protected $load = [
    'warfs.devices' => WarfsTransformer::class,
    'tags_assignment.tags' => StaffTagsTransformer::class,
];

 /**
 * Transform the model data into a generic array.
 *
 * @param  staff $staff
 * @return array
 */
public function transform(staff $staff):array
{
    return [
        'uuid' => (string) $staff->uuid,
        'firstname' => (string) $staff->firstname,
    ];
}

}

In WarfsTransformer I have

protected $relations = ['*'];

/**
 * Transform the model data into a generic array.
 *
 * @param  warfs $warfs
 * @return array
 */
public function transform(warfs $warfs):array
{
    return [
        'id' => (int) $warfs->id
    ];
}

However i receive all the columns on the warfs table when i transform the data:

{
"data": {
"uuid": "8EBB71E9-BCF2-4E5B-A95E-549F792C5BA7",
"firstname": "Ken",
"warfs": [{
"id": 18,
"uuid": "C90778D9-6B9F-4A6D-814F-7FC151E9DF4F",
"warf_identifier": "",
"workplace_id": "
",
"pivot": {
"staff_id": 1,
"warfs_id": 18
},
"devices": []
}, {
"id": 42,
"warf_identifier": "",
"workplace_id": "
",
"pivot": {
"staff_id": 1,
"warfs_id": 42
},
"devices": [{
"id": 5,
"uuid": "46497A88-42A6-438D-895B-541C6BD98A4D",
"sn": "6530165100014",
}]
}],
"tags_assignment": {
"id": 5,
"uuid": "1CAB4C9D-9213-4B26-A51E-32AECBA88221",
"tags_id": 1,
"staff_id": 1,
"warfs_id": 0,
"teams_id": 0,
"tags": {
"id": 1,
"uuid": "68D566C2-09CC-4EAF-B80F-095664202249",
"tag": "340062B83F",
"tag_type": "SINGLE"
}
},
"warfs.pivot": null,
"warfs.devices": null,
"warfs.devices.pivot": null,
"tags_assignment.tags": null
}
}

What am I doing wrong?

Class Translator does not exist

Firstly great package and awesome work.

I'm using laravel 5.3 the error I'm getting is

Class Illuminate\\Contracts\\Translation\\Translator does not exist

As I can see it's been used at 2 places.

Question

In response, there is always status and success key added no matter what Serializer i'm using.
What is the best way to not include these two key?

    "status": 200,
    "success": true,

problem when loading several relations through query parameter

When trying to load several relationships through query parameter via with i always get a call to undefined relationships Exception.

it appears that the relations came as a string and they are not converted to array.

Example: if i make a request like the following

GET users?with=roles,permissions

the response that i get is:

Response: Call to undefined relationship [roles,permissions] on model [App//User]

PD: When i load a single relation via with param the request have no problem at all

BindingResolutionException

I am getting this error in lumen when I try to use this library. Not if this is a bug to I am doing something wrong.

BindingResolutionException
Target [Illuminate\Contracts\Translation\Loader] is not instantiable while building
[Flugg\Responder\Responder, Flugg\Responder\ErrorFactory,
Flugg\Responder\ErrorMessageResolver, Illuminate\Translation\Translator].

  public function index(Responder $responder){
         $response = Experience::all();
         //return response($response,200);
         return responder()->success($response)->respond();
    }

issue with the same type model relationships

Hi flugger

I've been using relations with this package and it works just fine. For example if I wanna send the owner of the comment it works just fine.

On the other hand, I wanna send the children of comments (it's a tree-style comment system like Disqus) in my api, and only then(using relations to retrieve the same type of model) I get this error:
"Data must only contain models implementing the Transformable contract."

My relation implementation seems fine as it works just fine, it's just I need it in the API but it fails :(, any idea how to fix it?

Thank your for your great package

Transforming an empty Collection throws InvalidArgumentException

Getting an exception when I try to transform an empty Collection:

ClientController.php:

        $clients = Client::where('id', 'This does not exist.')->get();

        return $this->successResponse($clients);

Results in:

InvalidArgumentException in SuccessResponseFactory.php line 238:
Data must only contain models implementing the Transformable contract.
in SuccessResponseFactory.php line 238
at SuccessResponseFactory->resolveModel(object(Collection)) in SuccessResponseFactory.php line 114
at SuccessResponseFactory->transformCollection(object(Collection), null) in SuccessResponseFactory.php line 78
at SuccessResponseFactory->transform(object(Collection)) in SuccessResponseFactory.php line 52
at SuccessResponseFactory->make(object(Collection), '200', array()) in Responder.php line 62
at Responder->success(object(Collection), '200', array()) in RespondsWithJson.php line 28
at ClientController->successResponse(object(Collection)) in ClientController.php line 51
at ClientController->index(object(ClientFilters), object(Request))
at call_user_func_array(array(object(ClientController), 'index'), array(object(ClientFilters), object(Request))) in Controller.php line 80
at Controller->callAction('index', array(object(ClientFilters), object(Request))) in ControllerDispatcher.php line 146
at ControllerDispatcher->call(object(ClientController), object(Route), 'index') in ControllerDispatcher.php line 94
at ControllerDispatcher->Illuminate\Routing{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 52
at Pipeline->Illuminate\Routing{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 102
at Pipeline->then(object(Closure)) in ControllerDispatcher.php line 96
at ControllerDispatcher->callWithinStack(object(ClientController), object(Route), object(Request), 'index') in ControllerDispatcher.php line 54
at ControllerDispatcher->dispatch(object(Route), object(Request), 'App\Http\Controllers\API\ClientController', 'index') in Route.php line 174
at Route->runController(object(Request)) in Route.php line 140
at Route->run(object(Request)) in Router.php line 724
at Router->Illuminate\Routing{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 52
at Pipeline->Illuminate\Routing{closure}(object(Request)) in Authenticate.php line 28
at Authenticate->handle(object(Request), object(Closure))
at call_user_func_array(array(object(Authenticate), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in CreateFreshApiToken.php line 41
at CreateFreshApiToken->handle(object(Request), object(Closure))
at call_user_func_array(array(object(CreateFreshApiToken), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in VerifyCsrfToken.php line 64
at VerifyCsrfToken->handle(object(Request), object(Closure))
at call_user_func_array(array(object(VerifyCsrfToken), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in ShareErrorsFromSession.php line 49
at ShareErrorsFromSession->handle(object(Request), object(Closure))
at call_user_func_array(array(object(ShareErrorsFromSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in StartSession.php line 64
at StartSession->handle(object(Request), object(Closure))
at call_user_func_array(array(object(StartSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in AddQueuedCookiesToResponse.php line 37
at AddQueuedCookiesToResponse->handle(object(Request), object(Closure))
at call_user_func_array(array(object(AddQueuedCookiesToResponse), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in EncryptCookies.php line 59
at EncryptCookies->handle(object(Request), object(Closure))
at call_user_func_array(array(object(EncryptCookies), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 102
at Pipeline->then(object(Closure)) in Router.php line 726
at Router->runRouteWithinStack(object(Route), object(Request)) in Router.php line 699
at Router->dispatchToRoute(object(Request)) in Router.php line 675
at Router->dispatch(object(Request)) in Kernel.php line 246
at Kernel->Illuminate\Foundation\Http{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 52
at Pipeline->Illuminate\Routing{closure}(object(Request)) in Debugbar.php line 49
at Debugbar->handle(object(Request), object(Closure))
at call_user_func_array(array(object(Debugbar), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request)) in CheckForMaintenanceMode.php line 44
at CheckForMaintenanceMode->handle(object(Request), object(Closure))
at call_user_func_array(array(object(CheckForMaintenanceMode), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 136
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Illuminate\Routing{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 102
at Pipeline->then(object(Closure)) in Kernel.php line 132
at Kernel->sendRequestThroughRouter(object(Request)) in Kernel.php line 99
at Kernel->handle(object(Request)) in index.php line 53

It looks like there is a null check happening in SuccessResponseFactory.php:

    public function transform( $data = null, $transformer = null ):ResourceInterface
    {
        if ( is_null( $data ) ) {
            return new FractalNull();
        };

The problem is that a Collection with no items does not pass is_null().

My quick and dirty fix is:

        if ( is_null( $data ) || $data instanceof Collection && $data->isEmpty() ) {
            return new FractalNull();
        };

Am I doing something wrong here, or any ideas on a better way?

Laravel 5.1 vendor:publish Error

When using Laravel 5.1 and running php artisan vendor:publish I get the following error: Call to undefined function Flugg\Responder\resource_path()

Reponse problem

I can't seem to figure out why the successResponse() method returns the same object in all array keys. Before i call the reponse method i have a Collection with 2 different objects and the response is a JSON with 2 exactly same objects. From what i tried I saw that the toArray() method does that. Mention i'm using Laravel 5.3.*.

Calling multiple transformers in sequence

Lets say $model1 has a relationship 'shipments', $model2 has none. Transformer2 would throw a RelationNotFoundException exception looking for relation 'shipments' on $model2.

Transformer::transform($model1, new Transformer1);
Transformer::transform($model2, new Transformer2);

"exception":"Illuminate\Database\Eloquent\RelationNotFoundException",
"file":"/var/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/RelationNotFoundException.php",
"line": 34,

How to Pass the Resource Key

Hi, I think this is a very good packet, I am implementing it but i have a question.

How to pass the resource key into the Respond.
Fractal do this like this.
// Important, notice the Resource Key in the third parameter:
$resource = new Item($book, new JsonApiBookTransformer(), 'books');
books is the resouce key but I do not how to do it in laravel-responder.

thanks

Php 5.6

Hi, we are using PHP 5.6 in our server.

There is some package like this to work without php7?

Thanks!

Throwing same exception

Hi,

I have a question about error handling. I have comes across this when setting the Laravel App\Exceptions\Handler to use Flugg\Responder\Exceptions\Handler as ExceptionHandler. It looks like lines 78-80 of the file laravel-responder/src/Traits/HandlesApiErrors.php catches and throws the same error. Should the newly thrown error be an instance of Flugg\Responder\Exceptions\Http\RelationNotFoundException instead of Illuminate\Database\Eloquent\RelationNotFoundException?

/**
     * Transform an Eloquent exception into an API exception.
     *
     * @param  Exception $exception
     * @return void
     * @throws ResourceNotFoundException
     * @throws RelationNotFoundException
     */
    protected function transformEloquentException(Exception $exception)
    {
        if ($exception instanceof ModelNotFoundException) {
            throw new ResourceNotFoundException();
        }
        if ($exception instanceof RelationNotFoundException) {
            throw new RelationNotFoundException();
        }
    }

One change could be:

/**
     * Transform an Eloquent exception into an API exception.
     *
     * @param  Exception $exception
     * @return void
     * @throws ResourceNotFoundException
     * @throws RelationNotFoundException
     */
    protected function transformEloquentException(Exception $exception)
    {
        if ($exception instanceof ModelNotFoundException) {
            throw new ResourceNotFoundException();
        }
        if ($exception instanceof RelationNotFoundException) {
            throw new \Flugg\Responder\Exceptions\Http\RelationNotFoundException();
        }
    }

Am I overlooking anything with this proposed change?

Thanks,

Handler not converting 404 in Laravel 5.5

It shows JSON for just regular browser requests. It should show JSON on api requests & for HTTP browser requests the regular 404 view.

If I use https://github.com/flugger/laravel-responder#option-2-use-convertsexceptions-trait it returns the 404 view but not a 404 JSON response just a error with no message.

Right now i'm just using this with Option 2:

if($request->wantsJson()) {
       $this->convertDefaultException($exception);
    
       if ($exception instanceof HttpException) {
             return $this->renderResponse($exception);
       }
}

Including an Invalid Relation Shouldn't Throw Exception

Hi

First, thanks for the package, it has been really helpful :)

Now for the issue.

If i have defined a list of available relations on the transformer and then when i do a request and i request to include a relation that's not on that list and at the same time is invalid (doesn't exist on the model), it throws an exception about the relation being invalid, IMO, that shouldn't throw the exception, at all, since that's not on the list of the available relations.

Transformer:

<?php

namespace App\Transformers;

use App\Models\Client;

class ClientTransformer extends Transformer
{
    /**
     * List of available relations.
     *
     * @var array
     */
    protected $relations = ['invoices'];

    // Truncated for brevity
}

If i hit http://foo.dev/clients?with=invalid_relation an exception is thrown.

And if for example, i make that array empty and require ?with=invoices it doesn't throw an error, which is kinda expected, since it's not allowed.

I know i can catch the exception and deal with it, however, i don't feel that this is the correct behaviour.

Thanks!

Multiple transformers for the same model

I've been using the spatie/laravel-fractal package but appreciate the built-in error formatting this package provides. I need to be able to provide one of various transformers for the same model though. Is there any reason this package appears to lock you down to a single transformer class per entity/model?

Lumen [5.3] Not working

BindingResolutionException in Container.php line 763:
Target [Illuminate\Contracts\Routing\ResponseFactory] is not instantiable.
in Container.php line 763
at Container->build('Illuminate\Contracts\Routing\ResponseFactory', array()) in Container.php line 644
at Container->make('Illuminate\Contracts\Routing\ResponseFactory', array()) in Application.php line 211
at Application->make('Illuminate\Contracts\Routing\ResponseFactory') in Container.php line 1203
at Container->offsetGet('Illuminate\Contracts\Routing\ResponseFactory') in ResponderServiceProvider.php line 121
at ResponderServiceProvider->Flugg\Responder\{closure}(object(Application), array()) in Container.php line 746
at Container->build(object(Closure), array()) in Container.php line 644
at Container->make('Flugg\Responder\Http\SuccessResponseBuilder', array()) in Application.php line 211
at Application->make('Flugg\Responder\Http\SuccessResponseBuilder') in Container.php line 1203
at Container->offsetGet('Flugg\Responder\Http\SuccessResponseBuilder') in ResponderServiceProvider.php line 74
at ResponderServiceProvider->Flugg\Responder\{closure}(object(Application), array()) in Container.php line 746
at Container->build(object(Closure), array()) in Container.php line 644
at Container->make('Flugg\Responder\Responder', array()) in Application.php line 211
at Application->make('Flugg\Responder\Responder', array()) in helpers.php line 39
at app('Flugg\Responder\Responder') in helpers.php line 14
at responder() in web.php line 23
at Closure->{closure}()
at call_user_func_array(object(Closure), array()) in Container.php line 508
at Container->call(object(Closure), array()) in RoutesRequests.php line 523
at Application->callActionOnArrayBasedRoute(array(true, array(object(Closure)), array())) in RoutesRequests.php line 497
at Application->handleFoundRoute(array(true, array(object(Closure)), array())) in RoutesRequests.php line 394
at Application->Laravel\Lumen\Concerns\{closure}() in RoutesRequests.php line 650
at Application->sendThroughPipeline(array(), object(Closure)) in RoutesRequests.php line 400
at Application->dispatch(null) in RoutesRequests.php line 341
at Application->run() in index.php line 28

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.