/loopback4-example-family-tree

An example LoopBack application to demonstrate OASGraph

Primary LanguageTypeScriptOtherNOASSERTION

Example Family Tree

LoopBack

An example application made with LoopBack 4 for the purpose of demonstrating OpenAPI-to-GraphQL, a tool that can create GraphQL interfaces for APIs described with OpenAPI specifications (OAS).

Description

This application simulates the relationships between parent and child. There is only one model in this application. Here is what it looks like:

Person {
	id : number
	name : String
	generation: number
	motherId : number
	fatherId : number
}

In addition, this application is preloaded with some data. Here is what the data looks like:

Data diagram

Installation

Make sure you have Node.js >= 8.9.0 installed. Then do the following to clone and start the project.

git clone https://github.com/strongloop/loopback4-example-family-tree.git
cd loopback4-example-family-tree
npm i
npm start

OpenAPI-to-GraphQL

As mentioned before, the purpose of this repository is to demonstrate the capabilities of OpenAPI-to-GraphQL.

OpenAPI-to-GraphQL can either be used as a library or as a CLI tool. In the following section, we will describe how this API can be wrapped using the CLI tool.


First, install the CLI tool.

npm i -g openapi-to-graphql-cli

Second, start the Family Tree API.

cd loopback4-example-family-tree
npm start

Third, create the GraphQL server using OpenAPI-to-GraphQL.

openapi-to-graphql http://[::1]:3001/openapi.json -u http://[::1]:3001

Head to http://localhost:3001/graphql and enjoy!


Nested objects

As of now, the GraphQL interface will not have any nesting capabilities. To add these capabilities, you must define link objects in the OAS. To read more, click here.


Example: To create mother and father fields, which will allow you to query a person's mother or father, follow the ensuing instructions.

First, start the Family Tree API.

cd loopback4-example-family-tree
npm start

Second, save the OAS by going to http://[::1]:3001/openapi.json. Alternatively, run the following command.

wget http://[::1]:3001/openapi.json

Third, open the OAS in a text editor.

Find the /people/{id} path item object.

It should look a bit like the following:

"/people/{id}": {
    "get": {
        "x-controller-name": "PersonController",
        "x-operation-name": "findById",
        "tags": [
            "PersonController"
        ],
        "responses": {
            "200": {
                "description": "Person model instance",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Person"

Give the get operation object an operationId.

"/people/{id}": {
    "get": {
        "operationId": "getPerson"

Add the links into the response object.

"/people/{id}": {
    "get": {
        "responses": {
            "200": {
                "links": {
                    "mother": {
                        "operationId": "getPerson",
                        "parameters": {
                            "id": "$response.body#/motherId"
                        }
                    },
                    "father": {
                        "operationId": "getPerson",
                        "parameters": {
                            "id": "$response.body#/fatherId"
                        }
                    }
                }

Save the file and start the GraphQL server.

openapi-to-graphql openapi.json

Head to http://localhost:3001/graphql and enjoy!


Now you can create complex queries like the following:

query {
    person(id: 15) {
        name
        father {
            name 
            mother {
                name
                father {
                    name
                }
            }
        }
    }
}

Please be aware that the data may not be dense enough to support deeply nested queries and the API server and consequently the GraphQL server as well will throw errors. Please refer to the description for more information.

Notes

We needed to use the -u or -url option because the auto-generated OAS contains a placeholder server object.

The default server object should look like the following:

"servers": [
    {
        "url": "/"
    }
]

OpenAPI-to-GraphQL uses this object to form rest calls. Because this is an invalid base URL, we use the -u option to manually define a base URL.

Alternatively, the document could be saved and edited like so:

"servers": [
    {
        "url": "http://[::1]:3001/"
    }
]

Then, you can run OpenAPI-to-GraphQL without the -u option.

openapi-to-graphql openapi.json

To go more in depth on nested objects...

Links allow the user to define design-time relationships between operations, suggesting how one operation can naturally lead to the next.

Let's take a look at the provided example.

The following portion from the OAS describes an operation GET {base URL}/people/{id} that will return a Person object.

"/people/{id}": {
    "get": {
        "responses": {
            "200": {
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Person"

The Person object contains the following pieces of data:

{
    "title": "Person",
    "properties": {
        "id": {
        "type": "number"
        },
        "name": {
        "type": "string"
        },
        "generation": {
        "type": "number"
        },
        "motherId": {
        "type": "number"
        },
        "fatherId": {
        "type": "number"
        }
    }
}

Notice the motherId and fatherId fields.

Now, take a look at the following links.

"links": {
    "mother": {
        "operationId": "getPerson",
        "parameters": {
            "id": "$response.body#/motherId"
        }
    },
    "father": {
        "operationId": "getPerson",
        "parameters": {
            "id": "$response.body#/fatherId"
        }
    }
}

The links essentially say that when GET {base URL}/people/{id} returns a Person object, you can make a follow up call to get the mother or the father. The follow up call will be the operation that has the operationId: "getPerson". That operation is coincidentally also GET {base URL}/people/{id}. The id of the mother, which will be used in the /people/{id} path parameter, is the motherId of the returned Person object. Using this knowledge, OpenAPI-to-GraphQL is able to chain together multiple REST calls to get the mother or father of any person.

Another feature to note is that links are attached to GraphQL object types which means that any operation returning a Person (or a list of Persons) will also be able to query for the mother and the father, even if the links are defined elsewhere.

Examples

Here are some queries you can do with the basic API:

Query:

GET http://[::1]:3001/people/

Response:

[
    {
        "id": 1,
        "name": "Albert",
        "generation": 1,
        "motherId": 0,
        "fatherId": 0
    },
    {
        "id": 2,
        "name": "Allison",
        "generation": 1,
        "motherId": 0,
        "fatherId": 0
    },
    {
        "id": 3,
        "name": "Aaron",
        "generation": 1,
        "motherId": 0,
        "fatherId": 0
    },

    ...

    {
        "id": 13,
        "name": "Charles",
        "generation": 3,
        "motherId": 10,
        "fatherId": 9
    },
    {
        "id": 14,
        "name": "Claire",
        "generation": 3,
        "motherId": 12,
        "fatherId": 11
    },
    {
        "id": 15,
        "name": "Daron",
        "generation": 4,
        "motherId": 14,
        "fatherId": 13
    }
]

Query:

GET http://[::1]:3001/people/1

Response:

{
    "id": 1,
    "name": "Albert",
    "generation": 1,
    "motherId": 0,
    "fatherId": 0
}

License

MIT