Graph Operations
A connector must provide an endpoint allowing Unito to access the provider data. This endpoints is defined by the
graphRelativeUrl
property of the configuration file.
It represents an entry point to the graph, from which Unito can programatically start exploring.
The graph is composed of two types of nodes — items, and collections. Items link to collections, which in turn link to other items, in what can essentially be an endless graph.
Read an item
All items are readable by default.
Empty
On success, an Item is returned.
{
"fields": {},
"relations": [
{
"name": "users",
"path": "/users",
"schema": {
"fields": [
{
"name": "name",
"label": "Name",
"type": "string"
},
{
"name": "email",
"label": "Email",
"type": "email"
}
]
}
}
]
}
If the item can't be found, an error is returned.
{
"error": {
"message": "Item not found"
}
}
Create an item
When canCreateItem
is set to true, it is assumed one can POST new records to the relation's
path.
{
"name": "John Doe",
"email": "[email protected]"
}
On success, it returns an Item Summary.
{
"path": "/users/1"
}
Different errors can occur. As an example, a request to create an item might has been issued on a relation that doesn't support this operation.
{
"error": {
"message": "Connector received a bad request"
}
}
Or maybe the connector or the provider failed to validate the item.
{
"error": {
"message": "Provider couldn't process the request"
}
}
It's on the connector to use the most appropriate error code.
Update an item
When canUpdateItem
is set to true, it is assumed one can PATCH a record with the item's path.
{
"name": "Jane Doe"
}
On success, it returns an Item.
{
"fields": {
"id": 1,
"name": "Jane Doe",
"email": "[email protected]"
},
"relations": []
},
Multiple types of error can occur. As an example, validation might fail.
{
"error": {
"message": "Validation failed on field 'name'"
}
}
Or maybe the item couldn't be found.
{
"error": {
"message": "Item not found"
}
}
It's on the connector to use the most appropriate error code.
Delete an item
When canDeleteItem
is set to true, it is assumed one can DELETE a record with the item's path.
Empty
On success, it returns a 204
status code.
Empty
Multiple types of error can occur. As an example, validation might fail.
{
"error": {
"message": "This resource cannot be deleted at this time."
}
}
It's on the connector to use the most appropriate error code.
Read a relation
Each relation defines a path allowing its data to be fetched.
Empty
On success, it returns a Collection.
{
"info": {
"nextPage": "/users?page=2"
},
"data": [
{
"path": "/users/1"
},
{
"path": "/users/2"
},
...
]
}
Update a relation
When canAddFields
is set to true, it is assumed fields can be added to the schema of that relation. This can be
achieved with a PATCH operation on the relation owner's path. That being said, contrary to a regular update operation,
we want not to modify the item itself, but rather its internals. To make this possible, a special reserved keyword
called __meta
is available, which indicates that the modifications are meant for the schema, not the item itself.
{
"__meta": {
"additionalField": {
"relationName": "users",
"field" {
"name": "department",
"label": "Department",
"type": "string",
}
}
}
}
On success, it returns a 200
status code with the item, including its newly modified relations.
{
"fields": {},
"relations": [
{
"name": "users",
"path": "/users",
"schema": {
"fields": [
{
"name": "name",
"label": "Name",
"type": "string"
},
{
"name": "email",
"label": "Email",
"type": "email"
},
{
"name": "department",
"label": "Department",
"type": "string"
}
]
}
}
]
}
Multiple types of error can occur. As an example, validation might fail.
{
"error": {
"message": "This field type is not valid for this resource."
}
}
Select and Filters
A relation's path supports additional query parameters used to specify and control the amount of data returned in a collection. The connector must accept these query parameters, but the quality of the response will depend on the provider capabilities.
select
: Specify which fields should be returned in the response.filter
: Offer advanced type-specific search capabilities.
As an example, to retrieve the list of names and departments for users whose name starts with "John":
{
"info": {
"nextPage": "/users?filter=name^=John&select=name,department.name&page=2"
},
"data": [
{
"path": "/users/43",
"fields": {
"name": "John Doe",
"department": {
"path": "/departments/1",
"fields": {
"name": "Sales",
}
}
}
},
{
"path": "/users/108",
"fields": {
"name": "Johnny Burger",
"department": {
"path": "/departments/2",
"fields": {
"name": "R&D",
}
}
}
}
]
}
Advanced search functionalities through the filter
keyword are only available on certain fields. Each field type
determines which operators are available. The format of an operation takes the form of {field}{operator}{value}
.
Multiple operations are separated by a comma (,
) and should be understood as being cumulative (i.e. AND), while multiple
values for a single field are separated by the pipe operator (|
) and are understood as non-cumulative (i.e. OR).
As an example, to retrieve only active
or pending
users with a createdAt
date greater than 2022-01-01;
/users?filter=status=active|pending,createdAt>2022-01-01
The same field can be passed multiple times. As an example, to retrieve the list of users created in January 2022;
/users?filter=createdAt>=2022-01-01,createdAt<2022-02-01
Null and non-null operators do not need to specify a value. As an example, to retrieve users without an email;
/users?filter=email!!
It is also possible to filter by semantic using the special semantic:
prefix. As an example, to search for users
for which the field with a display name semantic starts with J
;
/users?filter=semantic:displayName^=J
Connectors should do their best to translate these parameters in a way that will be compatible with their provider, but we understand this might not be feasible in all instances. In those cases, connectors can try to manually do the filtering on their end, after having retrieved the records from their provider.