# 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...
  },
  "readOnly": boolean
}
```

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.  A ReadOnly property is set on the returned data for the convenience of the client software however note that the server will always determine this independently so if this property is ignored and the client attempts to update the record a error 2004 NOT_AUTHORIZED would be returned.

### GET DATALIST RESPONSE

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

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

`http://localhost:7575/api/v8/DataList/List?Offset=2&Limit=2&DataListKey=TestWidgetDataList`

Limit must be a value between 1 and 1000.

Response:

```json
{
  "data": [
    [
      {
        "v": 3
      },
      {
        "v": "Handcrafted Fresh Keyboard 27",
        "i": 3
      },
      {
        "v": 3
      },
      {
        "v": 697.34
      },
      {
        "v": 128
      },
      {
        "v": "2020-01-28T12:10:46.212435Z"
      },
      {
        "v": true
      },
      {
        "v": "Doug Effertz 17 - OpsAdminFull",
        "i": 18
      }
    ],
    ...etc...
  ],
  "paging": {
    "count": 100,
    "offset": 2,
    "limit": 2,
    "first": "http://localhost:7575/api/v8/DataList/List?DataListKey=TestWidgetDataList&pageNo=1&pageSize=2",
    "previous": "http://localhost:7575/api/v8/DataList/List?DataListKey=TestWidgetDataList&pageNo=1&pageSize=2",
    "next": "http://localhost:7575/api/v8/DataList/List?DataListKey=TestWidgetDataList&pageNo=3&pageSize=2",
    "last": "http://localhost:7575/api/v8/DataList/List?DataListKey=TestWidgetDataList&pageNo=50&pageSize=2"
  },
  "columns": [   
    {
      "cm": "WidgetName",
      "dt": 4,
      "ay": 2,
      "rid":1
    },
    {
      "cm": "WidgetSerial",
      "dt": 5
    },
    {
      "cm": "WidgetDollarAmount",
      "dt": 8
    },
    {
      "cm": "WidgetUserType",
      "dt": 10
    },
    {
      "cm": "WidgetStartDate",
      "dt": 1
    },
    {
      "cm": "Active",
      "dt": 6
    },
    {
      "cm": "User",
      "dt": 4,
      "ay": 3
    }
  ]
}


```

`Previous` or `next` properties will contain "null" instead of an url on boundaries where there is no record to link to.
`columns` collection is the list of columns returned in the same order as the individual data arrays for each object.
Note that the column with the `rid` flag is the default row ID column and contains the object type and id to open for that row which guarantees an openable object for the row regardless of which columns are set to be returned.  

### 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": "2202"
      },
      {
        "target": "EndDate",
        "error": "2205"
      },
      {
        "target": "Roles",
        "error": "2203"
      }
    ],
    "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 [api validation error code](api-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 `Concurrency` 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 unexpected internal server errors (preferrably with the log showing the exception details) to AyaNova support so we can look into it.
