Json error status 200

The following document provides reference information about the status codes and error messages that are used in the Cloud Storage JSON API. For the page specific to the Cloud Storage XML API, see HTTP status and error codes for XML.

Stay organized with collections

Save and categorize content based on your preferences.

The following document provides reference information about the status codes
and error messages that are used in the Cloud Storage JSON API. For
the page specific to the Cloud Storage XML API, see
HTTP status and error codes for XML.

Error Response Format

Cloud Storage uses the standard HTTP error reporting format for the
JSON API. Successful requests return HTTP status codes in the 2xx range. Failed
requests return status codes in the 4xx and 5xx ranges. Requests that require a
redirect returns status codes in the 3xx range. Error responses usually include
a JSON document in the response body, which contains information about the
error.

The following examples show some common errors. Note that the header
information in the responses is omitted.

The following is an example of an error response you receive if you try to
list the buckets for a project but do not provide an authorization header.

401 Unauthorized

{
"error": {
 "errors": [
  {
   "domain": "global",
   "reason": "required",
   "message": "Login Required",
   "locationType": "header",
   "location": "Authorization"
  }
 ],
 "code": 401,
 "message": "Login Required"
 }
}

403 Forbidden

This is an example of an error response you receive if you try to list the
buckets of a non-existent project or one in which you don’t have permission
to list buckets.

403 Forbidden

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "forbidden",
    "message": "Forbidden"
    }
  ],
  "code": 403,
  "message": "Forbidden"
 }
}

404 Not Found

The following is an example of an error response you receive if you try to
retrieve an object that does not exist.

404 Not Found

{
"error": {
 "errors": [
  {
   "domain": "global",
   "reason": "notFound",
   "message": "Not Found"
  }
 ],
 "code": 404,
 "message": "Not Found"
 }
}

409 Conflict

The following is an example of an error response you receive if you try to
create a bucket using the name of a bucket you already own.

409 Conflict

{
"error": {
 "errors": [
  {
   "domain": "global",
   "reason": "conflict",
   "message": "You already own this bucket. Please select another name."
  }
 ],
 "code": 409,
 "message": "You already own this bucket. Please select another name."
 }
}

The following table describes the elements that can appear in the response body
of an error. Fields should be used together to help determine the problem.
Also, the example values given below are meant for illustration and are not an
exhaustive list of all possible values.

Element Description
code An HTTP status code value, without the textual description.

Example values include: 400 (Bad Request), 401 (Unauthorized), and 404 (Not Found).

error A container for the error information.
errors A container for the error details.
errors.domain The scope of the error. Example values include: global and push.
errors.location The specific item within the locationType that caused the error. For example, if you specify an invalid value for a parameter, the location will be the name of the parameter.

Example values include: Authorization, project, and projection.

errors.locationType The location or part of the request that caused the error. Use with location to pinpoint the error. For example, if you specify an invalid value for a parameter, the locationType will be parameter and the location will be the name of the parameter.

Example values include header and parameter.

errors.message Description of the error.

Example values include Invalid argument, Login required, and Required parameter: project.

errors.reason Example values include invalid, invalidParameter, and required.
message Description of the error. Same as errors.message.

HTTP Status and Error Codes

This section provides a non-exhaustive list of HTTP status and error codes that
the Cloud Storage JSON API uses. The 1xx Informational and 2xx
Success codes are not discussed here. For more information, see Response Status
Codes in RFC 7231 §6, RFC 7232 §4,
RFC 7233 §4, RFC 7235 §3, and RFC 6585.

302—Found

Reason Description
found Resource temporarily located elsewhere according to the Location header.

303—See Other

Reason Description
mediaDownloadRedirect When requesting a download using alt=media URL parameter, the direct URL path to use is prefixed by /download. If this is omitted, the service will issue this redirect with the appropriate media download path in the Location header.

304—Not Modified

Reason Description
notModified The conditional request would have been successful, but the condition was false, so no body was sent.

307—Temporary Redirect

Reason Description
temporaryRedirect Resource temporarily located elsewhere according to the Location header. Among other reasons, this can occur when cookie-based authentication is being used, e.g., when using the Storage Browser, and it receives a request to download content.

308—Resume Incomplete

Description
Indicates an incomplete resumable upload and provides the range of bytes already received by Cloud Storage. Responses with this status do not contain a body.

400—Bad Request

