Skip to main content

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.

GET /
Empty

On success, an Item is returned.

200 OK
{
"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.

404 Not Found
{
"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.

POST /users
{
"name": "John Doe",
"email": "[email protected]"
}

On success, it returns an Item Summary.

201 Created
{
"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.

400 Bad Request
{
"error": {
"message": "Connector received a bad request"
}
}

Or maybe the connector or the provider failed to validate the item.

422 Unprocessable Entity
{
"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.

PATCH /users/1
{
"name": "Jane Doe"
}

On success, it returns an Item.

200 OK
{
"fields": {
"id": 1,
"name": "Jane Doe",
"email": "[email protected]"
},
"relations": []
},

Multiple types of error can occur. As an example, validation might fail.

422 Unprocessable Entity
{
"error": {
"message": "Validation failed on field 'name'"
}
}

Or maybe the item couldn't be found.

404 Not 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.

DELETE /users/1
Empty

On success, it returns a 204 status code.

204 No Content
Empty

Multiple types of error can occur. As an example, validation might fail.

422 Unprocessable Entity
{
"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.

GET /users
Empty

On success, it returns a Collection.

200 OK
{
"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.

PATCH /
{
"__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.

200 OK
{
"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.

422 Unprocessable Entity
{
"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":

GET /users?filter=name^=John&select=name,department.name
{
"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.