Json api error response

This page contains additional examples of how to apply various parts of the specification.

This page contains additional examples of how to apply various parts of the specification.

Sparse Fieldsets

Examples of how sparse fieldsets work.

Basic request:

GET /articles?include=author HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!",
      "body": "The shortest article. Ever.",
      "created": "2015-05-22T14:56:29.000Z",
      "updated": "2015-05-22T14:56:28.000Z"
    },
    "relationships": {
      "author": {
        "data": {"id": "42", "type": "people"}
      }
    }
  }],
  "included": [
    {
      "type": "people",
      "id": "42",
      "attributes": {
        "name": "John",
        "age": 80,
        "gender": "male"
      }
    }
  ]
}

Request with fields[articles] and fields[people] parameters:

GET /articles?include=author&fields[articles]=title,body,author&fields[people]=name HTTP/1.1

Note: The above example URI shows unencoded [ and ] characters simply
for readability. In practice, these characters should be percent-encoded, as
noted in the base specification. See “Square Brackets in Parameter Names”.

Here we want articles objects to have fields title, body and author only and people objects to have name field only.

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!",
      "body": "The shortest article. Ever."
    },
    "relationships": {
      "author": {
        "data": {"id": "42", "type": "people"}
      }
    }
  }],
  "included": [
    {
      "type": "people",
      "id": "42",
      "attributes": {
        "name": "John"
      }
    }
  ]
}

Pay attention to the fact that you have to add a relationship name both in include and fields (since relationships are fields too), otherwise you’ll get:

GET /articles?include=author&fields[articles]=title,body&fields[people]=name HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!",
      "body": "The shortest article. Ever."
    }
  }],
  "included": [
    {
      "type": "people",
      "id": "42",
      "attributes": {
        "name": "John"
      }
    }
  ]
}

Note: The above example URI shows unencoded [ and ] characters simply
for readability. In practice, these characters should be percent-encoded, as
noted in the base specification. See “Square Brackets in Parameter Names”.

Example of a page-based strategy on how to add pagination links.

Basic request:

GET /articles?page[number]=3&page[size]=1 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "meta": {
    "totalPages": 13
  },
  "data": [
    {
      "type": "articles",
      "id": "3",
      "attributes": {
        "title": "JSON:API paints my bikeshed!",
        "body": "The shortest article. Ever.",
        "created": "2015-05-22T14:56:29.000Z",
        "updated": "2015-05-22T14:56:28.000Z"
      }
    }
  ],
  "links": {
    "self": "http://example.com/articles?page[number]=3&page[size]=1",
    "first": "http://example.com/articles?page[number]=1&page[size]=1",
    "prev": "http://example.com/articles?page[number]=2&page[size]=1",
    "next": "http://example.com/articles?page[number]=4&page[size]=1",
    "last": "http://example.com/articles?page[number]=13&page[size]=1"
  }
}

Note: The above example URIs show unencoded [ and ] characters simply
for readability. In practice, these characters should be percent-encoded, as
noted in the base specification. See “Square Brackets in Parameter Names”.

Note: Putting a property like "totalPages" in "meta" can be a convenient way
to indicate to clients the total number of pages in a collection (as opposed to
the "last" link, which simply gives the URI of the last page). However, all
"meta" values are implementation-specific, so you can call this member whatever
you like ("total", "count", etc.) or not use it at all.

Error Objects

Examples of how error objects work.

A Basic Error Object

In the response below, the server is indicating that it encountered an error
while creating/updating the resource, and that this error was caused
by an invalid "firstName" attribute:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/vnd.api+json

{
  "errors": [
    {
      "status": "422",
      "source": { "pointer": "/data/attributes/firstName" },
      "title":  "Invalid Attribute",
      "detail": "First name must contain at least two characters."
    }
  ]
}

Every member in an error object is optional, but all help the client
by providing extra details.

The source member is used to indicate
which part of the request document caused the error.

The title and detail members are similar, but detail is specific
to this occurrence of the problem, whereas title is more generic.

The status member represents the HTTP status code associated with the problem.
It’s very helpful when multiple errors are returned at once (see below), as the
HTTP response itself can only have one status code. However, it can also be
useful for single errors, to save clients the trouble of consulting the HTTP
headers, or for using JSON:API over non-HTTP protocols, which may be officially
supported in the near future.

Multiple Errors

When multiple errors occur in response to a single request, the server
can simply add each error to the errors array:

HTTP/1.1 400 Bad Request
Content-Type: application/vnd.api+json

