# API response format

AyaNova uses a RESTful API and supports the [JSON](https://www.json.org/) data interchange format exclusively.
No other data formats are supported, your code must supply and consume JSON formatted data.

All developer interaction with the AyaNova API is via the REST server interface only.

## Successful responses

### GET RESPONSE

All successful GET responses have a standard format:

```json
{
  "data": {
    "id": 150,
    "name": "Handmade Rubber Pizza",
    ...etc...
  }
}
```

The results of the response are always contained in the `data` property and could be a single object, a collection or in some cases nothing at all.
HTTP Status Code is set in the header.

### GET COLLECTION RESPONSE

In the case of a collection most routes support paging, here is an example paged collection request and response:

Request (note the `offset` and `limit` parameters):

`http://localhost:3000/api/v8.0/Widget?Offset=2&Limit=3`

Limit must be a value between 1 and 1000.

Response:

```json
{
  "data": [
    ...collection...
  ],
  "paging": {
    "count": 2000,
    "offset": 2,
    "limit": 3,
    "first": "http://localhost:3000/api/v8.0/Widget?pageNo=1&pageSize=3",
    "previous": "http://localhost:3000/api/v8.0/Widget?pageNo=1&pageSize=3",
    "next": "http://localhost:3000/api/v8.0/Widget?pageNo=3&pageSize=3",
    "last": "http://localhost:3000/api/v8.0/Widget?pageNo=667&pageSize=3"
  }
}
```

`Previous` or `next` properties will contain "null" instead of an url on boundaries where there is no record to link to.

### PUT RESPONSE

A successful PUT response does not return any data but returns HTTP status code 204 (no content) in the header.

**WARNING:** Be careful using PUT, you must provide **all** properties or any properties left out will be removed at the server. If you are updating a subset of properties use PATCH instead to save bandwidth.

### PATCH RESPONSE

Use PATCH to update specific properties only.

A successful PATCH response does not return any data but returns HTTP status code 204 (no content) in the header.
Patches must conform to the [JSONPATCH](http://jsonpatch.com/) standard.

### POST RESPONSE

A successful POST response contains the object posted with it's Id value set and the HTTP status code of 201 (created).

### DELETE RESPONSE

A successful DELETE response does not return any data but returns HTTP status code 204 (no content) in the header.

## Error responses

### Fundamental errors

Fundamental, basic errors return a header status code only and are generally self explanatory. For example if you attempt to use XML formatted data with the API you will receive an error response consisting only of the header 415 (unsuported media type).

401
In cases where authentication fails you will receive an empty body response with the header 401 (unauthorized) returned.
The details of what was wrong are contained in the header, here is an example of an invalid JWT authentication token:

```json
{
  "content-length": "0",
  "date": "Fri, 09 Mar 2018 16:46:07 GMT",
  "server": "Kestrel",
  "www-authenticate": "Bearer error=\"invalid_token\", error_description=\"The signature is invalid\"",
  "content-type": null
}
```

### Error response object

All error responses that return data have an `Error` object property at top level. The error object varies in the properties it contains depending on the error.

Here is the most minimal error response that returns data:

```json
{
  "Error": {
    "Code": "2000",
    "Message": "Developer readable error message"
  }
}
```

An error object will always contain at minimum an [API error `Code`](api-error-codes.md) property for reference and a `message` property with descriptive text intended for developers.

### Validation error response object

Here is an example of a more detailed error response showing validation errors on a request:

```json  hl_lines="4 "
{
  "error": {
    "code": "2200",
    "details": [
      {
        "message": "255 max",
        "target": "Name",
        "error": "LengthExceeded"
      },
      {
        "target": "EndDate",
        "error": "RequiredPropertyEmpty"
      },
      {
        "target": "Roles",
        "error": "InvalidValue"
      }
    ],
    "message": "Object did not pass validation"
  }
}
```

The above example shows multiple validation errors ([API error code](api-error-codes.md) 2200) in several properties when attempting to post an object.

`details` outer property contains the collection of all validation errors.

`target` property shows the location of the error. The value of `target` is either a property name corresponding to the property that failed business rule validation or blank if the validation rule applies to the entire object in general.

`error` property contains the exact [validation error](api-validation-error-codes.md).

`message` property optionally contains further information of use to the developer, in the example above you can see that the name property has more than the maximum limit of 255 characters.

### Concurrency error response object

AyaNova uses "optimistic concurrency" tracking. This means a concurrency token needs to accompany most change (PUT, PATCH) routes.

Objects that require concurrency tokens to update are the objects that return a `ConcurrencyToken` property on a GET request.

Every update to an object results in a new concurrency token for that object.

In a concurrency error response ([API error code](api-error-codes.md) 2005) and header HTTP code 409 (Conflict)  is returned if a user attempts to update a record that was changed by another user since it was retrieved (outdated concurrency token provided).

Here is an example:

```json
{
  "error": {
    "code": "2005",
    "message": "Object was changed by another user since retrieval (concurrency token mismatch)"
  }
}
```

### Other errors response format

Errors not related to validation or concurrency may contain one or more nested `innerError` properties. Each nested `innererror` object represents a higher level of detail than its parent. When evaluating errors, clients MUST traverse through all of the nested `innererrors` and choose the deepest one that they understand.

Here is a sample error response with innererror set:

```json  hl_lines="6 "
{
  "error": {
    "code": "1005",
    "message": "Previous passwords may not be reused",
    "target": "password",
    "innererror": {
      "code": "1006",
      "innererror": {
        "code": "1007",
        "minLength": "6",
        "maxLength": "64",
        "characterTypes": ["lowerCase","upperCase","number","symbol"],
        "minDistinctCharacterTypes": "2",
        "innererror": {
          "code": "1008"
        }
      }
    }
  }
}
```

Note that the contents of the `innererror` property may vary and contain distinct properties appropriate to the specific error condition.

### Server internal errors

Internal server errors are returned with an HTTP Status Code of 500 and an error object as follows:

```json
{
  "error": {
    "code": "2002",
    "message": "See server log for details",
    "target": "Server internal error"
  }
}
```

For security reasons no details of an internal server exception are returned, you must examine the [server log](common-log.md) to see the details.
Generally this means the request triggered an unhandled exception which will be logged in detail to the log file.
Please report any internal server errors (preferrably with the log showing the exception details) to AyaNova support so we can look into it.
