Article
· Jul 6, 2018 6m read

GraphQL for InterSystems Data Platforms

GraphQL is a standard for declaring data structures and methods of data access that serves as a middleware layer between the client and the server. If you’ve never heard about GraphQL, here is a couple of useful online resources: here, here and here.

In this article, I will tell you how you can use GraphQL in your projects based on InterSystems technologies.

InterSystems platforms currently support several methods of creating client/server applications:

  • REST
  • WebSocket
  • SOAP

So what’s the advantage of GraphQL? What benefits does it provide compared with REST, for example?

GraphQL has several types of requests:

  • query - server requests for obtaining data, similar to GET requests recommended for fetching data using REST.
  • mutation - this type is responsible for server-side data changes, similar to POST (PUT, DELETE) requests in REST.
    Both mutation and query can return data – this comes in handy if you want to request updated data from the server immediately after performing a mutation.
  • subscriptions - the same query type that will output data. The only difference is that a query is launched by a page rendered on the client side while subscriptions are activated by mutations.

Key features and advantages of GraphQL

It’s up to the client to decide what data should be returned

One of the key features of GraphQL is that the structure and volume of returned data are defined by the client application. The client application specifies what data it wants to receive using a declarative, graph-like structure that closely resembles the JSON format. The response structure corresponds to that of the query.

Here is how a simple GraphQL query looks:

{
  Sample_Company {
    Name
  }
}

A response in the JSON format:

{
  "data": {
    "Sample_Company": [
      {
        "Name": "CompuSoft Associates"
      },
      {
        "Name": "SynerTel Associates"
      },
      {
        "Name": "RoboGlomerate Media Inc."
      },
      {
        "Name": "QuantaTron Partners"
      }
    ]
  }
}

Single endpoint

When using GraphQL to work with data, we always connect to a single endpoint, GQL server, and get different data by changing the structure, fields, and parameters of our queries. REST, in contrast, uses multiple endpoints.

Let’s compare REST with GraphQL using a simple example:

Let’s assume that we need to load a user’s content. If we are using REST, we need to send three queries to the server:

  1. Get the user’s data by their id
  2. Use their id to load their posts
  3. Use their id to get a list of their followers/subscribers

Below is a REST map corresponding to these queries:

   <Route Url="/user/:id" Method="GET" Call="GetUserByID"/>
   <Route Url="/user/:id/posts" Method="GET" Call="GetUserPostsByID"/>
   <Route Url="/user/:id/follovers" Method="GET" Call="GetUserFolloversByID"/>

In order to get a new data set, we will need to update this REST map with a new endpoint.

GraphQL handles this with a single query. To do that, just specify the following in the request body:

{
operationName: null,    //a query can have a name  ( query TestName(...){...} )
query: "query {
       User(id: "ertg439frjw") {
        name
        posts {
           title
        }
        followers(last: 3) {
           name
        }
    }
}",
variables: null      // initialization of the variables used in the query
}

A REST map corresponding to this query:

   <Route Url="/graphql" Method="POST" Call="GraphQL"/>

Note that this is the only endpoint on the server.

Installing GraphQL and GraphiQL

In order to start using GraphQL, you need to complete a few steps:

  1. Download the latest release from GitHub and import it to the necessary namespace
  2. Go to the system management portal and create a new web application based on your InterSystems Data Platform product (Caché, Ensemble or IRIS):
    • Name - /
    • Namespace - for example, SAMPLES
    • Handler class - GraphQL.REST.Main
  3. GraphiQL — a shell for testing GraphQL queries. Download the latest build or build from the source on your own.
  4. Create a new web application:
    • Name - /graphiql
    • Namespace - for example, SAMPLES
    • Physical path to CSP files - **C:\InterSystems\GraphiQL**

Let’s take a look at the result

Go to the following link in your browser http://localhost:57772/graphiql/index.html (localhost — server, 57772 — port)

GraphiQL

I hope everything is clear with the Query and Response namespaces. A Schema is a document that is generated for all stored classes in a namespace.

The schema contains:

  • Classes
  • Properties, arguments, and their types
  • Descriptions of all of the above generated from comments

Let’s take a closer look at a schema for the Sample_Company class:

GraphiQL also supports automatic code completion that can be activated by pressing the Ctrl + Space key combination:

Queries

Queries can be simple and complex for several sets of data. Below is a sample query for data from to different classes, Sample_Person and Sample_Company:

Filtering