{
  "errors": [
    {
      "status": "403",
      "source": { "pointer": "/data/attributes/secretPowers" },
      "detail": "Editing secret powers is not authorized on Sundays."
    },
    {
      "status": "422",
      "source": { "pointer": "/data/attributes/volume" },
      "detail": "Volume does not, in fact, go to 11."
    },
    {
      "status": "500",
      "source": { "pointer": "/data/attributes/reputation" },
      "title": "The backend responded with an error",
      "detail": "Reputation service not responding after three requests."
    }
  ]
}

The only uniqueness constraint on error objects is the id field. Thus,
multiple errors on the same attribute can each be given their own error
object. The example below shows multiple errors on the "firstName" attribute:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/vnd.api+json

{
  "errors": [
    {
      "source": { "pointer": "/data/attributes/firstName" },
      "title": "Invalid Attribute",
      "detail": "First name must contain at least two characters."
    },
    {
      "source": { "pointer": "/data/attributes/firstName" },
      "title": "Invalid Attribute",
      "detail": "First name must contain an emoji."
    }
  ]
}

Note: in the responses above with a 422 status code, 400 Bad Request would
also be acceptable. (More details.)
JSON:API doesn’t take a position on 400 vs. 422.

Error Codes

The code member of an error object contains an application-specific code
representing the type of problem encountered. code is similar to title
in that both identify a general type of problem (unlike detail, which is
specific to the particular instance of the problem), but dealing with code
is easier programatically, because the “same” title may appear in different
forms due to localization.

For the example below, imagine the API docs specifed the following mapping:

Code Problem
123 Value too short
225 Password lacks a letter, number, or punctuation character
226 Passwords do not match
227 Password cannot be one of last five passwords

Multiple errors on "password" attribute, with error code:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/vnd.api+json

{
  "jsonapi": { "version": "1.0" },
  "errors": [
    {
      "code":   "123",
      "source": { "pointer": "/data/attributes/firstName" },
      "title":  "Value is too short",
      "detail": "First name must contain at least two characters."
    },
    {
      "code":   "225",
      "source": { "pointer": "/data/attributes/password" },
      "title": "Passwords must contain a letter, number, and punctuation character.",
      "detail": "The password provided is missing a punctuation character."
    },
    {
      "code":   "226",
      "source": { "pointer": "/data/attributes/password" },
      "title": "Password and password confirmation do not match."
    }
  ]
}

Notice that this response includes not only the errors top-level member,
but the jsonapi top-level member. Error responses cannot contain the
top-level data member, but can include all the other top-level members
JSON:API defines.

Also, notice that the third error object lacks a detail member (perhaps
for security). Again, all error object members are optional.

Advanced source Usage

In the example below, the user is sending an invalid JSON:API
request, because it’s missing the data member:

PATCH /posts/1 HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{ "datum": [ ] }

Therefore, the server responds:

HTTP/1.1 422 Unprocesssable Entity
Content-Type: application/vnd.api+json

{
  "errors": [
    {
      "source": { "pointer": "" },
      "detail":  "Missing `data` Member at document's top level."
    }
  ]
}

It uses source to point to the top-level of the document ("").
(Pointing to “/” would be an appropriate reference to the string
"some value" in the request document {"": "some value"}.
Pointing to "/data" would be invalid because the request document did
not have a value at "/data", and source is always given with reference
to the request document.)

If the server cannot parse the request as valid JSON, including
source doesn’t make sense (because there’s no JSON document for source to
refer to). Here’s how the server might respond to an invalid JSON document:

{
  "errors": [{
    "status": "400",
    "detail": "JSON parse error - Expecting property name at line 1 column 2 (char 1)."
  }]
}

Invalid Query Parameters

The source member can also be used to indicate that the error originated
from a problem with a URI query parameter, like so:

GET /api/posts/1?include=author HTTP/1.1
HTTP/1.1 400 Bad Request
Content-Type: application/vnd.api+json

{
  "errors": [
    {
      "source": { "parameter": "include" },
      "title":  "Invalid Query Parameter",
      "detail": "The resource does not have an `author` relationship path."
    }
  ]
}

In most cases, JSON:API requires the server to return an error when it encounters
an invalid value for a JSON:API–defined query parameter. However, for API-specific
query parameters (i.e. those not defined by JSON:API), a server may choose to
ignore an invalid parameter and have the request succeed, rather than respond with
an error. API-specific query parameters must contain one non a-z
character.