[Domain.]Reason Description
badRequest The request cannot be completed based on your current Cloud Storage settings. For example, you cannot lock a retention policy if the requested bucket doesn’t have a retention policy, and you cannot set ACLs if the requested bucket has uniform bucket-level access enabled.
badRequestException The retention period on a locked bucket cannot be reduced.
cloudKmsBadKey Bad Cloud KMS key.
cloudKmsCannotChangeKeyName Cloud KMS key name cannot be changed.
cloudKmsDecryptionKeyNotFound Resource’s Cloud KMS decryption key not found.
cloudKmsDisabledKey Cloud KMS key is disabled, destroyed, or scheduled to be destroyed.
cloudKmsEncryptionKeyNotFound Cloud KMS encryption key not found.
cloudKmsKeyLocationNotAllowed Cloud KMS key location not allowed.
corsRequestWithXOrigin CORS request contains an XD3 X-Origin header.
customerEncryptionAlgorithmIsInvalid Missing an encryption algorithm, or the provided algorithm is not «AE256.»
customerEncryptionKeyFormatIsInvalid Missing an encryption key, or it is not Base64 encoded, or it does not meet the required length of the encryption algorithm.
customerEncryptionKeyIsIncorrect The provided encryption key is incorrect.
customerEncryptionKeySha256IsInvalid Missing a SHA256 hash of the encryption key, or it is not Base64 encoded, or it does not match the encryption key.
invalidAltValue The value for the alt URL parameter was not recognized.
invalidArgument The value for one of fields in the request body was invalid.
invalidParameter The value for one of the URL parameters was invalid. In addition to normal URL parameter validation, any URL parameters that have a corresponding value in provided JSON request bodies must match if they are both specified. If using JSONP, you will get this error if you provide an alt parameter that is not json.
notDownload Uploads or normal API request was sent to a /download/* path. Use the same path, but without the /download prefix.
notUpload Downloads or normal API request was sent to a /upload/* path. Use the same path, but without the /upload prefix.
parseError Could not parse the body of the request according to the provided Content-Type.
push.channelIdInvalid Channel id must match the following regular expression: [A-Za-z0-9\-_\+/=]+
push.channelIdNotUnique storage.objects.watchAll‘s id property must be unique across channels.
push.webhookUrlNoHostOrAddress storage.objects.watchAll‘s address property must contain a valid URL.
push.webhookUrlNotHttps storage.objects.watchAll‘s address property must be an HTTPS URL.
required A required URL parameter or required request body JSON property is missing.
resourceIsEncryptedWithCustomerEncryptionKey The resource is encrypted with a customer-supplied encryption key, but the request did not provide one.
resourceNotEncryptedWithCustomerEncryptionKey The resource is not encrypted with a customer-supplied encryption key, but the request provided one.
turnedDown A request was made to an API version that has been turned down. Clients will need to update to a supported version.
userProjectInvalid The user project specified in the request is invalid, either because it is a malformed project id or because it refers to a non-existent project.
userProjectMissing The requested bucket has Requester Pays enabled, the requester is not an owner of the bucket, and no user project was present in the request.
wrongUrlForUpload storage.objects.insert must be invoked as an upload rather than a metadata.

401—Unauthorized

[Domain.]Reason Description
AuthenticationRequiredRequesterPays Access to a Requester Pays bucket requires authentication.
authError This error indicates a problem with the authorization provided in the request to Cloud Storage. The following are some situations where that will occur:

  • The OAuth access token has expired and needs to be refreshed. This can be avoided by refreshing the access token early, but code can also catch this error, refresh the token and retry automatically.
  • Multiple non-matching authorizations were provided; choose one mode only.
  • The OAuth access token’s bound project does not match the project associated with the provided developer key.
  • The Authorization header was of an unrecognized format or uses an unsupported credential type.
lockedDomainExpired When downloading content from a cookie-authenticated site, e.g., using the Storage Browser, the response will redirect to a temporary domain. This error will occur if access to said domain occurs after the domain expires. Issue the original request again, and receive a new redirect.
required Access to a non-public method that requires authorization was made, but none was provided in the Authorization header or through other means.

403—Forbidden

[Domain.]Reason Description
accountDisabled The account associated with the project that owns the bucket or object has been disabled. Check the Google Cloud console to see if there is a problem with billing, and if not, contact account support.
countryBlocked The Cloud Storage JSON API is restricted by law from operating with certain countries.
forbidden According to access control policy, the current user does not have access to perform the requested action. This code applies even if the resource being acted on doesn’t exist.
insufficientPermissions According to access control policy, the current user does not have access to perform the requested action. This code applies even if the resource being acted on doesn’t exist.
objectUnderActiveHold Object replacement or deletion is not allowed due to an active hold on the object.
retentionPolicyNotMet Object replacement or deletion is not allowed until the object meets the retention period set by the retention policy on the bucket.
sslRequired Requests to this API require SSL.
stopChannelCallerNotOwner Calls to storage.channels.stop require that the caller own the channel.
UserProjectAccessDenied The requester is not authorized to use the project specified in the userProject portion of the request. The requester must have the serviceusage.services.use permission for the specified project.
UserProjectAccountProblem There is a problem with the project used in the request that prevents the operation from completing successfully. One issue could be billing. Check the billing page to see if you have a past due balance or if the credit card (or other payment mechanism) on your account is expired. For project creation, see the Projects page in the Google Cloud console. For other problems, see the Resources and Support page.

404—Not Found

Reason Description
notFound Either there is no API method associated with the URL path of the request, or the request refers to one or more resources that were not found.

405—Method Not Allowed

Reason Description
methodNotAllowed The HTTP verb is not supported by the URL endpoint used in the request. This can happen, for example, when using the wrong verb with the /upload or /download URLs.

408—Request Timeout

Reason Description
uploadBrokenConnection The request timed out. Please try again using truncated exponential backoff.

409—Conflict

Reason Description
conflict A request to change a resource, usually a storage.*.update or storage.*.patch method, failed to commit the change due to a conflicting concurrent change to the same resource. The request can be retried, though care should be taken to consider the new state of the resource to avoid blind replacement of another agent’s changes.

410—Gone

Description
You have attempted to use a resumable upload session or rewrite token that is no longer available. If the reported status code was not successful and you still wish to complete the upload or rewrite, you must start a new session.

411—Length Required

Description
You must provide the Content-Length HTTP header. This error has no response body.

412—Precondition Failed

Reason Description
conditionNotMet At least one of the pre-conditions you specified did not hold.
orgPolicyConstraintFailed Request violates an OrgPolicy constraint.

413—Payload Too Large

Reason Description
uploadTooLarge This error arises if you:

  • Attempt to upload an object larger than 5 TiB.
  • Attempt a Copy request that does not complete within 30 seconds and involves an object larger than 2.5 GiB. In this case, use the Rewrite method instead.

416—Requested Range Not Satisfiable

Reason Description
requestedRangeNotSatisfiable The requested Range cannot be satisfied.

429—Too Many Requests

[Domain.]Reason Description
usageLimits.rateLimitExceeded A Cloud Storage JSON API usage limit was exceeded. If your application tries to use more than its limit, additional requests will fail. Throttle your client’s requests, and/or use truncated exponential backoff.

499—Client Closed Request

Description
The resumable upload was cancelled at the client’s request prior to completion. This error has no response body.

500—Internal Server Error

Reason Description
backendError We encountered an internal error. Please try again using truncated exponential backoff.
internalError We encountered an internal error. Please try again using truncated exponential backoff.

502—Bad Gateway

This error is generated when there was difficulty reaching an internal service.
It is not formatted with a JSON document. Please try again using
truncated exponential backoff.

503—Service Unavailable

Reason Description
backendError We encountered an internal error. Please try again using truncated exponential backoff.

504—Gateway Timeout

This error is generated when there was difficulty reaching an internal service.
It is not formatted with a JSON document. Please try again using
truncated exponential backoff.

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2023-02-07 UTC.

Some Background

REST APIs use the Status-Line part of an HTTP response message to inform clients of their request’s overarching result.
RFC 2616 defines the Status-Line syntax as shown below:

Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF

A great amount of applications are using Restful APIs that are based on the HTTP protocol for connecting their clients. In all the calls, the server and the endpoint at the client both return a call status to the client which can be in the form of:

  • The success of API call.
  • Failure of API call.

In both the cases, it is necessary to let the client know so that they can proceed to the next step. In the case of a successful API call they can proceed to the next call or whatever their intent was in the first place but in the case of latter they will be forced to modify their call so that the failed call can be recovered.

RestCase

To enable the best user experience for your customer, it is necessary on the part of the developers to make excellent error messages that can help their client to know what they want to do with the information they get. An excellent error message is precise and lets the user know about the nature of the error so that they can figure their way out of it.

A good error message also allows the developers to get their way out of the failed call.

Next step is to know what error messages to integrate into your framework so that the clients on the end point and the developers at the server are constantly made aware of the situation which they are in. in order to do so, the rule of thumb is to keep the error messages to a minimum and only incorporate those error messages which are helpful.

HTTP defines over 40 standard status codes that can be used to convey the results of a client’s request. The status codes are divided into the five categories presented here:

  • 1xx: Informational — Communicates transfer protocol-level information
  • 2xx: Success -Indicates that the client’s request was accepted successfully.
  • 3xx: Redirection — Indicates that the client must take some additional action in order to complete their request.
  • 4xx: Client Error — This category of error status codes points the finger at clients.
  • 5xx: Server Error — The server takes responsibility for these error status codes.

HTTP & REST

If you would ask me 5 years ago about HTTP Status codes I would guess that the talk is about web sites, status 404 meaning that some page was not found and etc. But today when someone asks me about HTTP Status codes, it is 99.9% refers to REST API web services development. I have lots of experience in both areas (Website development, REST API web services development) and it is sometimes hard to come to a conclusion about what and how use the errors in REST APIs.

There are some cases where this status code is always returned, even if there was an error that occurred. Some believe that returning status codes other than 200 is not good as the client did reach your REST API and got response.

Proper use of the status codes will help with your REST API management and REST API workflow management.

If for example the user asked for “account” and that account was not found there are 2 options to use for returning an error to the user:

  • Return 200 OK Status and in the body return a json containing explanation that the account was not found.

  • Return 404 not found status.
    The first solution opens up a question whether the user should work a bit harder to parse the json received and to see whether that json contains error or not.

  • There is also a third solution: Return 400 Error — Client Error. I will explain a bit later why this is my favorite solution.

It is understandable that for the user it is easier to check the status code of 404 without any parsing work to do.

I my opinion this solution is actually miss-use of the HTTP protocol

We did reach the REST API, we did got response from the REST API, what happens if the users misspells the URL of the REST API – he will get the 404 status but that is returned not by the REST API itself.

I think that these solutions should be interesting to explore and to see the benefits of one versus the other.

There is also one more solution that is basically my favorite – this one is a combination of the first two solutions, he is also gives better Restful API services automatic testing support because only several status codes are returned, I will try to explain about it.

Error handling Overview

Error responses should include a common HTTP status code, message for the developer, message for the end-user (when appropriate), internal error code (corresponding to some specific internally determined ID), links where developers can find more info. For example:

‘{ «status» : 400,
«developerMessage» : «Verbose, plain language description of the problem. Provide developers suggestions about how to solve their problems here»,
«userMessage» : «This is a message that can be passed along to end-users, if needed.»,
«errorCode» : «444444»,
«moreInfo» : «http://www.example.gov/developer/path/to/help/for/444444,
http://tests.org/node/444444»,
}’

How to think about errors in a pragmatic way with REST?
Apigee’s blog post that talks about this issue compares 3 top API providers.

REST API Error Codes

Facebook

No matter what happens on a Facebook request, you get back the 200 status code — everything is OK. Many error messages also push down into the HTTP response. Here they also throw an #803 error but with no information about what #803 is or how to react to it.

Twilio

Twilio does a great job aligning errors with HTTP status codes. Like Facebook, they provide a more granular error message but with a link that takes you to the documentation. Community commenting and discussion on the documentation helps to build a body of information and adds context for developers experiencing these errors.

SimpleGeo

Provides error codes but with no additional value in the payload.

Error Handling — Best Practises

First of all: Use HTTP status codes! but don’t overuse them.
Use HTTP status codes and try to map them cleanly to relevant standard-based codes.
There are over 70 HTTP status codes. However, most developers don’t have all 70 memorized. So if you choose status codes that are not very common you will force application developers away from building their apps and over to wikipedia to figure out what you’re trying to tell them.

Therefore, most API providers use a small subset.
For example, the Google GData API uses only 10 status codes, Netflix uses 9, and Digg, only 8.

REST API Status Codes Subset

How many status codes should you use for your API?

When you boil it down, there are really only 3 outcomes in the interaction between an app and an API:

  • Everything worked
  • The application did something wrong
  • The API did something wrong

Start by using the following 3 codes. If you need more, add them. But you shouldn’t go beyond 8.

  • 200 — OK
  • 400 — Bad Request
  • 500 — Internal Server Error

Please keep in mind the following rules when using these status codes:

200 (OK) must not be used to communicate errors in the response body

Always make proper use of the HTTP response status codes as specified by the rules in this section. In particular, a REST API must not be compromised in an effort to accommodate less sophisticated HTTP clients.

400 (Bad Request) may be used to indicate nonspecific failure

400 is the generic client-side error status, used when no other 4xx error code is appropriate. For errors in the 4xx category, the response body may contain a document describing the client’s error (unless the request method was HEAD).

500 (Internal Server Error) should be used to indicate API malfunction 500 is the generic REST API error response.

Most web frameworks automatically respond with this response status code whenever they execute some request handler code that raises an exception. A 500 error is never the client’s fault and therefore it is reasonable for the client to retry the exact same request that triggered this response, and hope to get a different response.

If you’re not comfortable reducing all your error conditions to these 3, try adding some more but do not go beyond 8:

  • 401 — Unauthorized
  • 403 — Forbidden
  • 404 — Not Found

Please keep in mind the following rules when using these status codes:

A 401 error response indicates that the client tried to operate on a protected resource without providing the proper authorization. It may have provided the wrong credentials or none at all.

403 (Forbidden) should be used to forbid access regardless of authorization state

A 403 error response indicates that the client’s request is formed correctly, but the REST API refuses to honor it. A 403 response is not a case of insufficient client credentials; that would be 401 (“Unauthorized”). REST APIs use 403 to enforce application-level permissions. For example, a client may be authorized to interact with some, but not all of a REST API’s resources. If the client attempts a resource interaction that is outside of its permitted scope, the REST API should respond with 403.

404 (Not Found) must be used when a client’s URI cannot be mapped to a resource

The 404 error status code indicates that the REST API can’t map the client’s URI to a resource.

RestCase

Conclusion

I believe that the best solution to handle errors in a REST API web services is the third option, in short:
Use three simple, common response codes indicating (1) success, (2) failure due to client-side problem, (3) failure due to server-side problem:

  • 200 — OK
  • 400 — Bad Request (Client Error) — A json with error more details should return to the client.
  • 401 — Unauthorized
  • 500 — Internal Server Error — A json with an error should return to the client only when there is no security risk by doing that.

I think that this solution can also ease the client to handle only these 4 status codes and when getting either 400 or 500 code he should take the response message and parse it in order to see what is the problem exactly and on the other hand the REST API service is simple enough.

The decision of choosing which error messages to incorporate and which to leave is based on sheer insight and intuition. For example: if an app and API only has three outcomes which are; everything worked, the application did not work properly and API did not respond properly then you are only concerned with three error codes. By putting in unnecessary codes, you will only distract the users and force them to consult Google, Wikipedia and other websites.

Most important thing in the case of an error code is that it should be descriptive and it should offer two outputs:

  • A plain descriptive sentence explaining the situation in the most precise manner.
  • An ‘if-then’ situation where the user knows what to do with the error message once it is returned in an API call.

The error message returned in the result of the API call should be very descriptive and verbal. A code is preferred by the client who is well versed in the programming and web language but in the case of most clients they find it hard to get the code.

As I stated before, 404 is a bit problematic status when talking about Restful APIs. Does this status means that the resource was not found? or that there is not mapping to the requested resource? Everyone can decide what to use and where :)

Status

This page presents the latest published version of JSON:API, which is
currently version 1.1. New versions of JSON:API will
always be backwards compatible
using a never remove, only add strategy.
Additions can be proposed in our discussion forum.

If you catch an error in the specification’s text, or if you write an
implementation, please let us know by opening an issue or pull request at our
GitHub repository.

Introduction

JSON:API is a specification for how a client should request that resources be
fetched or modified, and how a server should respond to those requests. JSON:API
can be easily extended with extensions and profiles.

JSON:API is designed to minimize both the number of requests and the amount of
data transmitted between clients and servers. This efficiency is achieved
without compromising readability, flexibility, or discoverability.

JSON:API requires use of the JSON:API media type
(application/vnd.api+json)
for exchanging data.

Semantics

All document members, query parameters, and processing rules defined by
this specification are collectively called “specification semantics”.

Certain document members, query parameters, and processing rules are reserved
for implementors to define at their discretion. These are called “implementation
semantics”.

All other semantics are reserved for potential future use by this specification.

Conventions

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”,
“SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this
document are to be interpreted as described in
BCP 14
[RFC2119]
[RFC8174]
when, and only when, they appear in all capitals, as shown here.

The JSON:API media type is
application/vnd.api+json.

Media Type Parameters

The JSON:API specification supports two media type parameters: ext and
profile, which are used to specify extensions and profiles, respectively.

Note: A media type parameter is an extra piece of information that can
accompany a media type. For example, in the header
Content-Type: text/html; charset="utf-8", the media type is text/html and
charset is a parameter.

Extensions

Extensions provide a means to “extend” the base specification by defining
additional specification semantics.

Extensions cannot alter or remove specification semantics, nor can they specify
implementation semantics.

Profiles

Profiles provide a means to share a particular usage of the specification among
implementations.

Profiles can specify implementation semantics, but cannot alter,
add to, or remove specification semantics.

Rules for Media Type Parameters

The JSON:API media type MUST NOT be specified with any media type parameters
other than ext and profile. The ext parameter is used to support
extensions and the profile parameter is used to support profiles.

Extensions and profiles are each uniquely identified by a
URI. Visiting an extension’s or a
profile’s URI SHOULD return documentation that describes its usage. The
values of the ext and profile parameters MUST equal a space-separated
(U+0020 SPACE, “ “) list of extension or profile URIs, respectively.

Note: When serializing the ext or profile media type parameters, the HTTP
specification requires that parameter values be surrounded by quotation marks
(U+0022 QUOTATION MARK, “»”).

Rules for Extensions

An extension MAY impose additional processing rules or further restrictions
and it MAY define new object members as described below.

An extension MUST NOT lessen or remove any processing rules, restrictions or
object member requirements defined in this specification or other extensions.

An extension MAY define new members within the document structure defined by
this specification. The rules for extension member names are covered
below.

An extension MAY define new query parameters. The rules for extension-defined
query parameters are covered below.

When an extension defines new query parameters or document members, the
extension MUST define a namespace to guarantee that extensions will never
conflict with current or future versions of this specification. A namespace
MUST meet all of the following conditions:

  • A namespace MUST contain at least one character.
  • A namespace MUST contain only these characters:
    • U+0061 to U+007A, “a-z”
    • U+0041 to U+005A, “A-Z”
    • U+0030 to U+0039, “0-9”

An extension MUST NOT define more than one namespace. The namespace used for
all query parameters and document members MUST be the same for any given
extension.

In the following example, an extension with the namespace version has
specified a resource object member version:id to support per-resource
versioning. This member might appear as follows:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json; ext="https://jsonapi.org/ext/version"

// ...
{
  "type": "articles",
  "id": "1",
  "version:id": "42",
  "attributes": {
    "title": "Rails is Omakase"
  }
}
// ...

Rules for Profiles

The rules for profile usage are dictated by RFC
6906.

A profile MAY define document members and processing rules that are reserved
for implementors.

A profile MUST NOT define any query parameters.

A profile MUST NOT alter or remove processing rules that have been defined
by this specification or by an extension. However, a profile
MAY define processing rules for query parameters whose processing rules
have been reserved for implementors to define at their discretion.

For example, a profile could define rules for interpreting the filter query
parameter, but it could not specify that relationship
names in the include query parameter are
space-separated instead of dot-separated.

Unlike extensions, profiles do not need to define a namespace for document
members because profiles cannot define specification semantics and thus cannot
conflict with current or future versions of this specification. However, it is
possible for profiles to conflict with other profiles. Therefore, it is the
responsibility of implementors to ensure that they do not support conflicting
profiles.

In the following example, a profile has defined a timestamps
attribute. According to the profile, the attribute must be an
object containing a created member and a modified member and these members’
values must use the RFC 3339 format.
With such a profile applied, a response might appear as follows:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json; profile="https://example.com/resource-timestamps"

// ...
{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "Rails is Omakase",
    "timestamps": {
      "created": "2020-07-21T12:09:00Z",
      "modified": "2020-07-30T10:19:01Z"
    }
  }
}
// ...

Content Negotiation

Universal Responsibilities

Clients and servers MUST send all JSON:API payloads using the JSON:API media
type in the Content-Type header.

Clients and servers MUST specify the ext media type parameter in the
Content-Type header when they have applied one or more extensions to a
JSON:API document.

Clients and servers MUST specify the profile media type parameters in the
Content-Type header when they have applied one or more profiles to a JSON:API
document.

Client Responsibilities

When processing a JSON:API response document, clients MUST ignore any
parameters other than ext and profile parameters in the server’s
Content-Type header.

A client MAY use the ext media type parameter in an Accept header to
require that a server apply all the specified extensions to the response
document.

A client MAY use the profile media type parameter in an Accept header
to request that the server apply one or more profiles to the response document.

Note: A client is allowed to send more than one acceptable media type in the
Accept header, including multiple instances of the JSON:API media type. This
allows clients to request different combinations of the ext and profile
media type parameters. A client can use quality values
to indicate that some combinations are less preferable than others. Media types
specified without a qvalue are equally preferable to each other, regardless of
their order, and are always considered more preferable than a media type with a
qvalue less than 1.

Server Responsibilities

If a request specifies the Content-Type header with the JSON:API media type,
servers MUST respond with a 415 Unsupported Media Type status code if
that media type contains any media type parameters other than ext or
profile.

If a request specifies the Content-Type header with an instance of
the JSON:API media type modified by the ext media type parameter and that
parameter contains an unsupported extension URI, the server MUST respond
with a 415 Unsupported Media Type status code.

Note: JSON:API servers that do not support version 1.1 of this specification
will respond with a 415 Unsupported Media Type client error if the ext or
profile media type parameter is present.

If a request’s Accept header contains an instance of the JSON:API media type,
servers MUST ignore instances of that media type which are modified by a
media type parameter other than ext or profile. If all instances of that
media type are modified with a media type parameter other than ext or profile,
servers MUST respond with a 406 Not Acceptable status code. If every
instance of that media type is modified by the ext parameter and each contains
at least one unsupported extension URI, the server MUST also respond with a
406 Not Acceptable.

If the profile parameter is received, a server SHOULD attempt to apply any
requested profile(s) to its response. A server MUST ignore any profiles
that it does not recognize.

Note: The above rules guarantee strict agreement on extensions between the
client and server, while the application of profiles is left to the discretion
of the server.

Servers that support the ext or profile media type parameters SHOULD
specify the Vary header with Accept as one of its values. This applies to
responses with and without any profiles or extensions applied.

Note: Some HTTP intermediaries (e.g. CDNs) may ignore the Vary header
unless specifically configured to respect it.

Document Structure

This section describes the structure of a JSON:API document, which is identified
by the JSON:API media type. JSON:API documents are
defined in JavaScript Object Notation (JSON) [RFC8259].

Although the same media type is used for both request and response documents,
certain aspects are only applicable to one or the other. These differences are
called out below.

Extensions MAY define new members within the document structure. These
members MUST comply with the naming requirements specified
below.

Unless otherwise noted, objects defined by this specification or any applied
extensions MUST NOT contain any additional members. Client and server
implementations MUST ignore non-compliant members.

Note: These conditions allow this specification to evolve through additive
changes.

Top Level

A JSON object MUST be at the root of every JSON:API request and response
document containing data. This object defines a document’s “top level”.

A document MUST contain at least one of the following top-level members:

  • data: the document’s “primary data”.
  • errors: an array of error objects.
  • meta: a meta object that contains non-standard
    meta-information.
  • a member defined by an applied extension.

The members data and errors MUST NOT coexist in the same document.

A document MAY contain any of these top-level members:

  • jsonapi: an object describing the server’s implementation.
  • links: a links object related to the primary data.
  • included: an array of resource objects that are related to the primary
    data and/or each other (“included resources”).

If a document does not contain a top-level data key, the included member
MUST NOT be present either.

The top-level links object MAY contain the following members:

  • self: the link that generated the current response document. If a
    document has extensions or profiles applied to it, this link SHOULD be
    represented by a link object with the type target attribute specifying the
    JSON:API media type with all applicable parameters.
  • related: a related resource link when the primary data represents a
    resource relationship.
  • describedby: a link to a description document (e.g. OpenAPI or JSON
    Schema) for the current document.
  • pagination links for the primary data.

Note: The self link in the top-level links object allows a client to
refresh the data represented by the current response document. The client
should be able to use the provided link without applying any additional
information. Therefore the link must contain the query parameters provided
by the client to generate the response document. This includes but is not
limited to query parameters used for [inclusion of related resources][fetching resources],
[sparse fieldsets][fetching sparse fieldsets], [sorting][fetching sorting],
[pagination][fetching pagination] and [filtering][fetching filtering].

The document’s “primary data” is a representation of the resource or collection
of resources targeted by a request.

Primary data MUST be either:

  • a single resource object, a single resource identifier object, or null,
    for requests that target single resources
  • an array of resource objects, an array of
    resource identifier objects, or
    an empty array ([]), for requests that target resource collections

For example, the following primary data is a single resource object:

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      // ... this article's attributes
    },
    "relationships": {
      // ... this article's relationships
    }
  }
}

The following primary data is a single resource identifier object that
references the same resource:

{
  "data": {
    "type": "articles",
    "id": "1"
  }
}

A logical collection of resources MUST be represented as an array, even if
it only contains one item or is empty.

Resource Objects

“Resource objects” appear in a JSON:API document to represent resources.

A resource object MUST contain at least the following top-level members:

  • id
  • type

Exception: The id member is not required when the resource object originates
at the client and represents a new resource to be created on the server. In that
case, a client MAY include a lid member to uniquely identify the resource
by type locally within the document.

In addition, a resource object MAY contain any of these top-level members:

  • attributes: an attributes object representing some of the resource’s data.
  • relationships: a relationships object describing relationships between
    the resource and other JSON:API resources.
  • links: a links object containing links related to the resource.
  • meta: a meta object containing non-standard meta-information about a
    resource that can not be represented as an attribute or relationship.

Here’s how an article (i.e. a resource of type “articles”) might appear in a document:

// ...
{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "Rails is Omakase"
  },
  "relationships": {
    "author": {
      "links": {
        "self": "/articles/1/relationships/author",
        "related": "/articles/1/author"
      },
      "data": { "type": "people", "id": "9" }
    }
  }
}
// ...

Identification

As noted above, every resource object MUST contain a
type member. Every resource object MUST also contain an id member,
except when the resource object originates at the client and represents a new
resource to be created on the server. If id is omitted due to this exception,
a lid member MAY be included to uniquely identify the resource by type
locally within the document. The value of the lid member MUST be
identical for every representation of the resource in the document, including
resource identifier objects.

The values of the id, type, and lid members MUST be strings.

Within a given API, each resource object’s type and id pair MUST
identify a single, unique resource. (The set of URIs controlled by a server,
or multiple servers acting as one, constitute an API.)

The type member is used to describe resource objects that share common
attributes and relationships.

The values of type members MUST adhere to the same constraints as
member names.

Note: This spec is agnostic about inflection rules, so the value of type
can be either plural or singular. However, the same value should be used
consistently throughout an implementation.

Fields

A resource object’s attributes and its relationships are collectively called
its “fields”.

Fields for a resource object MUST share a common namespace with each
other and with type and id. In other words, a resource can not have an
attribute and relationship with the same name, nor can it have an attribute
or relationship named type or id.

Attributes

The value of the attributes key MUST be an object (an “attributes
object”). Members of the attributes object (“attributes”) represent information
about the resource object in which it’s defined.

Attributes may contain any valid JSON value, including complex data structures
involving JSON objects and arrays.

Keys that reference related resources (e.g. author_id) SHOULD NOT appear
as attributes. Instead, relationships SHOULD be used.

Note: See fields and member names for more restrictions on this container.

Relationships

The value of the relationships key MUST be an object (a “relationships
object”). Each member of a relationships object represents
a “relationship” from the resource object
in which it has been defined to other resource objects.

Relationships may be to-one or to-many.

A relationship’s name is given by its key. The value at that key MUST be an
object (“relationship object”).

A “relationship object” MUST contain at least one of the following:

  • links: a links object containing at least one of the following:
    • self: a link for the relationship itself (a “relationship link”). This
      link allows the client to directly manipulate the relationship. For example,
      removing an author through an article’s relationship URL would disconnect
      the person from the article without deleting the people resource itself.
      When fetched successfully, this link returns the linkage
      for the related resources as its primary data.
      (See Fetching Relationships.)
    • related: a related resource link
    • a member defined by an applied extension.
  • data: resource linkage
  • meta: a meta object that contains non-standard meta-information about the
    relationship.
  • a member defined by an applied extension.

A relationship object that represents a to-many relationship MAY also contain
pagination links under the links member, as described below. Any
pagination links in a relationship object MUST paginate the relationship
data, not the related resources.

Note: See fields and member names for more restrictions on this container.

A “related resource link” provides access to resource objects linked
in a relationship. When fetched, the related resource object(s)
are returned as the response’s primary data.

For example, an article’s comments relationship could
specify a link that returns a collection of comment resource objects
when retrieved through a GET request.

If present, a related resource link MUST reference a valid URL, even if the
relationship isn’t currently associated with any target resources. Additionally,
a related resource link MUST NOT change because its relationship’s content
changes.

Resource Linkage

Resource linkage in a compound document allows a client to link together all
of the included resource objects without having to GET any URLs via links.

Resource linkage MUST be represented as one of the following:

  • null for empty to-one relationships.
  • an empty array ([]) for empty to-many relationships.
  • a single resource identifier object for non-empty to-one relationships.
  • an array of resource identifier objects for non-empty to-many relationships.

Note: The spec does not impart meaning to order of resource identifier
objects in linkage arrays of to-many relationships, although implementations
may do that. Arrays of resource identifier objects may represent ordered
or unordered relationships, and both types can be mixed in one response
object.

For example, the following article is associated with an author:

// ...
{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "Rails is Omakase"
  },
  "relationships": {
    "author": {
      "links": {
        "self": "http://example.com/articles/1/relationships/author",
        "related": "http://example.com/articles/1/author"
      },
      "data": { "type": "people", "id": "9" }
    }
  },
  "links": {
    "self": "http://example.com/articles/1"
  }
}
// ...

The author relationship includes a link for the relationship itself (which
allows the client to change the related author directly), a related resource
link to fetch the resource objects, and linkage information.

Resource Links

The optional links member within each resource object contains links
related to the resource.

If present, this links object MAY contain a self link that
identifies the resource represented by the resource object.

// ...
{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "Rails is Omakase"
  },
  "links": {
    "self": "http://example.com/articles/1"
  }
}
// ...

A server MUST respond to a GET request to the specified URL with a
response that includes the resource as the primary data.

Resource Identifier Objects

A “resource identifier object” is an object that identifies an individual
resource.

A “resource identifier object” MUST contain a type member. It MUST
also contain an id member, except when it represents a new resource to be
created on the server. In this case, a lid member MUST be included that
identifies the new resource.

The values of the id, type, and lid members MUST be strings.

A “resource identifier object” MAY also include a meta member, whose value is a meta object that
contains non-standard meta-information.

Compound Documents

Servers MAY allow responses that include related resources along with the
requested primary resources. Such responses are called “compound documents”.

In a compound document, all included resources MUST be represented as an
array of resource objects in a top-level included member.

Every included resource object MUST be identified via a chain of
relationships originating in a document’s primary data. This means that
compound documents require “full linkage” and that no resource object can be
included without a direct or indirect relationship to the document’s primary
data.

The only exception to the full linkage requirement is when relationship fields
that would otherwise contain linkage data are excluded due to
sparse fieldsets requested by the client.

A complete example document with multiple included relationships:

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!"
    },
    "links": {
      "self": "http://example.com/articles/1"
    },
    "relationships": {
      "author": {
        "links": {
          "self": "http://example.com/articles/1/relationships/author",
          "related": "http://example.com/articles/1/author"
        },
        "data": { "type": "people", "id": "9" }
      },
      "comments": {
        "links": {
          "self": "http://example.com/articles/1/relationships/comments",
          "related": "http://example.com/articles/1/comments"
        },
        "data": [
          { "type": "comments", "id": "5" },
          { "type": "comments", "id": "12" }
        ]
      }
    }
  }],
  "included": [{
    "type": "people",
    "id": "9",
    "attributes": {
      "firstName": "Dan",
      "lastName": "Gebhardt",
      "twitter": "dgeb"
    },
    "links": {
      "self": "http://example.com/people/9"
    }
  }, {
    "type": "comments",
    "id": "5",
    "attributes": {
      "body": "First!"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "2" }
      }
    },
    "links": {
      "self": "http://example.com/comments/5"
    }
  }, {
    "type": "comments",
    "id": "12",
    "attributes": {
      "body": "I like XML better"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "9" }
      }
    },
    "links": {
      "self": "http://example.com/comments/12"
    }
  }]
}

A compound document MUST NOT include more than one resource object for
each type and id pair.

Note: In a single document, you can think of the type and id as a
composite key that uniquely references resource objects in another part of
the document.

Note: For resources that do not contain an id member but do contain a lid,
the lid is sufficient to establish resource identity and thus linkage between
resource objects and resource identifier objects throughout the document.

Note: This approach ensures that a single canonical resource object is
returned with each response, even when the same resource is referenced
multiple times.

Meta Information

Where specified, a meta member can be used to include non-standard
meta-information. The value of each meta member MUST be an object (a
“meta object”).

Any members MAY be specified within meta objects.

For example:

{
  "meta": {
    "copyright": "Copyright 2015 Example Corp.",
    "authors": [
      "Yehuda Katz",
      "Steve Klabnik",
      "Dan Gebhardt",
      "Tyler Kellen"
    ]
  },
  "data": {
    // ...
  }
}

Links

Where specified, a links member can be used to represent links. The value
of this member MUST be an object (a “links object”).

Within this object, a link MUST be represented as either:

  • a string whose value is a URI-reference [RFC3986 Section 4.1]
    pointing to the link’s target,
  • a link object or
  • null if the link does not exist.

A link’s relation type SHOULD be inferred from the name of the link unless the
link is a link object and the link object has a rel member.

A link’s context is the top-level object, resource
object, or relationship object in which it
appears.

In the example below, the self link is a string whereas the related link is
a link object. The related link object provides additional information
about the targeted related resource collection as well as a schema that serves
as a description document for that collection:

"links": {
  "self": "http://example.com/articles/1/relationships/comments",
  "related": {
    "href": "http://example.com/articles/1/comments",
    "title": "Comments",
    "describedby": "http://example.com/schemas/article-comments",
    "meta": {
      "count": 10
    }
  }
}

Link objects

A “link object” is an object that represents a web link.

A link object MUST contain the following member:

  • href: a string whose value is a URI-reference [RFC3986 Section 4.1]
    pointing to the link’s target.

A link object MAY also contain any of the following members:

  • rel: a string indicating the link’s relation type. The string MUST be a
    valid link relation type.
  • describedby: a link to a description document (e.g. OpenAPI or JSON
    Schema) for the link target.
  • title: a string which serves as a label for the destination of a link
    such that it can be used as a human-readable identifier (e.g., a menu
    entry).
  • type: a string indicating the media type of the link’s target.
  • hreflang: a string or an array of strings indicating the language(s) of the
    link’s target. An array of strings indicates that the link’s target is
    available in multiple languages. Each string MUST be a valid language tag
    [RFC5646].
  • meta: a meta object containing non-standard meta-information about the
    link.

Note: the type and hreflang members are only hints; the target resource
is not guaranteed to be available in the indicated media type or language
when the link is actually followed.

JSON:API Object

A JSON:API document MAY include information about its implementation
under a top level jsonapi member. If present, the value of the jsonapi
member MUST be an object (a “jsonapi object”).

The jsonapi object MAY contain any of the following members:

  • version — whose value is a string indicating the highest JSON:API version
    supported.
  • ext — an array of URIs for all applied extensions.
  • profile — an array of URIs for all applied profiles.
  • meta — a meta object that contains non-standard meta-information.

Clients and servers MUST NOT use an ext or profile member for content
negotiation. Content negotiation MUST only happen based on media type
parameters in Content-Type header.

A simple example appears below:

{
  "jsonapi": {
    "version": "1.1",
    "ext": [
      "https://jsonapi.org/ext/atomic"
    ],
    "profile": [
      "http://example.com/profiles/flexible-pagination",
      "http://example.com/profiles/resource-versioning"
    ]
  }
}

If the version member is not present, clients should assume the server
implements at least version 1.0 of the specification.

Note: Because JSON:API is committed to making additive changes only, the
version string primarily indicates which new features a server may support.

Member Names

Implementation and profile defined member names used in a JSON:API document
MUST be treated as case sensitive by clients and servers, and they MUST
meet all of the following conditions:

  • Member names MUST contain at least one character.
  • Member names MUST contain only the allowed characters listed below.
  • Member names MUST start and end with a “globally allowed character”,
    as defined below.

To enable an easy mapping of member names to URLs, it is RECOMMENDED that
member names use only non-reserved, URL safe characters specified in RFC 3986.

Allowed Characters

The following “globally allowed characters” MAY be used anywhere in a member name:

  • U+0061 to U+007A, “a-z”
  • U+0041 to U+005A, “A-Z”
  • U+0030 to U+0039, “0-9”
  • U+0080 and above (non-ASCII Unicode characters; not recommended, not URL safe)

Additionally, the following characters are allowed in member names, except as the
first or last character:

  • U+002D HYPHEN-MINUS, “-“
  • U+005F LOW LINE, “_”
  • U+0020 SPACE, “ “ (not recommended, not URL safe)

Reserved Characters

The following characters MUST NOT be used in implementation and
profile defined member names:

  • U+002B PLUS SIGN, “+” (has overloaded meaning in URL query strings)
  • U+002C COMMA, “,” (used as a separator between relationship paths)
  • U+002E PERIOD, “.” (used as a separator within relationship paths)
  • U+005B LEFT SQUARE BRACKET, “[” (used in query parameter families)
  • U+005D RIGHT SQUARE BRACKET, “]” (used in query parameter families)
  • U+0021 EXCLAMATION MARK, “!”
  • U+0022 QUOTATION MARK, ‘”’
  • U+0023 NUMBER SIGN, “#”
  • U+0024 DOLLAR SIGN, “$”
  • U+0025 PERCENT SIGN, “%”
  • U+0026 AMPERSAND, “&”
  • U+0027 APOSTROPHE, “’”
  • U+0028 LEFT PARENTHESIS, “(“
  • U+0029 RIGHT PARENTHESIS, “)”
  • U+002A ASTERISK, “*”
  • U+002F SOLIDUS, “/”
  • U+003A COLON, “:”
  • U+003B SEMICOLON, “;”
  • U+003C LESS-THAN SIGN, “<”
  • U+003D EQUALS SIGN, “=”
  • U+003E GREATER-THAN SIGN, “>”
  • U+003F QUESTION MARK, “?”
  • U+0040 COMMERCIAL AT, “@” (except as first character in @-Members)
  • U+005C REVERSE SOLIDUS, “”
  • U+005E CIRCUMFLEX ACCENT, “^”
  • U+0060 GRAVE ACCENT, “`”
  • U+007B LEFT CURLY BRACKET, “{“
  • U+007C VERTICAL LINE, “|”
  • U+007D RIGHT CURLY BRACKET, “}”
  • U+007E TILDE, “~”
  • U+007F DELETE
  • U+0000 to U+001F (C0 Controls)

@-Members

Member names MAY also begin with an at sign (U+0040 COMMERCIAL AT, “@”).
Members named this way are called “@-Members”. @-Members MAY appear
anywhere in a document.

This specification provides no guidance on the meaning or usage of @-Members,
which are considered to be implementation semantics. @-Members
MUST be ignored when interpreting this specification’s definitions and
processing instructions given outside of this subsection. For example, an
attribute is defined above as any member of the attributes object.
However, because @-Members must be ignored when interpreting that definition, an
@-Member that occurs in an attributes object is not an attribute.

Note: Among other things, “@” members can be used to add JSON-LD data to a
JSON:API document. Such documents should be served with an extra header
to convey to JSON-LD clients that they contain JSON-LD data.

Extension Members

The name of every new member introduced by an extension MUST be prefixed
with the extension’s namespace followed by a colon (:).
The remainder of the name MUST adhere to the rules for implementation
defined member names.

Fetching Data

Data, including resources and relationships, can be fetched by sending a
GET request to an endpoint.

Responses can be further refined with the optional features described below.

Fetching Resources

A server MUST support fetching resource data for every URL provided as:

  • a self link as part of the top-level links object
  • a self link as part of a resource-level links object
  • a related link as part of a relationship-level links object

For example, the following request fetches a collection of articles:

GET /articles HTTP/1.1
Accept: application/vnd.api+json

The following request fetches an article:

GET /articles/1 HTTP/1.1
Accept: application/vnd.api+json

And the following request fetches an article’s author:

GET /articles/1/author HTTP/1.1
Accept: application/vnd.api+json

Responses

200 OK

A server MUST respond to a successful request to fetch an individual
resource or resource collection with a 200 OK response.

A server MUST respond to a successful request to fetch a resource
collection with an array of resource objects or an empty array ([]) as
the response document’s primary data.

For example, a GET request to a collection of articles could return:

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

{
  "links": {
    "self": "http://example.com/articles"
  },
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!"
    }
  }, {
    "type": "articles",
    "id": "2",
    "attributes": {
      "title": "Rails is Omakase"
    }
  }]
}

A similar response representing an empty collection would be:

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

{
  "links": {
    "self": "http://example.com/articles"
  },
  "data": []
}

A server MUST respond to a successful request to fetch an individual
resource with a resource object or null provided as
the response document’s primary data.

null is only an appropriate response when the requested URL is one that
might correspond to a single resource, but doesn’t currently.

Note: Consider, for example, a request to fetch a to-one related resource link.
This request would respond with null when the relationship is empty (such that
the link is corresponding to no resources) but with the single related resource’s
resource object otherwise.

For example, a GET request to an individual article could return:

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

{
  "links": {
    "self": "http://example.com/articles/1"
  },
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!"
    },
    "relationships": {
      "author": {
        "links": {
          "related": "http://example.com/articles/1/author"
        }
      }
    }
  }
}

If the above article’s author is missing, then a GET request to that related
resource would return:

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

{
  "links": {
    "self": "http://example.com/articles/1/author"
  },
  "data": null
}
404 Not Found

A server MUST respond with 404 Not Found when processing a request to
fetch a single resource that does not exist, except when the request warrants a
200 OK response with null as the primary data (as described above).

Other Responses

A server MAY respond with other HTTP status codes.

A server MAY include error details with error responses.

A server MUST prepare responses, and a client MUST interpret
responses, in accordance with
HTTP semantics.

Fetching Relationships

A server MUST support fetching relationship data for every relationship URL
provided as a self link as part of a relationship’s links object.

For example, the following request fetches data about an article’s comments:

GET /articles/1/relationships/comments HTTP/1.1
Accept: application/vnd.api+json

And the following request fetches data about an article’s author:

GET /articles/1/relationships/author HTTP/1.1
Accept: application/vnd.api+json

Responses

200 OK

A server MUST respond to a successful request to fetch a relationship
with a 200 OK response.

The primary data in the response document MUST match the appropriate
value for resource linkage, as described above for
relationship objects.

The top-level links object MAY contain self and related links,
as described above for relationship objects.

For example, a GET request to a URL from a to-one relationship link could
return:

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

{
  "links": {
    "self": "/articles/1/relationships/author",
    "related": "/articles/1/author"
  },
  "data": {
    "type": "people",
    "id": "12"
  }
}

If the above relationship is empty, then a GET request to the same URL would
return:

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

{
  "links": {
    "self": "/articles/1/relationships/author",
    "related": "/articles/1/author"
  },
  "data": null
}

A GET request to a URL from a to-many relationship link could return:

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

{
  "links": {
    "self": "/articles/1/relationships/tags",
    "related": "/articles/1/tags"
  },
  "data": [
    { "type": "tags", "id": "2" },
    { "type": "tags", "id": "3" }
  ]
}

If the above relationship is empty, then a GET request to the same URL would
return:

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

{
  "links": {
    "self": "/articles/1/relationships/tags",
    "related": "/articles/1/tags"
  },
  "data": []
}
404 Not Found

A server MUST return 404 Not Found when processing a request to fetch
a relationship link URL that does not exist.

Note: This can happen when the parent resource of the relationship
does not exist. For example, when /articles/1 does not exist, request to
/articles/1/relationships/tags returns 404 Not Found.

If a relationship link URL exists but the relationship is empty, then
200 OK MUST be returned, as described above.

Other Responses

A server MAY respond with other HTTP status codes.

A server MAY include error details with error responses.

A server MUST prepare responses, and a client MUST interpret
responses, in accordance with
HTTP semantics.

An endpoint MAY return resources related to the primary data by default.

An endpoint MAY also support an include query parameter to allow the
client to customize which related resources should be returned.

If an endpoint does not support the include parameter, it MUST respond
with 400 Bad Request to any requests that include it.

If an endpoint supports the include parameter and a client supplies it:

  • The server’s response MUST be a compound document with an included key — even if that included key holds an empty array (because the requested relationships are empty).
  • The server MUST NOT include unrequested resource objects in the included
    section of the compound document.

The value of the include parameter MUST be a comma-separated (U+002C
COMMA, “,”) list of relationship paths. A relationship path is a dot-separated
(U+002E FULL-STOP, “.”) list of relationship names. An empty
value indicates that no related resources should be returned.

If a server is unable to identify a relationship path or does not support
inclusion of resources from a path, it MUST respond with 400 Bad Request.

Note: For example, a relationship path could be comments.author, where
comments is a relationship listed under a articles resource object, and
author is a relationship listed under a comments resource object.

For instance, comments could be requested with an article:

GET /articles/1?include=comments HTTP/1.1
Accept: application/vnd.api+json

In order to request resources related to other resources, a dot-separated path
for each relationship name can be specified:

GET /articles/1?include=comments.author HTTP/1.1
Accept: application/vnd.api+json

Note: Because compound documents require full linkage
(except when relationship linkage is excluded by sparse fieldsets), intermediate
resources in a multi-part path must be returned along with the leaf nodes. For
example, a response to a request for comments.author should include comments
as well as the author of each of those comments.

Note: A server may choose to expose a deeply nested relationship such as
comments.author as a direct relationship with an alternative name such as
commentAuthors. This would allow a client to request
/articles/1?include=commentAuthors instead of
/articles/1?include=comments.author. By exposing the nested relationship with
an alternative name, the server can still provide full linkage in compound
documents without including potentially unwanted intermediate resources.

Multiple related resources can be requested in a comma-separated list:

GET /articles/1?include=comments.author,ratings HTTP/1.1
Accept: application/vnd.api+json

Furthermore, related resources can be requested from a relationship endpoint:

GET /articles/1/relationships/comments?include=comments.author HTTP/1.1
Accept: application/vnd.api+json

In this case, the primary data would be a collection of
resource identifier objects that represent linkage to comments for an article,
while the full comments and comment authors would be returned as included data.

Note: This section applies to any endpoint that responds with primary
data, regardless of the request type. For instance, a server could support
the inclusion of related resources along with a POST request to create a
resource or relationship.

Sparse Fieldsets

A client MAY request that an endpoint return only specific fields in the
response on a per-type basis by including a fields[TYPE] query parameter.

The value of any fields[TYPE] parameter MUST be a comma-separated (U+002C
COMMA, “,”) list that refers to the name(s) of the fields to be returned.
An empty value indicates that no fields should be returned.

If a client requests a restricted set of fields for a given resource type,
an endpoint MUST NOT include additional fields in resource objects of
that type in its response.

If a client does not specify the set of fields for a given resource type, the
server MAY send all fields, a subset of fields, or no fields for that
resource type.

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

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

Note: This section applies to any endpoint that responds with resources as
primary or included data, regardless of the request type. For instance, a
server could support sparse fieldsets along with a POST request to create
a resource.

Sorting

A server MAY choose to support requests to sort resource collections
according to one or more criteria (“sort fields”).

Note: Although recommended, sort fields do not necessarily need to
correspond to resource attribute and relationship names.

Note: It is recommended that dot-separated (U+002E FULL-STOP, “.”) sort
fields be used to request sorting based upon relationship attributes. For
example, a sort field of author.name could be used to request that the
primary data be sorted based upon the name attribute of the author
relationship.

An endpoint MAY support requests to sort the primary data with a sort
query parameter. The value for sort MUST represent sort fields.

GET /people?sort=age HTTP/1.1
Accept: application/vnd.api+json

An endpoint MAY support multiple sort fields by allowing comma-separated
(U+002C COMMA, “,”) sort fields. Sort fields SHOULD be applied in the
order specified.

GET /people?sort=age,name HTTP/1.1
Accept: application/vnd.api+json

The sort order for each sort field MUST be ascending unless it is prefixed
with a minus (U+002D HYPHEN-MINUS, “-“), in which case it MUST be descending.

GET /articles?sort=-created,title HTTP/1.1
Accept: application/vnd.api+json

The above example should return the newest articles first. Any articles
created on the same date will then be sorted by their title in ascending
alphabetical order.

If the server does not support sorting as specified in the query parameter
sort, it MUST return 400 Bad Request.

If sorting is supported by the server and requested by the client via query
parameter sort, the server MUST return elements of the top-level
data array of the response ordered according to the criteria specified.
The server MAY apply default sorting rules to top-level data if
request parameter sort is not specified.

Note: This section applies to any endpoint that responds with a resource
collection as primary data, regardless of the request type.

A server MAY choose to limit the number of resources returned in a response
to a subset (“page”) of the whole set available.

A server MAY provide links to traverse a paginated data set (“pagination
links”).

Pagination links MUST appear in the links object that corresponds to a
collection. To paginate the primary data, supply pagination links in the
top-level links object. To paginate an included collection returned in
a compound document, supply pagination links in the corresponding links
object.

The following keys MUST be used for pagination links:

  • first: the first page of data
  • last: the last page of data
  • prev: the previous page of data
  • next: the next page of data

Keys MUST either be omitted or have a null value to indicate that a
particular link is unavailable.

Concepts of order, as expressed in the naming of pagination links, MUST
remain consistent with JSON:API’s sorting rules.

The page query parameter family is reserved for pagination. Servers and
clients SHOULD use these parameters for pagination operations.

Note: JSON API is agnostic about the pagination strategy used by a server, but
the page query parameter family can be used regardless of the strategy
employed. For example, a page-based strategy might use query parameters such
as page[number] and page[size], while a cursor-based strategy might use
page[cursor].

Note: This section applies to any endpoint that responds with a resource
collection as primary data, regardless of the request type.

Filtering

The filter query parameter family is reserved for filtering data. Servers
and clients SHOULD use these parameters for filtering operations.

Note: JSON API is agnostic about the strategies supported by a server.

Creating, Updating and Deleting Resources

A server MAY allow resources of a given type to be created. It MAY
also allow existing resources to be modified or deleted.

A request MUST completely succeed or fail (in a single “transaction”). No
partial updates are allowed.

Note: The type member is required in every resource object throughout requests and
responses in JSON:API. There are some cases, such as when POSTing to an
endpoint representing heterogeneous data, when the type could not be inferred
from the endpoint. However, picking and choosing when it is required would be
confusing; it would be hard to remember when it was required and when it was
not. Therefore, to improve consistency and minimize confusion, type is
always required.

Creating Resources

A resource can be created by sending a POST request to a URL that represents
a collection of resources. The request MUST include a single resource object
as primary data. The resource object MUST contain at least a type member.

For instance, a new photo might be created with the following request:

POST /photos HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "photos",
    "attributes": {
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    },
    "relationships": {
      "photographer": {
        "data": { "type": "people", "id": "9" }
      }
    }
  }
}

If a relationship is provided in the relationships member of the
resource object, its value MUST be a relationship object with a data
member. The value of this key represents the linkage the new resource is to
have.

Client-Generated IDs

A server MAY accept a client-generated ID along with a request to create
a resource. An ID MUST be specified with an id key, the value of
which MUST be a universally unique identifier. The client SHOULD use
a properly generated and formatted UUID as described in RFC 4122
[RFC4122].

NOTE: In some use-cases, such as importing data from another source, it
may be possible to use something other than a UUID that is still guaranteed
to be globally unique. Do not use anything other than a UUID unless you are
100% confident that the strategy you are using indeed generates globally
unique identifiers.

For example:

POST /photos HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "photos",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    }
  }
}

A server MUST return 403 Forbidden in response to an unsupported request
to create a resource with a client-generated ID.

Responses

201 Created

If the requested resource has been created successfully and the server changes
the resource in any way (for example, by assigning an id), the server MUST
return a 201 Created response and a document that contains the resource as
primary data.

The response SHOULD include a Location header identifying the location
of the newly created resource, in order to comply with RFC
7231.

If the resource object returned by the response contains a self key in its
links member and a Location header is provided, the value of the self
member MUST match the value of the Location header.

HTTP/1.1 201 Created
Location: http://example.com/photos/550e8400-e29b-41d4-a716-446655440000
Content-Type: application/vnd.api+json

{
  "data": {
    "type": "photos",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    },
    "links": {
      "self": "http://example.com/photos/550e8400-e29b-41d4-a716-446655440000"
    }
  }
}

A server MAY return a 201 Created response with a document that contains
no primary data if the requested resource has been created successfully and the
server does not change the resource in any way (for example, by assigning an
id or createdAt attribute). Other top-level members, such as meta, could
be included in the response document.

Note: Only servers that accept Client-Generated
IDs can avoid assigning an id to a new resource.

202 Accepted

If a request to create a resource has been accepted for processing, but the
processing has not been completed by the time the server responds, the
server MUST return a 202 Accepted status code.

204 No Content

If the requested resource has been created successfully and the server does not
change the resource in any way (for example, by assigning an id or createdAt
attribute), the server MUST return either a 201 Created status code and
response document (as described above) or a 204 No Content status code with no
response document.

403 Forbidden

A server MAY return 403 Forbidden in response to an unsupported request
to create a resource.

404 Not Found

A server MUST return 404 Not Found when processing a request that
references a related resource that does not exist.

409 Conflict

A server MUST return 409 Conflict when processing a POST request to
create a resource with a client-generated ID that already exists.

A server MUST return 409 Conflict when processing a POST request in
which the resource object’s type is not among the type(s) that constitute the
collection represented by the endpoint.

A server SHOULD include error details and provide enough information to
recognize the source of the conflict.

Other Responses

A server MAY respond with other HTTP status codes.

A server MAY include error details with error responses.

A server MUST prepare responses, and a client MUST interpret
responses, in accordance with
HTTP semantics.

Updating Resources

A resource can be updated by sending a PATCH request to the URL that
represents the resource.

The URL for a resource can be obtained in the self link of the resource
object. Alternatively, when a GET request returns a single resource object as
primary data, the same request URL can be used for updates.

The PATCH request MUST include a single resource object as primary data.
The resource object MUST contain type and id members.

For example:

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

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "To TDD or Not"
    }
  }
}

Updating a Resource’s Attributes

Any or all of a resource’s attributes MAY be included in the resource
object included in a PATCH request.

If a request does not include all of the attributes for a resource, the server
MUST interpret the missing attributes as if they were included with their
current values. The server MUST NOT interpret missing attributes as null
values.

For example, the following PATCH request is interpreted as a request to
update only the title and text attributes of an article:

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

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "To TDD or Not",
      "text": "TLDR; It's complicated... but check your test coverage regardless."
    }
  }
}

Updating a Resource’s Relationships

Any or all of a resource’s relationships MAY be included in the resource
object included in a PATCH request.

If a request does not include all of the relationships for a resource, the server
MUST interpret the missing relationships as if they were included with their
current values. It MUST NOT interpret them as null or empty values.

If a relationship is provided in the relationships member of a resource
object in a PATCH request, its value MUST be a relationship object
with a data member. The relationship’s value will be replaced with the
value specified in this member.

For instance, the following PATCH request will update the author relationship of an article:

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

{
  "data": {
    "type": "articles",
    "id": "1",
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "1" }
      }
    }
  }
}

Likewise, the following PATCH request performs a complete replacement of
the tags for an article:

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

{
  "data": {
    "type": "articles",
    "id": "1",
    "relationships": {
      "tags": {
        "data": [
          { "type": "tags", "id": "2" },
          { "type": "tags", "id": "3" }
        ]
      }
    }
  }
}

A server MAY reject an attempt to do a full replacement of a to-many
relationship. In such a case, the server MUST reject the entire update,
and return a 403 Forbidden response.

Note: Since full replacement may be a very dangerous operation, a server
may choose to disallow it. For example, a server may reject full replacement if
it has not provided the client with the full list of associated objects, and
does not want to allow deletion of records the client has not seen.

Responses

200 OK

If a server accepts an update but also changes the targeted resource in ways
other than those specified by the request (for example, updating the
updatedAt attribute or a computed sha), it MUST return a 200 OK
response and a document that contains the updated resource as primary data.

A server MAY return a 200 OK response with a document that contains no
primary data if an update is successful and the server does not change the
targeted resource in ways other than those specified by the request. Other
top-level members, such as meta, could be included in the response document.

202 Accepted

If an update request has been accepted for processing, but the processing
has not been completed by the time the server responds, the server MUST
return a 202 Accepted status code.

204 No Content

If an update is successful and the server doesn’t change the targeted
resource in ways other than those specified by the request, the server
MUST return either a 200 OK status code and response document (as
described above) or a 204 No Content status code with no response document.

403 Forbidden

A server MUST return 403 Forbidden in response to an unsupported request
to update a resource or relationship.

404 Not Found

A server MUST return 404 Not Found when processing a request to modify
a resource that does not exist.

A server MUST return 404 Not Found when processing a request that
references a related resource that does not exist.

409 Conflict

A server MAY return 409 Conflict when processing a PATCH request to
update a resource if that update would violate other server-enforced
constraints (such as a uniqueness constraint on a property other than id).

A server MUST return 409 Conflict when processing a PATCH request in
which the resource object’s type or id do not match the server’s endpoint.

A server SHOULD include error details and provide enough information to
recognize the source of the conflict.

Other Responses

A server MAY respond with other HTTP status codes.

A server MAY include error details with error responses.

A server MUST prepare responses, and a client MUST interpret
responses, in accordance with
HTTP semantics.

Updating Relationships

Although relationships can be modified along with resources (as described
above), JSON:API also supports updating of relationships independently at
URLs from relationship links.

Note: Relationships are updated without exposing the underlying server
semantics, such as foreign keys. Furthermore, relationships can be updated
without necessarily affecting the related resources. For example, if an article
has many authors, it is possible to remove one of the authors from the article
without deleting the person itself. Similarly, if an article has many tags, it
is possible to add or remove tags. Under the hood on the server, the first
of these examples might be implemented with a foreign key, while the second
could be implemented with a join table, but the JSON:API protocol would be
the same in both cases.

Note: A server may choose to delete the underlying resource if a
relationship is deleted (as a garbage collection measure).

Updating To-One Relationships

A to-one relationship can be updated by sending a PATCH request to a URL
from a to-one relationship link.

The PATCH request MUST include a top-level member named data containing
one of:

  • a resource identifier object corresponding to the new related resource.
  • null, to remove the relationship.

For example, the following request updates the author of an article:

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

{
  "data": { "type": "people", "id": "12" }
}

And the following request clears the author of the same article:

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

{
  "data": null
}

If the relationship is updated successfully then the server MUST return
a successful response.

Updating To-Many Relationships

A to-many relationship can be updated by sending a PATCH, POST, or
DELETE request to a URL from a to-many relationship link.

For all request types, the body MUST contain a data member whose value
is an empty array or an array of resource identifier objects.

If a client makes a PATCH request to a URL from a to-many
relationship link, the server MUST either completely
replace every member of the relationship, return an appropriate error response
if some resources cannot be found or accessed, or return a 403 Forbidden
response if complete replacement is not allowed by the server.

For example, the following request replaces every tag for an article:

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

{
  "data": [
    { "type": "tags", "id": "2" },
    { "type": "tags", "id": "3" }
  ]
}

And the following request clears every tag for an article:

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

{
  "data": []
}

If a client makes a POST request to a URL from a
relationship link, the server MUST add the specified
members to the relationship unless they are already present. If a given type
and id is already in the relationship, the server MUST NOT add it again.

Note: This matches the semantics of databases that use foreign keys for
has-many relationships. Document-based storage should check the has-many
relationship before appending to avoid duplicates.

If all of the specified resources can be added to, or are already present
in, the relationship then the server MUST return a successful response.

Note: This approach ensures that a request is successful if the server’s
state matches the requested state, and helps avoid pointless race conditions
caused by multiple clients making the same changes to a relationship.

In the following example, the comment with ID 123 is added to the list of
comments for the article with ID 1:

POST /articles/1/relationships/comments HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": [
    { "type": "comments", "id": "123" }
  ]
}

If the client makes a DELETE request to a URL from a
relationship link the server MUST delete the specified
members from the relationship or return a 403 Forbidden response. If all of
the specified resources are able to be removed from, or are already missing
from, the relationship then the server MUST return a successful response.

Note: As described above for POST requests, this approach helps avoid
pointless race conditions between multiple clients making the same changes.

Relationship members are specified in the same way as in the POST request.

In the following example, comments with IDs of 12 and 13 are removed
from the list of comments for the article with ID 1:

DELETE /articles/1/relationships/comments HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": [
    { "type": "comments", "id": "12" },
    { "type": "comments", "id": "13" }
  ]
}

Note: RFC 7231 specifies that a DELETE request may include a body, but
that a server may reject the request. This spec defines the semantics of a
server, and we are defining its semantics for JSON:API.

Responses

200 OK

If a server accepts an update but also changes the targeted relationship in
other ways than those specified by the request, it MUST return a 200 OK
response and a document that includes the updated relationship data as its
primary data.

A server MAY return a 200 OK response with a document that contains no
primary data if an update is successful and the server does not change the
targeted relationship in ways other than those specified by the request. Other
top-level members, such as meta, could be included in the response document.

202 Accepted

If a relationship update request has been accepted for processing, but the
processing has not been completed by the time the server responds, the
server MUST return a 202 Accepted status code.

204 No Content

If an update is successful and the server doesn’t change the targeted
relationship in ways other than those specified by the request, the server
MUST return either a 200 OK status code and response document (as
described above) or a 204 No Content status code with no response document.

Note: This is the appropriate response to a POST request sent to a URL
from a to-many relationship link when that relationship already
exists. It is also the appropriate response to a DELETE request sent to a URL
from a to-many relationship link when that relationship does
not exist.

403 Forbidden

A server MUST return 403 Forbidden in response to an unsupported request
to update a relationship.

Other Responses

A server MAY respond with other HTTP status codes.

A server MAY include error details with error responses.

A server MUST prepare responses, and a client MUST interpret
responses, in accordance with
HTTP semantics.

Deleting Resources

A resource can be deleted by sending a DELETE request to the URL
that represents the resource:

DELETE /photos/1 HTTP/1.1
Accept: application/vnd.api+json

Responses

200 OK

A server MAY return a 200 OK response with a document that contains no
primary data if a deletion request is successful. Other top-level members, such
as meta, could be included in the response document.

202 Accepted

If a deletion request has been accepted for processing, but the processing has
not been completed by the time the server responds, the server MUST
return a 202 Accepted status code.

204 No Content

If a deletion request is successful, the server MUST return either a 200
OK
status code and response document (as described above) or a 204 No Content
status code with no response document.

404 NOT FOUND

A server SHOULD return a 404 Not Found status code if a deletion request fails
due to the resource not existing.

Other Responses

A server MAY respond with other HTTP status codes.

A server MAY include error details with error responses.

A server MUST prepare responses, and a client MUST interpret
responses, in accordance with
HTTP semantics.

Query Parameters

Query Parameter Families

Although “query parameter” is a common term in everyday web development, it is
not a well-standardized concept. Therefore, JSON:API provides its own
definition of a query parameter.

For the most part, JSON:API’s definition coincides with colloquial usage, and its
details can be safely ignored. However, one important consequence of this
definition is that a URL like the following is considered to have two distinct
query parameters:

/?page[offset]=0&page[limit]=10

The two parameters are named page[offset] and page[limit]; there is no
single page parameter.

In practice, however, parameters like page[offset] and page[limit] are
usually defined and processed together, and it’s convenient to refer to them
collectively. Therefore, JSON:API introduces the concept of a query parameter
family.

A “query parameter family” is the set of all query parameters whose name starts
with a “base name”, followed by zero or more instances of empty square brackets
(i.e. []) or square-bracketed legal member names. The family is referred to
by its base name.

For example, the filter query parameter family includes parameters named:
filter, filter[x], filter[], filter[x][], filter[][], filter[x][y],
etc. However, filter[_] is not a valid parameter name in the family, because
_ is not a valid member name.

Extension-Specific Query Parameters

The base name of every query parameter introduced by an extension MUST be
prefixed with the extension’s namespace followed by a colon (:). The
remainder of the base name MUST contain only the characters [a-z] (U+0061
to U+007A, “a-z”).

Implementation-Specific Query Parameters

Implementations MAY support custom query parameters. However, the names of
these query parameters MUST come from a family
whose base name is a legal member name and also contains at least
one non a-z character (i.e., outside U+0061 to U+007A).

It is RECOMMENDED that a capital letter (e.g. camelCasing) be used to
satisfy the above requirement.

If a server encounters a query parameter that does not follow the naming
conventions above, or the server does not know how to process it as a query
parameter from this specification, it MUST return 400 Bad Request.

Note: By forbidding the use of query parameters that contain only the characters
[a-z], JSON:API is reserving the ability to standardize additional query
parameters later without conflicting with existing implementations.

Errors

Processing Errors

A server MAY choose to stop processing as soon as a problem is encountered,
or it MAY continue processing and encounter multiple problems. For instance,
a server might process multiple attributes and then return multiple validation
problems in a single response.

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.

Error Objects

Error objects provide additional information about problems encountered while
performing an operation. Error objects MUST be returned as an array
keyed by errors in the top level of a JSON:API document.

An error object MAY have the following members, and MUST contain at
least one of:

  • id: a unique identifier for this particular occurrence of the problem.
  • links: a links object that MAY contain the following members:
    • about: a link that leads to further details about this
      particular occurrence of the problem. When derefenced, this URI SHOULD
      return a human-readable description of the error.
    • type: a link that identifies the type of error that this
      particular error is an instance of. This URI SHOULD be dereferencable to
      a human-readable explanation of the general error.
  • status: the HTTP status code applicable to this problem, expressed as a
    string value. This SHOULD be provided.
  • code: an application-specific error code, expressed as a string value.
  • title: a short, human-readable summary of the problem that SHOULD NOT
    change from occurrence to occurrence of the problem, except for purposes of
    localization.
  • detail: a human-readable explanation specific to this occurrence of the
    problem. Like title, this field’s value can be localized.
  • source: an object containing references to the primary source of the error.
    It SHOULD include one of the following members or be omitted:

    • pointer: a JSON Pointer [RFC6901]
      to the value in the request document that caused the error [e.g. "/data"
      for a primary data object, or "/data/attributes/title" for a specific
      attribute]. This MUST point to a value in the request document that
      exists; if it doesn’t, the client SHOULD simply ignore the pointer.
    • parameter: a string indicating which URI query parameter caused
      the error.
    • header: a string indicating the name of a single request header which
      caused the error.
  • meta: a meta object containing non-standard meta-information about the
    error.

Appendix

Query Parameters Details

Parsing/Serialization

A query parameter is a name–value pair extracted from, or serialized into, a
URI’s query string.

To extract the query parameters from a URI, an implementation MUST run the
URI’s query string, excluding the leading question mark, through the
application/x-www-form-urlencoded parsing algorithm,
with one exception: JSON:API allows the specification that defines a query
parameter’s usage to provide its own rules for parsing the parameter’s value
from the value bytes identified in steps 3.2 and and 3.3 of the application/x-www-form-urlencoded
parsing algorithm. The resulting value might not be a string.

Note: In general, the query string parsing built in to servers and browsers
will match the process specified above, so most implementations do not need
to worry about this.

The application/x-www-form-urlencoded format is referenced because it is
the basis for the a=b&c=d style that almost all query strings use today.

However, application/x-www-form-urlencoded parsing contains the bizarre
historical artifact that + characters must be treated as spaces, and it
requires that all values be percent-decoded during parsing, which makes it
impossible to use RFC 3986 delimiter characters
as delimiters. These issues motivate the exception that JSON:API defines above.

Similarly, to serialize a query parameter into a URI, an implementation MUST
use the the application/x-www-form-urlencoded serializer,
with the corresponding exception that a parameter’s value — but not its name —
may be serialized differently than that algorithm requires, provided the
serialization does not interfere with the ability to parse back the resulting URI.

Square Brackets in Parameter Names

With query parameter families, JSON:API allows for
query parameters whose names contain square brackets (i.e., U+005B “[” and
U+005D “]”).

According to the query parameter serialization rules above, a compliant
implementation will percent-encode these square brackets. However, some URI
producers — namely browsers — do not always encode them. Servers SHOULD
accept requests in which these square brackets are left unencoded in a query
parameter’s name. If a server does accept these requests, it MUST treat the
request as equivalent to one in which the square brackets were percent-encoded.

The 4xx HTTP status codes may not be enough to describe the cause of the error to the client. For this reason, several companies introduced a custom error response format to provide the caller with everything they need to deal with the error. This is a great addition you can make to your backend application, especially considering that implementing it requires only a few lines of code. Let’s see what you need to get started with error response customization for 401 Unauthorized and 403 Forbidden errors in Express.

An Introduction to HTTP Error Status Codes

The HTTP status code is a code number returned by the server in response to a client’s request. The many HTTP status codes available can be grouped into the following five classes based on their number:

  • 1xx: informational responses
  • 2xx: successful responses
  • 3xx: redirection messages
  • 4xx: client error responses
  • 5xx: server error responses

As you can see, there are only two categories of HTTP status codes that represent errors: 4xx and 5xx.

The 4xx class of HTTP status code refers to errors due to the client’s request, for example, because of a malformed request. When it comes to 4xx errors, the server should provide the client with additional info behind the error to prevent it from causing it again.

The 5xx class of HTTP status code refers to errors encountered by the server while processing the request. For security reasons, you should not provide the client with additional info about this type of error. This is because you do not want an attacker to understand how the server works based on what you returned to them.

Using the right HTTP error status codes is important to help the client understand what occurred. In fact, each 4xx or 5xx HTTP status code corresponds to a particular type of error. For example, the 400 status code should be used when the form of the client request is not as the API expects, while the 401 status code should be returned when the client provides no credentials or invalid credentials. However, with 4xx errors, the HTTP status code alone may not be enough, and you should provide the client with more info.

Let’s delve into why you might need to customize your HTTP error responses.

Why Customize Error Responses?

Considering that 4xx errors are caused by the client’s request, not receiving enough info to understand why that request failed may be frustrating. Therefore, you need to customize error responses to provide the client with more details about the problem that occurred. This means returning additional data along with the HTTP error status code.

For example, imagine a situation where an API requires a numeric customerId parameter. Now, a client calls that API without the customerId parameter or using a non-numeric string. As a result, it will receive a generic 400 Bad Request error from the server. As you can imagine, the default «Bad Request» message cannot help the caller understand how they should call the API. On the other hand, if the server returned a 400 HTTP status code response containing the «customerId required» or «customerId must be a number» message, the client could figure out how they need to call the API properly and avoid making the same mistake twice. Therefore, providing a detailed message on 4xx errors helps end-users, and it is also why several companies with public APIs use custom error responses.

Notice that customizing error responses represent a security concern. Although providing extra info in case of errors can be helpful, you should never return info that could jeopardize the security of your application. This is why you should consider customization on error responses only on 4xx errors, which are all directly referable to the client. On the contrary, you should never provide additional info on your 5xx error responses.

Now, let’s see an interesting format for your custom error responses.

A Format for Your Error Responses

To get an idea of how to define a good custom error response format, you can have a look at what reputable companies with public APIs like Google, Apple, and Amazon do in case of errors. For example, this is what GitHub returns in case of a 401 error:

{
   "message": "Requires authentication",
   "documentation_url": "https://docs.github.com/rest/reference/repos#create-an-organization-repository"
}

Returning a string message containing the error description is a common practice, but what is particularly insightful is the documentation_url field. This is a brilliant idea to provide the caller with pathways to solutions and not just report error messages. Also, if something changes, you do not have to update your error responses. What will be changing is the content of the documentation page used in the error response. In addition, returning a public link to the documentation does not pose a security problem by definition because anyone can already access the documentation.

Now, let’s see how to customize your error responses to follow this format in an Express server.

Customize Error Responses in Express

Here, you will learn how to customize the 401 Unauthorized or 403 Forbidden HTTP errors by extending the Auth0 Hello World API. This is a good example of a demo Express application in JavaScript to start from. Also, HTTP 401 and 403 errors fall into the 4xx class and are good examples of errors that may require custom responses.

Let’s now dive into the Auth0 Express Hello World API.

Get started with the Auth0 Hello Word API

You can find the Auth0 Express Hello World API repo here. In detail, let’s focus on the basic-role-based-access-control branch. You can clone it to take a look at its code with the command below:

git clone https://github.com/auth0-developer-hub/api_express_javascript_hello-world.git --branch basic-role-based-access-control

This codebase contains the Express.js Hello World API protected via role validation provided by Auth0. You need an Auth0 account to configure the application, If you don’t have one, sign up for free right now!

Notice that this RBAC (Role-Based Access Control) strategy depends on the Auth0 User Management features. You can learn more about the Express Hello World API with basic RBAC protection here.

Specifically, authentication and authorization error logic is handled in the error.middleware.js file as below:

// src/middleware/error.middleware.js

const errorHandler = (error, request, response, next) => {
  if (error.status === 401 && error.message === "Unauthorized") {
    const status = 401;
    const message = "Requires authentication";

    response.status(status).json({ message });

    return;
  }

  if (
    error.status === 401 &&
    error.code === "invalid_token" &&
    error.message === "Permission denied"
  ) {
    const status = 403;
    const message = error.message;

    response.status(status).json({ message });

    return;
  }

  const status = error.statusCode || error.code || 500;
  const message = error.message || "internal error";

  response.status(status).json({ message });
};

module.exports = {
  errorHandler,
};

Here, the «Unauthorized» 401 error raised by the Auth0 SDK is intercepted and transformed into the following 401 HTTP status code error response:

"Requires authentication"

Similarly, the “Permission denied” 401 error generated by the Auth0 SDK is converted into the following 403 HTTP status code error response:

"Permission denied"

Note that the Auth0 Express library used to provide authorization and authentication does not return a 403 error when the access token is not associated with a user with the expected role, as you might expect. This is because the Auth0 SDK team wanted to keep the library as generic as possible and always returns a generic 401 error. It is up to you to weigh in and determine whether that error returned by the SDK is the most appropriate for your use case. Here, it is not, and that is why the 401 error becomes a 403 error.

Let’s now learn more about the Auth0 library used.

How is access checked?

The Express Hello World API relies on the express-oauth2-jwt-bearer Auth0 library to implement authorization and authentication. If you are not familiar with it, express-oauth2-jwt-bearer is an authentication middleware for Express that validates bearer access tokens in JWT format.

In detail, express-oauth2-jwt-bearer is used in the src/middleware/auth0.middleware.js file as follows:

// src/middleware/auth0.middleware.js

const { auth, claimCheck } = require("express-oauth2-jwt-bearer");
const dotenv = require("dotenv");

dotenv.config();

const validateAccessToken = auth({
  issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
  audience: process.env.AUTH0_AUDIENCE,
});

const checkRequiredPermissions = (requiredPermissions) => {
  return (req, res, next) => {
    const permissionCheck = claimCheck((payload) => {
      const permissions = payload.permissions || [];

      return requiredPermissions.every((requiredPermission) =>
        permissions.includes(requiredPermission)
      );
    }, "Permission denied");

    permissionCheck(req, res, next);
  };
};

module.exports = {
  validateAccessToken,
  checkRequiredPermissions,
};

The validateAccessToken() function is generated by the express-oauth2-jwt-bearer auth() function, which takes a AuthOptions object and returns a middleware function that can be used to restrict an Express endpoint to authorized users. Similarly, the checkRequiredPermissions() function is generated by the express-oauth2-jwt-bearer claimCheck() function, which takes a JWTPayload object and returns a middleware function that can be used to restrict an Express endpoint to authenticated users.

The two functions can be used to provide authentication and authorization as follows:

// src/services/example.js

const express = require("express");
const {
  checkRequiredPermissions,
  validateAccessToken,
} = require("../middleware/auth0.middleware.js");

const messagesRouter = express.Router();

// a public endpoint
messagesRouter.get("/public", (req, res) => {
  res.status(200).json("Hello, World!");
});

// an Express endpoint accessible only by authenticated users
// thanks to the validateAccessToken middleware
messagesRouter.get("/protected", validateAccessToken, (req, res) => {
  res.status(200).json("Hello, World!");
});

// an Express endpoint accessible only by authenticated and authorized users
// thanks to the validateAccessToken and checkRequiredPermissions middleware
// functions respectively
messagesRouter.get(
  "/admin",
  validateAccessToken,
  checkRequiredPermissions(["read:admin-messages"]),
  (req, res) => {
    const message = getAdminMessage();

    res.status(200).json(message);
  }
);

module.exports = { messagesRouter };

Customizing 401 and 403 Error Responses

Let’s now see how to extend the basic-role-based-access-control branch application to implement custom error responses on 401 and 403 errors. You can find the full code in the GitHub repository that supports the article. To achieve the goal, simply change the file error.middleware.js as follows:

// src/middleware/error.middleware.js

const errorHandler = (error, request, response, next) => {
  if (error.status === 401 && error.message === "Unauthorized") {
    // defining the HTTP status code
    const status = 401;
    // standard HTTP 401 error message
    const message = "Unauthorized";
    // the link to the hosted version of the "how-to-handle-authentication" HTML page
    // you can find in the /docs folder
    const authority = `${request.protocol}://${request.hostname}:${process.env.PORT}`;
    const documentationLink = `${authority}/docs/how-to-handle-authentication.html`;

    // implementing a custom error response on 401 errors
    // matching the GitHub error response format
    response.status(status).json({
      message: message,
      documentationLink: documentationLink
    });

    return;
  }

  if (
      error.status === 401 &&
      error.code === "invalid_token" &&
      error.message === "Permission denied"
  ) {
    // defining the HTTP status code
    const status = 403;
    // standard HTTP 403 error message
    const message = "Forbidden";
    // the link to the hosted version of the "how-to-handle-authorization" HTML page
    // you can find in the /docs folder
    const authority = `${request.protocol}://${request.hostname}:${process.env.PORT}`;
    const documentationLink = `${authority}/docs/how-to-handle-authorization.html`;

    // implementing a custom error response on 403 errors
    // matching the GitHub error response format
    response.status(status).json({
      message: message,
      documentationLink: documentationLink
    });

    return;
  }

  const status = error.statusCode || error.code || 500;
  const message = error.message || "internal error";

  response.status(status).json({ message });
};

module.exports = {
  errorHandler,
};

This is what the 401 error response will look like:

{
   "message": "Unauthorized",
   "documentationLink": "https://your-domain.com/docs/how-to-handle-authentication.html"
}

And this is what the 403 error response will look like:

{
   "message": "Forbidden",
   "documentationLink": "https://your-domain.com/docs/how-to-handle-authorization.html"
}

Note that in both cases the error message matches the standard HTTP error message. Also, the links used in the error responses point to the hosted version of the two custom static HTML pages you can find in the /docs folder of the project.

The "How To Handle Authentication" sample doc page

Keep in mind that these HTML documents are only sample pages with lorem ipsum text. Therefore, you should populate the pages with complete information to handle authentication and authorization errors or replace the URLs with appropriate links to your documentation.

Testing the 401 and 403 Error Response

First, clone the extended version of the basic-role-based-access-control Auth0 Hello World API branch with the following command:

git clone https://github.com/auth0-blog/extended-basic-role-based-access-control

Then, enter the extended-basic-role-based-access-control project directory with this command:

cd extended-basic-role-based-access-control

Now, install the npm project dependencies with:

npm install

Then, create a .env file under the root directory of the project and populate it as follows:

PORT=6060
CLIENT_ORIGIN_URL=http://localhost:4040
AUTH0_AUDIENCE=<YOUR-AUTH0-AUDIENCE>
AUTH0_DOMAIN=<YOUR-AUTH0-DOMAIN>

Replace <YOUR-AUTH0-AUDIENCE> and <YOUR-AUTH0-DOMAIN> with the values you can find in the Auth0 dashboard. Also, you will need to retrieve a valid <AUTH0-ACCESS-TOKEN> value. Follow this guide from the official Auth0 documentation to learn how to retrieve these values.

Launch the Express.js API server with the command below:

npm run dev

You are now ready to start testing the 401 error response. For example, let’s try to call the api/messages/protected API that requires authentication without the required Auth0 access token:

curl --request GET 
  --url http:/localhost:6060/api/messages/protected

You will receive a 401 error response containing the following JSON:

{
   "message": "Unauthorized",
   "documentationLink": "https://your-domain.com/docs/how-to-handle-authentication.html"
}

On the contrary, let’s try to use the valid <AUTH0-ACCESS-TOKEN> retrieved earlier.

curl --request GET 
  --url http:/localhost:6060/api/messages/protected 
  --header 'authorization: <AUTH0-ACCESS-TOKEN>'

In this case, you would get:

{
    text: "This is a protected message."
}

Replicating a 403 error requires a little more effort. This is because you need to run a frontend client application that uses the Auth0 SDK. Follow this tutorial from the official documentation to learn how to set up RBAC in Auth0. Make sure to set up a «read:admin-messages» role and associate it with the admin user role.

Then, use any of the Auth0 frontend client demos from the list you can find here to login and access the GET /api/messages/admin endpoint exposed by the Express server launched earlier on port 6060.

When logging with an authorized admin user, you will get:

{
    "text": "This is an admin message."
}

On the other hand, when using an unauthorized user, you will receive the following JSON error response:

{
   "message": "Forbidden",
   "documentationLink": "https://your-domain.com/docs/how-to-handle-authorization.html"
}

Security for Web Developers

Conclusion

In this article, we looked at how to customize error responses when dealing with REST applications developed in Express. This requires just a bunch of lines of code, but you should not take it lightheartedly. On the contrary, it should be implemented with security in mind to avoid providing attackers with useful information about how your backend works. First, we introduced HTTP error status codes and clarified why you might need error response customization on 4xx errors. Then, we studied how companies with public APIs deal with the 4xx errors to define a real-world backed error response format. Finally, we learned how to implement this format when it comes to 401 and 403 errors returned by the Auth0 Express Hello World API using the express-oauth2-jwt-bearer library for authentication and authorization.

Thanks for reading! I hope that you found this article helpful. Feel free to reach out to me with any questions, comments, or suggestions.

In the course of fetching APIs in Next.js, we may encounter an error if the API request doesn’t go as planned. Let’s see how to manage these errors using Next’s Response Helpers.

It is a web framework built on top of React.js. Next.js extends the capabilities of React.js by providing the developers features like server-side rendering, static site generation, incremental static generation, a working REST API, file-system-based routing, dynamic routing, etc. It provides better optimization, additional structure, and features to your application. All in all, it is focused on better data fetching.

API Errors

When a request to an API doesn’t go as planned, an API error occurs. So, the API must respond to the client specifying whether the request was successful or not. In this case, we should send an error response, and it is the only way for the developers to diagnose what went wrong. HTTP Status Codes are used for this purpose. The following status codes notify about the errors.

  • 4xx — Client error. Such as 404: Requested URL not found.
  • 5xx — Server error.

Informing the client about the error helps them understand the error and its cause.

Next.js API Routes

Next.js provides API routes that allow you to create your own API. Any file inside the pages/api is dealt with as an API endpoint, which the client-side can access. Here is an example API route that fetches an API from RapidAPI Hub.

jsx

// pages/api/getColors.js

import axios from 'axios';

export default async function handler(req, res) {

const options = {

method: 'GET',

url: 'https://random-palette-generator.p.rapidapi.com/palette/'

};

try {

let response = await axios(options);

// Send response to the client side

} catch (error) {

// Send error to the client side

}

}

As you can see, we need some way to send the response and error (if any) to the client-side. This is where the Response Helpers come into play.

Response Helpers

They are helper functions like those in Express.js that make managing HTTP requests and their response easy. They are available in the Server Response object, often abbreviated as res like the code above. Here are the main helper functions:

  • res.send(body). It sends the HTTP response received from the API to the client.
  • res.json(body). It sends the response in JSON.
  • res.status(code). Sets an HTTP status code.

In order to send a successful response, we set its status code to 200 using the .status helper and combine it with res.send or res.json. For example:

jsx

// pages/api/getColors.js

import axios from 'axios';

export default async function handler(req, res) {

const options = {

method: 'GET',

url: 'https://random-palette-generator.p.rapidapi.com/palette/'

};

try {

let response = await axios(options);

// Sends response to the client side

res.status(200).json(response.data);

} catch (error) {

// Send error to the client side

}

}

Similarly, we can send an error message to the client-side if an error occurs. For example, to send a 500 error, we can do something like this:

js

// pages/api/getColors.js

import axios from 'axios';

export default async function handler(req, res) {

const options = {

method: 'GET',

url: 'https://random-palette-generator.p.rapidapi.com/palette/'

};

try {

let response = await axios(options);

res.status(200).json(response.data);

} catch (error) {

// Sends error to the client side

res.status(500).send('Internal Server Error.');

}

}

If you are using Axios, you can also set the error details dynamically using the error.response object.

js

// pages/api/getColors.js

import axios from 'axios';

export default async function handler(req, res) {

const options = {

method: 'GET',

url: 'https://random-palette-generator.p.rapidapi.com/palette/'

};

try {

let response = await axios(options);

res.status(200).json(response.data);

} catch (error) {

// Sends error to the client side

res.status(error.response.status).send(error.response.data);

}

}

Now you know how to manage API errors using Response Helpers in Next.js.

@ix-xerri

I’m building a REST API and only need to send error codes from the server. Messages are being handled by the client.

res.json(200); works.

res.json(304); does not. 304 becomes the body with the status being changed to 200.

res.json(304, {}); works.

@jonathanong

If your body is empty, send a 204 code not 200.

@ix-xerri

I need to send 200 in cases like a successful post request or delete
request. I use res.json because my aka requests are of dataType: ‘json’.

On 11 Jun 2013, at 19:06, Jonathan Ong notifications@github.com wrote:

If your body is empty, send a 204 code not 200, and don’t use res.jaon.


Reply to this email directly or view it on
GitHubhttps://github.com//issues/1649#issuecomment-19275459
.

@sirlancelot

Have a look at response.js@171

statusCode is only set when there are two arguments.

@jonathanong

If your client doesn’t recognize the 204 status code as equivalent to 200 without any body, it is a bug with the client. Personally, I would just send something, even just an «ok» message.

@tj

json without a body is really weird, we should make that required if anything

@ix-xerri

I omitted the ok because the client would purposely disregard it. So it’s
extra data.

On 11 Jun 2013, at 21:22, Jonathan Ong notifications@github.com wrote:

If your client doesn’t recognize the 204 status code as equivalent to 200
without any body, it is a bug with the client. Personally, I would just
send something, even just an «ok» message.


Reply to this email directly or view it on
GitHubhttps://github.com//issues/1649#issuecomment-19286012
.

@ix-xerri

@jonathanong

thats what a 204 status code is.

@jonathanong

you should just do

or

res.statusCode = 204
res.end()

@ix-xerri

Will try it out. Thanks everyone!

Matthew Xerri

On 12 Jun 2013, at 00:16, Jonathan Ong notifications@github.com wrote:

you should just do

res.statusCode = 204res.end()


Reply to this email directly or view it on
GitHubhttps://github.com//issues/1649#issuecomment-19296089
.

@jaketrent

returns status 200 w/ ‘204’ in body.

res.statusCode = 204
res.end()

works as expected and returns a 204 w/o a message body.

also works as expected

@dougwilson

FYI res.json(200); never worked as the OP thought it did; it sent the number «200» as the body and of course defaulted to the status code of 200; res.json takes either 1 argument of the JSON to send with the default status code OR two arguments where if the first is a number, it is the status code.

Понравилась статья? Поделить с друзьями:
  • Json error online
  • Json error none
  • Json error malformed utf 8 characters possibly incorrectly encoded bitrix
  • Json error malformed utf 8 characters possibly incorrectly encoded 5 100
  • Json error cyclic dependency detected