Relay Compatibility
Introduction
The Parse Server GraphQL API follows latest standards currently available for highly-scalable APIs and ambitious front-end projects.
The Parse Open Source Team choose to follow the GraphQL Server Relay Specification.
Relay is a JavaScript framework for building data-driven React applications powered by GraphQL, designed from the ground up to be easy to use, extensible and, most of all, performant. Relay accomplishes this with static queries and ahead-of-time code generation.
Starting from Parse 3.10, full compatibility with Relay is implemented.
This document will walk you through those implementations
Prerequisites
To begin with this tutorial, you will need:
- An app created at Back4App.
- See the Create New App tutorial to learn how to create an app at Back4App.
Step 1 - Create a New Back4App App
First of all, it’s necessary to make sure that you have an existing app created at Back4App. However, if you are a new user, you can check this tutorial to learn how to create one.
Step 2 - Create a few Classes
In your newly created App, go to the Database Browser
and click the Create a class
button
Choose to crate a Custom
class and give it a name.
Following the Relay example schema, I created the classes Faction, Ship and others as described with matching properties, but you can create your own classes in order to follow this documention. Just change your queries and mutations accordingly.
Remember that by convention classes start with an Uppercase letter, are CamelCase and does not contain special characters such as spaces and symbols.
Click Create class
when you’re done.
Step 3 - GraphQL Console
With your Classes and Properties created, you can go to the API Console
and then GraphQL Console
to execute your queries and mutations.
Step 4 - Queries
Our very first query will retrieve an object based on its objectId
(not to confuse with id
).
Parse has evolved and now queries support both ObjectId
, formerly known as id
in previous versions, but now also supports Global Id
, know as id
, which refers to Relay’s global ID and has a longer format as it contains the classname encrypted into it.
Example of ObjectId
: EaT0dDk09v
Example of id
(a.k.a. Global id): RmFjdGlvbjpFYVQwZERrMDl2
Let’s make our very first query retrieving an object by its ObjectId
:
1
2
3
4
5
6
7
query RebelsQuery {
faction(id:"EaT0dDk09v") {
objectId #ObjectId for Parse
id #GlobalID for Relay
name #n
}
}
That will output
1
2
3
4
5
6
7
8
9
{
"data": {
"faction": {
"objectId": "EaT0dDk09v",
"id": "RmFjdGlvbjpFYVQwZERrMDl2",
"name": "Galactic Empire"
}
}
}
Now, let’s change that for the GlobalId for Relay:
1
2
3
4
5
6
7
query RebelsQuery {
faction(id:"RmFjdGlvbjpFYVQwZERrMDl2") {
objectId #ObjectId for Parse
id #GlobalID for Relay
name #n
}
}
And notice that the result will be the same:
1
2
3
4
5
6
7
8
9
{
"data": {
"faction": {
"objectId": "EaT0dDk09v",
"id": "RmFjdGlvbjpFYVQwZERrMDl2",
"name": "Galactic Empire"
}
}
}
This happens because the Global Id
works, as it name implies, globally, and has the class name encrypted into it, so Parse knows where to search for that id.
Step 5 - Refetching
Also with the Global Id
you can refetch like Relay’s specification as follows:
1
2
3
4
5
6
7
query RefetchQuery{
node(id:"RmFjdGlvbjpFYVQwZERrMDl2"){
id ... on Faction{
name
}
}
}
which will result in
1
2
3
4
5
6
7
8
{
"data": {
"node": {
"id": "RmFjdGlvbjpFYVQwZERrMDl2",
"name": "Galactic Empire"
}
}
}
Step 6 - Connections
Relay’s connections works the same way in Parse with GraphQL, so, if you need to retrieve the Rebel’s ships:
1
2
3
4
5
6
7
8
9
10
11
12
13
query RebelsShipsQuery {
faction(id: "RmFjdGlvbjphcTAzNklSZ2RQ"){
objectId
name
ships{
edges{
node{
name
}
}
}
}
}
which will result:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"data": {
"faction": {
"objectId": "aq036IRgdP",
"name": "Alliance to Restore the Republic",
"ships": {
"edges": [
{
"node": {
"name": "Y-Wing"
}
},
{
"node": {
"name": "X-Wing"
}
}
]
}
}
}
}
You can also retrieve the Nth ships:
1
2
3
4
5
6
7
8
9
10
11
12
13
query RebelsShipsQuery {
faction(id: "RmFjdGlvbjphcTAzNklSZ2RQ"){
objectId
name
ships(first: 1){
edges{
node{
name
}
}
}
}
}
resulting in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"data": {
"faction": {
"objectId": "aq036IRgdP",
"name": "Alliance to Restore the Republic",
"ships": {
"edges": [
{
cursor
"node": {
"name": "Y-Wing"
}
}
]
}
}
}
}
Or retrieve the Nth ships after a specific one, using its cursor value:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
query RebelsShipsQuery {
faction(id: "RmFjdGlvbjphcTAzNklSZ2RQ"){
objectId
name
ships(first: 1 after: "YXJyYXljb25uZWN0aW9uOjA"){ #cursor for the Y-wing ship
edges{
cursor
node{
name
}
}
}
}
}
which will retrieve:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"data": {
"faction": {
"objectId": "aq036IRgdP",
"name": "Alliance to Restore the Republic",
"ships": {
"edges": [
{
"cursor": "YXJyYXljb25uZWN0aW9uOjE=",
"node": {
"name": "X-Wing"
}
}
]
}
}
}
}
Step 7 - Mutations
We can also use Mutations compatible with Relay’s mutations.
Let’s create a new Ship
:
1
2
3
4
5
6
7
8
mutation createBWing($input: CreateShipInput!){
createShip(input: $input){
ship{
id
name
}
}
}
That needs the following Query Variable:
1
2
3
4
5
6
7
{
"input":{
"fields": {
"name": "B-Wing"
}
}
}
And will return the Global Id
and name
as specified in the mutation:
1
2
3
4
5
6
7
8
9
10
{
"data": {
"createShip": {
"ship": {
"id": "U2hpcDpXb21QZnVzeXVF",
"name": "B-Wing"
}
}
}
}