Other examples of invalid parameters include: ?fields[people]= (invalid parameter name;
should be fields[people]) and ?redirect_to=http%3A%2F%2Fwww.owasp.org (invalid parameter,
in this case, a phishing attack), etc.

  • Introduction
  • Error Objects
  • Error Lists
  • Responses
    • HTTP Status
  • JSON:API Exceptions
    • Helper Methods
  • Validation Errors
    • Source Pointers
  • Error Rendering
    • JSON Responses
    • Middleware Responses
    • Always Rendering JSON:API Errors
    • Custom Rendering Logic
    • Converting Exceptions
  • Error Reporting

# Introduction

The JSON:API specification defines error objects (opens new window)
that are used to provide information to a client about problems encountered
while performing an operation.

Errors are returned to the client in the top-level errors member of the
JSON document.

Laravel JSON:API makes it easy to return errors to the client — either
as responses, or by throwing exceptions. In addition, the exception
renderer you added to your exception handler during
installation takes care of
converting standard Laravel exceptions to JSON:API error responses
if the client has sent an Accept: application/vnd.api+json header.

# Error Objects

Use our LaravelJsonApiCoreDocumentError object to create a JSON:API
error object. The easiest way to construct an error object is using the
static fromArray method. For example:

The fromArray method accepts all the error object members
defined in the specification. (opens new window)

Alternatively, if you want to use setters, use the static make method
to fluently construct your error object:

The available setters are:

  • setAboutLink
  • setCode
  • setDetail
  • setId
  • setLinks
  • setMeta
  • setStatus
  • setSource
  • setSourceParameter
  • setSourcePointer
  • setTitle

# Error Lists

If you need to return multiple errors at once, use our
LaravelJsonApiCoreDocumentErrorList class. This accepts any number
of error objects to its constructor. For example:

Use the push method to add errors after constructing the error list:

# Responses

Both the Error and ErrorList classes implement Laravel’s Responsable
interface. This means you can return them directly from controller actions
and they will be converted to a JSON:API error response.

If you need to customise the error response, then you need to use our
LaravelJsonApiCoreResponsesErrorResponse class. Either create
a new one, passing in the Error or ErrorList object:

Or alternatively, use the prepareResponse method on either the Error
or ErrorList object:

The ErrorResponse class has all the helper methods
required to customise both the headers and the JSON:API document that
is returned in the response.

For example, if we were adding a header and meta to our response:

# HTTP Status

The JSON:API specification says:

When a server encounters multiple problems for a single request,
the most generally applicable HTTP error code SHOULD be used in the response.
For instance, 400 Bad Request might be appropriate for multiple 4xx errors
or 500 Internal Server Error might be appropriate for multiple 5xx errors.

Our ErrorResponse class takes care of calculating the HTTP status for you.

If there is only one error, or all the errors have the same status, then
the response status will match this status.

If you have multiple errors with different statuses, the response status
will be 400 Bad Request if the error objects only have 4xx status codes.
If there are any 5xx status codes, the response status will be
500 Internal Server Error.

If the response has no error objects, or none of the error objects have a
status, then the response will have a 500 Internal Server Error status.

If you want the response to have a specific HTTP status, use the
withStatus method. For example:

# JSON:API Exceptions

Our LaravelJsonApiCoreExceptionsJsonApiException allows you to terminate
processing of a request by throwing an exception with JSON:API errors
attached.

The exception expects its first argument to be either an Error or an
ErrorList object. For example:

The JsonApiException class has all the helper methods
required to customise both the headers and the JSON:API document that
is returned in the response. Use the static make method if you need to
call any of these methods. For example:

There is also a handy static error method. This allows you to fluently
construct an exception for a single error, providing either an Error
object or an array. For example:

# Helper Methods

The JsonApiException class has a number of helper methods:

  • is4xx
  • is5xx
  • getErrors

# is4xx

Returns true if the HTTP status code is a client error, i.e. in the 400-499
range.

# is5xx

Returns true if the HTTP status code is a server error, i.e. in the 500-599
range.

# getErrors

Use the getErrors() method to retrieve the JSON:API error objects from the
exception. For example, if we wanted to log the errors:

# Validation Errors

Our implementation of resource requests and
query parameter requests already takes
care of converting Laravel validation error messages to JSON:API errors.

If however you have a scenario where you want to convert a failed validator
to JSON:API errors manually, we provide the ability to do this.