At the moment, only strict equality is supported:

filter

Pagination

Pagination is supported through 4 functions that can be combined to achieve the necessary result:

  • after: n – all records with id greater than n
  • before: n – all records with id smaller than n
  • first: n – first n records
  • last: n – last n records

pagination

Visibility areas

In most situations, the business logic of an application dictates that particular clients only have access to particular namespace classes (role-based permissions). Based on that, you may need to limit class visibility for a client:

  • All classes in the namespace (GraphQL.Scope.All)
  • Classes inherited from a superclass (GraphQL.Scope.Superclass)
  • Classes belonging to a particular package (GraphQL.Scope.Package)

In order to change the method of visibility restriction, open the studio, switch to the necessary namespace, and open the GraphQL.Settings class. It has a SCOPECLASS parameter with the default value of GraphQL.Scope.All — this is the class containing the description of the class visibility interface in the namespace:
scope
To change class visibility restrictions, you need to set one of the values provided above: GraphQL.Scope.Package or GraphQL.Scope.Superclass.

If you picked GraphQL.Scope.Package, you will also need to go to that class and change the value of the Package parameter to the name of the necessary package – for instance, Sample. This will make all the stored classes from this package fully available:

If you picked GraphQL.Scope.Superclass, simply inherit from this class once again in the necessary classes::

Currently supported

Queries:

  • Basic
  • Embedded objects
    • Only many to one relation
  • List of simple types
  • List of objects

Currently under development

Queries:

  • Embedded objects
    • Support of relations of all types
  • Filtering
    • Support of inequalities

Plans

Link to the project repository
Link to the demo server

Issues Pull Requests are very welcome.
Keep an eye on our project updates!

Discussion (24)3
Log in or sign up to continue

As I release my code as Open Source, I've no idea of usage stats.  There's growing interest in the use of GraphQL in the community I work within these days, for all sorts of reasons.

QEWD is a re-badging of EWD 3, so yes, it is supported in QEWD - which of course is straightforward since QEWD is JavaScript/Node.js and can just use the Facebook JavaScript GraphQL module.

Just making the point that GraphQL and support for it in Cache isn't something new, as those who follow our work at M/Gateway will know :-)

Rob

QEWD supports Cache Objects for those who wish to use them via the cache.node APIs for Cache Objects.:

https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY...

Your handler logic (which runs in a QEWD Worker process) has access to these APIs via the "this.db" object, eg this.db.invoke_classmethod()

The following post is a bit old and refers to how you used these APIs in EWD.js.  However, change the invocation to this.db.xxx() and the examples should work in QEWD:

https://groups.google.com/forum/#!searchin/enterprise-web-developer-comm...

Personally I prefer to use the Cache database as a persistent JSON database / Document Database, via the ewd-document-store abstraction that is used by QEWD, and integrate that storage into JavaScript Objects.  But Cache Objects will work with QEWD and GraphQL just fine

Rob

Hi Rob,

I have searched and read through all training materials only for this answer. Probably, it is a good idea to have a separate slide which shows how QEWD can make use of cache object scripts from the handler methods with examples.

This may be useful for:

1. Applications written in Cache object scripts over the years with business logic that is not easy to change in few years of development.

2. Applications using a middle layer and they want to replace it with QEWD to make use of micro-service architecture.

3. New development mainly focusing on back-end logic in Cache database with object oriented programming.

4. And of course, to make use of QEWD while enjoying the Cache object oriented programming style rather than using it as a document store (I think Cache is not mainly used for document store, but because of its value added features and strengths).

Also, to adopt QEWD in Cache based ERP applications, integration of QEWD with Cahce object script is vital.

Any training materials, slides or GitHub source with working examples to use QEWD and cache object scripts is highly recommended.

Thanks,

Jose

After import an error occurred as below.

---------------------------
Studio
---------------------------
ERROR #6301: SAX XML Parser Error: invalid XML encoding declaration '' while processing Anonymous Stream at line 1 offset 32
  > ERROR #5490: Error running generator for method 'DispatchMap:GraphQL.REST.AbstractREST'
ERROR: %CSP.REST.cls(DispatchMap) of generated code compiling subclass 'GraphQL.REST.AbstractREST'
    > ERROR #5030: An error occurred while compiling class 'GraphQL.REST.AbstractREST'
---------------------------
OK   
---------------------------

I am using Cache 2017.2.2.

Any pointers will be a great help.

Thanks,