You will need to resolve an instance of LaravelJsonApiValidationFactory
out of the service container. For example, you could use the app helper,
or use dependency injection by type-hinting it in a constructor of a service.

Once you have the factory instance, use the createErrors method,
providing it with the validator instance. For example, in a controller
action:

The object this returns is Responsable — so you can return it directly
from a controller action. If you want to convert it to an error response,
use our prepareResponse pattern as follows:

# Source Pointers

By default this process will convert validation error keys to JSON source
pointers. For example, if you have a failed message for the foo.bar
value, the resulting error object will have a source pointer of
/foo/bar.

If you need to prefix the pointer value, use the withSourcePrefix method.
The following example would convert foo.bar to /data/attributes/foo/bar:

If you need to fully customise how the validation key should be converted,
provide a Closure to the withPointers method:

# Error Rendering

As described in the installation instructions,
the following should have been added to the register method on your
application’s exception handler:

The Laravel exception handler already takes care of converting exceptions to
either application/json or text/html responses. Our exception handler
effectively adds JSON:API error responses as a third media type. If the
client has sent a request with an Accept header of application/vnd.api+json,
then they will receive the exception response as a JSON:API error response —
even if the endpoint they are hitting is not one of your JSON:API server
endpoints.

WARNING

There are some scenarios where the Laravel exception handler does not call
any registered renderables. For example, if an exception implements Laravel’s
Responsable interface, our exception parser will not be invoked as the handler
uses the Responsable::toResponse() method on the exception to generate a
response.

# JSON Responses

If a client encounters an exception when using an Accept header of
application/json, they will still receive Laravel’s default JSON exception
response, rather than a JSON:API response.

If you want our exception parser to render JSON exception responses instead
of the default Laravel response, use the acceptsJson() method when registering
our exception parser:

# Middleware Responses

Sometimes you may want exceptions to be converted to JSON:API errors if the
current route has a particular middleware applied to it. The most common example
of this would be if you want JSON:API errors to always be rendered if the
current route has the api middleware.

In this scenario, use the acceptsMiddleware() method when registering our
exception parser. For example:

TIP

You can provide multiple middleware names to the acceptsMiddleware() method.
When you do this, it will match a route that contains any of the provided
middleware.

# Always Rendering JSON:API Errors

If you want our exception parser to always convert exceptions to JSON:API
errors, use the acceptsAll() helper method:

# Custom Rendering Logic

If you want your own logic for when a JSON:API exception response should be
rendered, pass a closure to the accept() method.

For example, let’s say we wanted our API to always return JSON:API exception
responses, regardless of what Accept header the client sent. We would use
the request is() method to check if the path is our API:

TIP

If you return false from the callback, the normal exception rendering logic
will run — meaning a client that has sent an Accept header with the JSON:API
media type will still receive a JSON:API response. This is semantically correct,
as the Accept header value should be respected.

# Converting Exceptions

Our exception parser is built so that you can easily add support for
custom exceptions to the JSON:API rendering process. The implementation works
using a pipeline, meaning you can add your own handlers for converting
exceptions to JSON:API errors.

For example, imagine our application had a PaymentFailed exception, that
we wanted to convert to JSON:API errors if thrown to the exception handler.
We would write the following class:

We can then add it to the JSON:API exception parser using either the
prepend or append method:

# Error Reporting

As described in the installation instructions,
the following should have been added to the $dontReport property on your
application’s exception handler:

This prevents our JsonApiException from being reported in your application’s
error log. This is a sensible starting position, as the JsonApiException
class is effectively a HTTP exception that needs to be rendered to the client.

However, this does mean that any JsonApiException that has a 5xx status
code (server-side error) will not be reported in your error log. Therefore,
an alternative is to use the helper methods on the JsonApiException class
to determine whether or not the exception should be reported.

To do this, we will use the reportable() method to register a callback
for the JSON:API exception class. (At the same time, we remove the exception
class from the $dontReport property.) For example, the following will stop
the propagation of JSON:API exceptions to the default logging stack if the
exception does not have a 5xx status:

In the following example, we log 4xx statuses as debug information, while
letting all other JSON:API exceptions propagate to the default logging stack:

REST API response format based on some of the best practices

Rest API Popular Endpoint Formats

https://api.example.com/v1/items

https://example.com/api/v1/items

Rest API Success Responses

1- GET — Get single item — HTTP Response Code: 200

    HTTP/1.1 200
    Content-Type: application/json

    {
        "id": 10,
        "name": "shirt",
        "color": "red",
        "price": "$23"
    }

2- GET — Get item list — HTTP Response Code: 200

    HTTP/1.1 200
    Pagination-Count: 100
    Pagination-Page: 5
    Pagination-Limit: 20
    Content-Type: application/json
    
    [
      {
        "id": 10,
        "name": "shirt",
        "color": "red",
        "price": "$123"
      },
      {
        "id": 11,
        "name": "coat",
        "color": "black",
        "price": "$2300"
      }
    ]

3- POST — Create a new item — HTTP Response Code: 201

    HTTP/1.1  201
    Location: /v1/items/12
    Content-Type: application/json
 
    {
      "message": "The item was created successfully"
    }

4- PUT — Update an item — HTTP Response Code: 200/204

If updated entity is to be sent after the update

    HTTP/1.1  200
    Content-Type: application/json
 
    {
        "id": 10,
        "name": "shirt",
        "color": "red",
        "price": "$23"
    }

If updated entity is not to be sent after the update

5- DELETE — Delete an item — HTTP Response Code: 204

Rest API Error Responses

1- GET — HTTP Response Code: 404

    HTTP/1.1  404
    Content-Type: application/json
 
    {
      "message": "The item does not exist"
    }

2- DELETE — HTTP Response Code: 404

    HTTP/1.1  404
    Content-Type: application/json
 
    {
      "message": "The item does not exist"
    }

3- POST — HTTP Response Code: 400

    HTTP/1.1  400
    Content-Type: application/json
    
    {
        "message": "Validation errors in your request", /* skip or optional error message */
        "errors": [
            {
                "message": "Oops! The value is invalid",
                "code": 34,
                "field": "email"
            },
            {
                "message": "Oops! The format is not correct",
                "code": 35,
                "field": "phoneNumber"
            }
        ]
    }

4- PUT — HTTP Response Code: 400/404

    HTTP/1.1  400
    Content-Type: application/json
    
    {
        "message": "Validation errors in your request", /* skip or optional error message */
        "errors": [
            {
                "message": "Oops! The format is not correct",
                "code": 35,
                "field": "phoneNumber"
            }
        ]
    }
    
    
    HTTP/1.1  404
    Content-Type: application/json
 
    {
      "message": "The item does not exist"
    }

5- VERB Unauthorized — HTTP Response Code: 401

    HTTP/1.1  401
    Content-Type: application/json
 
    {
      "message": "Authentication credentials were missing or incorrect"
    }

6- VERB Forbidden — HTTP Response Code: 403

    HTTP/1.1  403
    Content-Type: application/json
 
    {
      "message": "The request is understood, but it has been refused or access is not allowed"
    }

7- VERB Conflict — HTTP Response Code: 409

    HTTP/1.1  409
    Content-Type: application/json
 
    {
      "message": "Any message which should help the user to resolve the conflict"
    }

8- VERB Too Many Requests — HTTP Response Code: 429

    HTTP/1.1  429
    Content-Type: application/json
 
    {
      "message": "The request cannot be served due to the rate limit having been exhausted for the resource"
    }

9- VERB Internal Server Error — HTTP Response Code: 500

    HTTP/1.1  500
    Content-Type: application/json
 
    {
      "message": "Something is broken"
    }

10- VERB Service Unavailable — HTTP Response Code: 503

    HTTP/1.1  503
    Content-Type: application/json
 
    {
      "message": "The server is up, but overloaded with requests. Try again later!"
    }

Validation Error Formats

Validation error formats can be different depending on your requirements. Following are some other popular formats, other than the one used above.

    HTTP/1.1  400
    Content-Type: application/json
    
    {
        "message": "Validation errors in your request", /* skip or optional error message */
        "errors": {
            "email": [
                  "Oops! The email is invalid"
                ],
            "phoneNumber": [
                  "Oops! The phone number format is not correct"
                ]
        }
    }
    HTTP/1.1  400
    Content-Type: application/json
    
    {
        "message": "Validation errors in your request", /* skip or optional error message */
        "errors": {
            "email": [
              {
                "message": "Oops! The email is invalid",
                "code": 35
              }
            ],
            "phoneNumber": [
              {
                "message": "Oops! The phone number format is not correct",
                "code": 36
              }
            ]
        }
    }

References

Avoid using ‘X-‘ in custom headers: https://tools.ietf.org/html/rfc6648

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Js как изменить текст тега
  • Js как изменить стиль у класса
  • Js как изменить атрибут элемента
  • Js type error is not a function
  • Js throw error with object

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии