Denodo GraphQL Service - User Manual

Overview

GraphQL is a data query language, and a runtime for executing those queries against your data.

  • It gives clients the power to ask for exactly what they need.

  • It gets many resources in a single request, reducing the number of API requests.

Denodo GraphQL Service enables the execution of GraphQL queries against the Denodo virtual data model, allowing graphQL-like queries on top of any data source.

Denodo GraphQL Service follows a bottom-up approach where the API specifications are automatically generated from the metadata of the Denodo views and stored procedures.

The GraphQL Service creates a query type for each view and stored procedure of a Denodo database. The view fields appear as children of the view object, and the same occurs for the parameters, in the case of stored procedure objects. Associations in Denodo are mapped to nested relationships between the different objects, so the GraphQL queries will fetch related objects and their fields in one request.

type Query {

    order(order_id: Int, cust_id: Int, total_price: BigInteger, order_desc: String, order_date: Timestamp, last_updated_time: Timestamp, _first: Int, _offset: Int): [order]!

}

type order {

  order_id: Int

  cust_id: Int

  total_price: BigInteger  

  order_desc: String 

  order_date: Timestamp

  last_updated_time: Timestamp

  order_detail: [order_detail]!    # Denodo Association

 

 

}

# Custom Scalar for Timestamp.

# Its format is:yyyy-MM-dd hh:mm:ss[.sss]

scalar Timestamp

                        GraphQL schema for the Denodo view 'order'

Denodo GraphQL Service responses are given in JSON format.

The privilege system of Denodo is enforced, so users see only the views and stored procedures they are authorized to access.

Features

The Denodo GraphQL Service provides:

  • Read-only access to Denodo databases

  • Pagination

  • Filtering (when property graphql.enable.filtering is true)

 

  • Sorting (when property graphql.enable.filtering is true)

  • Group by and aggregation functions (when property graphql.enable.filtering is true)

  • HTTP Authentication

  • Basic

  • SPNEGO (Kerberos)

  • OAuth 2.0

Installation

The Denodo GraphQL Service distribution consists of:

  • Command-line executable scripts for Windows and Linux (/bin folder)

  • Configuration files: application.properties and log4j2.xml (/config folder)

  • Java libraries (/lib folder)

  • Denodo GraphQL Service application jar: denodo-graphql-service-<version>-jar

  • Denodo driver jar: denodo-vdp-jdbcdriver-dist-<version>-full.jar 

If you need to use a Denodo driver version different to the one that is distributed, you only need to replace this jar with the Denodo driver of the proper version.

For installing it just download the .zip file and extract the service into the desired folder.

For running it you need Java 8 and the environment variables JAVA_HOME and PATH correctly configured.

After running the script in the /bin folder, you can use the Denodo GraphQL Service from a GraphQL client, using HTTP Basic Authentication, SPNEGO or OAuth 2.0 with Denodo-valid credentials.

Denodo GraphQL Service runs at: http://localhost:8085/graphql/<DBNAME>

Configuration

The Denodo GraphQL Service has the following properties:

cors.allowed-origins=*

graphql.enable.filtering=true

graphql.max.query.complexity=200

graphql.max.query.depth=5

query.default-page-size=1000

server.admin.enabled=false

server.port=8085

server.servlet.context-path=/graphql

vdp.datasource.driverClassName=com.denodo.vdp.jdbc.Driver

vdp.datasource.jdbcUrl=jdbc:vdb://localhost:9999/?noAuth=true

  • cors.allowed-origins: By default, the value of the property cors.allowed-origins is *. This means that the Service allows CORS requests received from any domain.

To limit the domains from which CORS requests are allowed, change the value of this property: replace * with the list of allowed URLs (separate each URL by a comma). For example, http://foo.com, https://foo.bar.com.

  • graphql.enable.filtering: If true user is allowed to sort data, specify complex filters, group results and calculate aggregation functions in the GraphQL queries. If false the user is only allowed to use GraphQL standard features. Default is true.

  • graphql.max.query.complexity: GraphQL Service prevents the execution of the query if its complexity is greater than the value specified by this property. The complexity is calculated using this formula: 1 + childComplexity. Default is 200.

  • graphql.max.query.depth: GraphQL Service prevents the execution of the query if its depth is greater than the value specified by this property. Default is 5.

  • query.default-page-size: Number of results returned per query. If -1 all results are retrieved. Default is 1000.

  • server.admin.enabled: If false the user account admin (not other administrator accounts) is not able to access the GraphQL Service. This functionality can be used only with HTTP Basic authentication. Default is false.

  • server.port: Port at which the GraphQL Service listens to HTTP requests. Default is 8085.

  • server.servlet.context-path: The server context path. Default is /graphql.

  • vdp.datasource.driverClassName: The full package name of the Denodo driver class. Its value is com.denodo.vdp.jdbc.Driver.

  • vdp.datasource.jdbcUrl: The database URI to access to Denodo from the GraphQL Service. Default is jdbc:vdb://localhost:9999/?noAuth=true.

SSL

Configuring the Denodo GraphQL Service with HTTPs requires two steps:

  1. Obtaining an SSL certificate

  1. Configuring SSL in Denodo GraphQL Service

In this section we focus on the second step, as it is the one that affects the GraphQL Service configuration.

For enabling HTTPS in the Denodo GraphQL Service you have to add Spring Boot server.ssl.* properties to the config/application.properties file. Here is an example:

# custom port instead of the default 8085

server.port=8443

# path to the key store that holds the SSL certificate

server.ssl.key-store=path_to_keystore.jks

# password used to generate the certificate

server.ssl.key-store-password=secret

# password to access the key in the key store

server.ssl.key-password=another-secret

Cross-Origin Resource Sharing (CORS)

CORS is a W3C specification implemented by browsers that allows you to specify what kind of cross domain requests are authorized.

By default, the Denodo GraphQL Service allows requests received from any domain: the value of cors.allowed-origins is * in the config/application.properties file.

To limit the domains from which CORS requests are allowed, change the value of this property: replace * with the list of allowed URLs (separate each URL by a comma). For example,

cors.allowed-origins=http://foo.com, https://foo.bar.com

CORS requests from any other origin will be denied with the HTTP code 403 (Forbidden).

GZIP

In the GraphQL website is recommended that any production GraphQL service enable GZip compression and encourage their clients to send the header:

Accept-Encoding: gzip

Depending on your scenario, compressing the JSON response can increase the performance or not. If it turns out that it is an effective strategy, you can enable GZip in the GraphQL Service adding Spring Boot server.compression.* properties to the config/application.properties file. Here is an example:

# enable response compression

server.compression.enabled=true

# comma-separated list of mime types that should be compressed

server.compression.mime-types=application/json, application/graphql

Denodo Privilege Requirements

Users of Denodo GraphQL Service should have the following Denodo privileges assigned:

  •  At database level

  • Connect

  • At view level

  • Execute: If you do not have Execute access to an entire database, but you have it over some of its elements, the Denodo GraphQL Service only allows to query the elements that you have Execute privileges over.

Schema

Denodo GraphQL Service creates automatically the GraphQL schema from the metadata of the views and stored procedures of a Denodo database.

Denodo 'hibernate' database model

The GraphQL Service generates a query type for each view and each stored procedure. The view fields appear as children of the view object, and the same occurs for the parameters, in the case of stored procedure objects. Associations in Denodo are mapped to nested relationships between the different objects, so the GraphQL queries will fetch related objects and their fields in one request.

Besides being able to use the standard GraphQL introspection mechanisms, you can easily obtain the schema of a Denodo database sending a GET request to the GraphQL Service to: http://localhost:8085/graphql/<DBNAME>/schema.json

Schema request for Denodo 'hibernate' database

The schema describes the set of possible data you can query for that Denodo database.

For example, for the Denodo 'hibernate' database model above, the Denodo GraphQL Service generates this schema:

type Query {

    order(cust_id: Int, order_id: Int, total_price: BigInteger, order_desc: String, order_date: Timestamp, last_updated_time: Timestamp, _first: Int, _offset: Int): [order]!

    order_detail(order_id: Int, prod_id: Int, price: BigInteger, last_updated_time: Timestamp, _first: Int, _offset: Int): [order_detail]!

    product(prod_id: Int, prod_name: String, prod_desc: String, regular_price: BigInteger, last_updated_time: Timestamp, _first: Int, _offset: Int): [product]!

}

type order {

  cust_id: Int

  order_id: Int

  total_price: BigInteger  

  order_desc: String

  order_date: Timestamp

  last_updated_time: Timestamp

  order_detail: [order_detail]!    # Denodo association

}

type order_detail {

  order_id: Int

  prod_id: Int  

  price: BigInteger

  last_updated_time: Timestamp

  orders: order    # Denodo association

  product: product

}

type product {

  prod_id: Int

  prod_name: String

  prod_desc: String

  regular_price: BigInteger

  last_updated_time: Timestamp

  order_detail: [order_detail]!    # Denodo association

}

#Custom Scalar for Timestamp. This type uses ISO8601

scalar Timestamp

Schema  for Denodo 'hibernate' database

Custom scalar types

The Denodo GraphQL Service includes custom scalar types for handling Denodo types not defined in the GraphQL specification:

  • Array: custom scalar for Denodo Array. It is displayed as a String, but it is not supported as an argument in GraphQL queries.

"array_type": "[{value=666-987-8549}, {value=555-125-7841}]"

Array format

  • Blob: custom scalar for Denodo Blob. It is displayed as a String, but it is not supported as an argument in GraphQL queries.

  • LocalDate: custom scalar for Denodo LocalDate. This type formats and parses dates following the ISO-8601 extended local date format: yyyy-MM-dd.

"date_type": "2018-02-04"

LocalDate format

  • IntervalDaySecond: custom scalar for Denodo Intervaldaysecond. It is displayed as a String, but it is not supported as an argument in GraphQL queries.

"intervalds_type": "1 21:01:02.345"

IntervalDaySecond format

  • IntervalYearMonth: custom scalar for Denodo Intervalyearmonth. It is displayed as a String, but it is not supported as an argument in GraphQL queries.

"intervalym_type": "-2-3"

IntervalYearMonth format

  • Struct: custom scalar for Denodo Register. It is displayed as a String, but it is not supported as an argument in GraphQL queries.

"struct_type": "{SALARY=32330.04, NAME=Diane O'Donnell}"

Struct format

  • Time: custom scalar for Denodo Time. This type formats and parses times following the ISO-8601 extended local time format: hh:mm:ss[.sss].

"time_type": "16:06:11"

Time format

  • Timestamp: custom scalar for Denodo Timestamp. This type formats and parses times following the ISO-8601 extended local date and time formats. T delimiter between date and time is omitted: yyyy-MM-dd hh:mm:ss[.sss].

"timestamp_type": "2018-02-04 17:07:06"

Timestamp format

  • Timestamptz: custom scalar for Denodo Timestamptz. This type formats and parses times following the ISO-8601 extended local date and time formats, including the time zone designator. T delimiter between date and time is omitted: yyyy-MM-dd hh:mm:ss[.sss](±hh:mm:ss|Z).

"timestamptz_type": "2018-02-04 16:07:06Z"

Timestamptz format

  • Xml: custom scalar for Denodo Xml. It is displayed as a String, but it is not supported as an argument in GraphQL queries.

Introspection

An alternative way to discover the queries and types available at the Denodo GraphQL Service is the GraphQL introspection system.

For example, if you want to know which fields are available for the GraphQL type order, you can send a POST request to the introspection system:

Introspection request for 'order' type

{

   "data": {

       "__type": {

           "name": "order",

           "kind": "OBJECT",

           "description": null,

           "fields": [

               {

                   "name": "order_id",

                   "type": {

                        "name": "Int",

                        "kind": "SCALAR"

                    }

               },

               {

                   "name": "cust_id",

                   "type": {

                        "name": "Int",

                        "kind": "SCALAR"

                    }

               },

               {

                   "name": "total_price",

                   "type": {

                               "name": "BigInteger",

                               "kind": "SCALAR"

                        }

               },

               {

                   "name": "order_desc",

                   "type": {

                        "name": "String",

                               "kind": "SCALAR"

                        }

               },

               {

                   "name": "order_date",

                   "type": {

                       "name": "Timestamp",

                              "kind": "SCALAR"

                        }

               },

               {

                   "name": "last_updated_time",

                   "type": {

                       "name": "Timestamp",

                              "kind": "SCALAR"

                        }

               },

               {

                   "name": "order_detail",

                   "type": {

                              "name": null,

                              "kind": "NON_NULL"

                        }

               }

           ]

       }

   }

}

Introspection response for 'order' type

Basic querying

This section shows how to query the Denodo GraphQL Service.

Fields

GraphQL is about asking for specific fields on objects. Queries can also traverse related objects and their fields, letting users fetch related data in one request.

In the query of the example below, we are requesting the fields order_id, order_desc and total_price of the object order. Also, for each order, we are retrieving the related object order_detail, with its fields prod_id and price.

Query for 'order' type fields

{

  "data": {

            "order": [

                {

                    "order_id": 111,

                    "order_desc": "Internet and phone",

                    "order_detail": [

                        {

                            "prod_id": 2000,

                            "price": 60

                        },

                        {

                            "prod_id": 2020,

                            "price": 40

                        }

                    ],

                    "total_price": 100

                },

                {

                    "order_id": 222,

                    "order_desc": "Cable at discounted price",

                    "order_detail": [

                        {

                            "prod_id": 2010,

                            "price": 15

                        }

                    ],

                    "total_price": 15

                }

      ]

  }

}

Response for 'order' type fields

Arguments

GraphQL allows to pass arguments to fields to narrow results.

In the query of the example below, we are requesting the fields order_desc and total_price of the object order that has 222 as order_id.

Query with arguments

{

  "data": {

            "order": [

                {

                    "order_desc": "Cable at discounted price",

                    "total_price": 15

                }

             ]

  }

}

Response for query with arguments

Notice that the following custom scalar types are not supported as an argument in GraphQL queries:

  • Array

  • Blob

  • IntervalDaySecond

  • IntervalYearMonth

  • Struct

  • Xml

Aliases

If you want to query for the same fields with different arguments you will need to use aliases to avoid name conflicts.

In the query of the example below, we use first_order and second_order as aliases of the two queries.

Query with aliases

{

  "data": {

            "first_order": [

                {

                    "order_desc": "Internet and phone",

                    "total_price": 100

                }

             ],

            "second_order": [

                {

                    "order_desc": "Cable at discounted price",

                    "total_price": 15

                }

             ]

  }

}

Response for query with aliases

Fragments

Fragments allow you to define a set of fields once and reuse them in all the queries you need, avoiding field repetition.

In the query of the example below, we define the orderFields fragment and use it in both queries first_order and second_order. This is a sample, but in complex scenarios fragments are really useful.

Query with fragment

{

  "data": {

            "first_order": [

                {

                    "order_desc": "Internet and phone",

                    "total_price": 100

                }

             ],

            "second_order": [

                {

                    "order_desc": "Cable at discounted price",

                    "total_price": 15

                }

             ]

  }

}

Response for query with fragment

Variables

Variables are used when the arguments of a query are going to be dynamic. This way, when we want to use the same query with different argument values, we only have to pass a different variable rather than writing a new GraphQL query.

In the query of the example below, $price is a GraphQL variable.

Query with variables

{

  "data": {

            "order_detail": [

                {

                    "order_id": 333,

                    "prod_id": 2000,

                    "last_updated_time": "2018-06-13 17:08:02",

                    "price": 33

                },

                {

                    "order_id": 333,

                    "prod_id": 2010,

                    "last_updated_time": "2018-06-13 17:08:02",

                    "price": 33

                }

            ]

  }

}

Response for query with variables

Directives

The Denodo GraphQL Service includes the two directives defined as mandatory in the specification:

  • @include(if: Boolean): only include this field in the result if the argument is true.

  • @skip(if: Boolean): skip this field if the argument is true.

Query with directive @include

{

  "data": {

            "order": [

                {

                    "order_id": 111,

                    "order_desc": "Internet and phone"

                },

                {

                    "order_id": 222,

                    "order_desc": "Cable at discounted price"

                },

                {

                    "order_id": 333,

                    "order_desc": "3 in one offer"

                }

            ]

  }

}

Response for query with directive @include

Pagination

Denodo GraphQL Service implements offset-based pagination.

The query order_detail(_offset:1, _first:2) asks for the next two order_details in the list, skipping the first one.

The pagination arguments are:

  • _offset: the number of results to skip

  • _first: the number of results to fetch. If _first is not specified, its value is the one configured in the property query.default-page-size that has a default value of 1000.

Query with pagination

{

  "data": {

            "order_detail": [

                {

                    "prod_id": 2010,

                    "price": 33

                },

                {

                    "prod_id": 2020,

                    "price": 33

                }

            ]

  }

}

Response for query with pagination

GraphQL names

Names in GraphQL specification are limited to this ASCII subset of characters:

Denodo GraphQL service escapes disallowed characters with the Unicode escape sequence: \u4_hex_digits but replacing \ with _, as \ is not valid.

The identifiers 29client and na-me of the Denodo table below, are not allowed by the GraphQL specification.

When the Denodo GraphQL Service generates the GraphQL schema it escapes those identifiers of the 29client view:

  • 29client -> _u00329client
  • na-me -> na_u002Dme

type Query {

    _u00329client(client_id: String, na_u002Dme: String, surname: String, client_type: String, company_code: String, ssn: String, _first: Int, _offset: Int): [_u00329client]!

}

type _u00329client {

  client_id: String

  na_u002Dme: String

  surname: String

  client_type: String

  company_code: String

  ssn: String

}

                        GraphQL schema with non ASCII characters

Query with non ASCII characters

{

  "data": {

            "_u00329client": [

                {

                    "na_u002Dme": "John",

                    "client_id": "C001",

                    "client_type": "01",

                    "company_code": "COM01",

                    "ssn": "592-76-8867",

                    "surname": "Smith"

                },

        ...

            ]

  }

}

Response for query with non ASCII characters

Advanced querying

Beyond the GraphQL standard features, Denodo GraphQL Service allows to specify complex filters, sort data, group results and calculate aggregation functions when the property graphql.enable.filtering is true.

Filtering

When graphql.enable.filtering is true, a new optional argument _filter is added to each query definition in the schema generated by Denodo GraphQL Service.

This way, the user can query the GraphQL Service using conditions other than equality and combine them using the and, or and not operators.

In the query of the example below, we select the films that have a rental duration equal to 3 days and a rental rate greater than 3:

Query with complex filtering

{

  "data": {

            "film": [

                {

                    "film_id": 2,

                    "title": "ACE GOLDFINGER",

                    "description": "An Astounding Epistle of a    

                   Database Administrator And an Explorer who  

                   must Find a Car in Ancient China",

                    "length": 48,

                    "rental_duration": 3,

                    "rental_rate": 4.99

                },

        ...

            ]

  }

}

Response for query with complex filtering

Besides the _filter argument the required input types are added to the schema:

type Query {

    order(cust_id: Int, order_id: Int, total_price: BigInteger, order_desc: String, order_date: Timestamp, last_updated_time: Timestamp, _first: Int, _offset: Int, _filter: FilterInput, _orderBy: [SortInput!], _groupBy: [String!]): [order]!

}

# Only one is allowed: eq | neq | gt | gte | lt | lte | in | isnull | like | containsand | containsor | iscontained | regexp_like | regexp_ilike

input FilterExpressionInput {

  containsand: String

  containsor: String

  eq: String

  field: String!

  gt: String

  gte: String

  in: String

  iscontained: String

  isnull: String

  like: String

  lt: String

  lte: String

  neq: String

  regexp_ilike: String

  regexp_like: String

}

# Only one is allowed: and | expression | not | or

input FilterInput {

  and: [FilterInput!]

  expression: FilterExpressionInput

  not: FilterInput

  or: [FilterInput!]

}

                        GraphQL schema for complex filtering

The comparison operators that can be used in complex filtering are the ones defined in the input type FilterExpressionInput and are explained in the Comparison Operators section in the Virtual DataPort Administration Guide.

Filtering limitations

The following custom scalar types are not supported as an input field in this kind of filtering:

  • Array

  • Blob

  • IntervalDaySecond

  • IntervalYearMonth

  • Struct

  • Xml

Also, fields cannot be specified at the same time in the _filter argument and in the field selection set:

Invalid query with complex filtering

Sorting

When graphql.enable.filtering is true, a new argument _orderby is added to each query in the schema generated by Denodo GraphQL Service.

This way, the user can sort data when querying the GraphQL Service.

In the query of the example below, we sort films by their length in a descending order and by their rental rate in ascending order:

Query with sorting

{

  "data": {

            "film": [

       

              {

                    "film_id": 991,

                    "title": "WORST BANGER",

                    "description": "A Thrilling Drama of a Madman And

                  a Dentist who must Conquer a Boy in The

                  Outback",

                    "length": 185,

                    "release_year": "2006-01-01",

                    "rental_rate": 2.99

                },

                {

                    "film_id": 141,

                    "title": "CHICAGO NORTH",

                    "description": "A Fateful Yarn of a Mad Cow And a

                   Waitress who must Battle a Student in

                  California",

                    "length": 185,

                    "release_year": "2006-01-01",

                    "rental_rate": 4.99

                },

        ...

            ]

  }

}

Response for query with sorting

Besides the _orderby argument the required input type is added to the schema:

type Query {

    order(cust_id: Int, order_id: Int, total_price: BigInteger, order_desc: String, order_date: Timestamp, last_updated_time: Timestamp, _first: Int, _offset: Int, _filter: FilterInput, _orderBy: [SortInput!], _groupBy: [String!]): [order]!

}

#Only one is allowed: asc | desc

input SortInput {

  asc: String

  desc: String

}

GraphQL schema for sorting

Group by and aggregation functions

In the schema generated by Denodo GraphQL Service, when graphql.enable.filtering is true, a new argument _groupBy is added to each query and an _aggregation field is added to each view type.

This way, users can group the results and calculate aggregate values (average, sum, max, …) of their data.

In the query of the example below, we retrieve the average rental rate according to the length of films:

Query with group by and aggregation functions

{

  "data": {

            "film": [

                {

                "_aggregation": [

                {

                   "avg": {

                        "field": "rental_rate",

                        "value": 2.59

                    }

                }

                    "length": 46

                },

        ...

            ]

  }

}

Response for query with group by and aggregation functions

Besides the _groupBy argument and the _aggregation field, the required types are added to the schema:

type Query {

    order(cust_id: Int, order_id: Int, total_price: BigInteger, order_desc: String, order_date: Timestamp, last_updated_time: Timestamp, _first: Int, _offset: Int, _filter: FilterInput, _orderBy: [SortInput!], _groupBy: [String!]): [order]!

}

type order {

  cust_id: Int

  order_id: Int

  total_price: BigInteger

  order_desc: String

  last_updated_time: Timestamp

  order_date: Timestamp

  order_detail: [order_detail]!    # Denodo association

  _aggregation: AggregationFunction!

}

type Aggregated {

  field: String!

  value: String!

}

type AggregationFunction {

  avg(field: String): Aggregated

  count: BigInteger

  first(field: String): Aggregated

  last(field: String): Aggregated

  max(field: String): Aggregated

  median(field: String): Aggregated

  min(field: String): Aggregated

  stdev(field: String): Aggregated

  stdevp(field: String): Aggregated

  sum(field: String): Aggregated

  var(field: String): Aggregated

  varp(field: String): Aggregated

}

                        GraphQL schema for group by and aggregation functions

The aggregation functions that can be used are the ones defined in the type AggregationFunction and are explained in the Aggregation Functions section in the Virtual DataPort Administration Guide.

Using an aggregation function more than once in a query

As functions are fields in the AggregationFunction type, we are not able to use the same aggregation function more than once unless we use the alias mechanism provided by GraphQL. Naming each function call with a unique name inside the _aggregation clause will let you repeat any function.

Query with a repeated aggregation function (max)

{

    "data": {

        "film": [

            {

                "_aggregation": {

                    "count": 1000,

                    "max1": {

                        "field": "rental_rate",

                        "value": "4.99"

                    },

                    "max2": {

                        "field": "rental_duration",

                        "value": "7"

                    },

                    "max3": {

                        "field": "length",

                        "value": "185"

                    }

                }

            }

        ]

    }

}

Authentication

Any client using the Denodo GraphQL Service needs to authenticate itself with Denodo-valid credentials.

The authentication methods available are described below.

Basic

In HTTP Basic the Denodo user name and password are passed as unencrypted base64 encoded text with an Authorization HTTP request header.

 <username>:<password> -> Authorization: Basic YWRtaW46YWRtaW4=

SPNEGO (Kerberos)

The HTTP SPNEGO authentication method can only be used when Kerberos authentication is enabled on the Denodo Server. The section Kerberos Authentication of the Virtual DataPort Administration Guide explains how to enable this.

Also, the client has to be configured to use SPNEGO and Kerberos. This article, (section Client Configuration), explains how to configure Internet Explorer and Mozilla Firefox to use the Kerberos-SPNEGO authentication. No special configuration is needed for Google Chrome.

When you connect from a browser to the Denodo GraphQL Service using SPNEGO and Kerberos, instead of having to enter your credentials, the browser will obtain a Kerberos ticket from the system and send it with the request. If the browser requests your credentials, it means that the browser is not correctly configured to use Kerberos authentication or that there was an authentication error.

Notice that for accessing the Denodo GraphQL Service, you have to use the Fully Qualified Domain Name of the Server Principal Name you configured in the Denodo Server. If the server hostname differs, SPNEGO authentication will fail. For example, if the server principal is HTTP/denodo-prod.subnet1.contoso.com@CONTOSO.COM, the client should use http://denodo-prod.subnet1.contoso.com:8085/graphql/<DBNAME>.

OAuth 2.0

To use OAuth2 as an authentication method, you need to enable OAuth authentication on the Denodo server. The section OAuth Authentication of the Virtual DataPort Administration Guide explains how to do this.

Then, you need to obtain an access token. You can use the OAuth 2.0 credentials wizard in VDP Admin Tool to obtain it. The wizard is available at Tools → OAuth credentials wizards → OAuth 2.0 Wizard.

OAuth 2.0 Credentials Wizard

Once you have the access token you have to pass it to the Denodo GraphQL Service with an Authorization request header:

oauth_token -> Authorization: Bearer oauth_token

Resource limitations

Theoretically, GraphQL could allow users to submit very expensive nested queries that could be damaging for the performance of the server.

For this reason, the Denodo GraphQL Service prevents the execution of queries if any of these conditions are met:

  • The query complexity is greater than the value specified by the property graphql.max.query.complexity. Default is 200.

The complexity is based on the number of fields requested and it is calculated using the formula: 1 + childComplexity.

  • The query depth is greater than the value specified by the property graphql.max.query.depth. Default is 5.

Limitations

Mutations and subscriptions

Mutations and subscriptions are not supported.

Group by

The _groupBy clause is only supported for fields of the main entity of the query. For example:

Grouping by fields of related entities is not supported by the Denodo GraphQL Service.

{

    "errors": [

        {

            "message": "Error in _groupBy clause: Grouping by navigational fields is not supported.",

            "extensions": {

                "orderByField": "orders.total_price",

                "invalidClause": "_groupBy",

                "classification": "ValidationError"

            }

        }

    ],

    "data": {

        "order_detail": []

    }

}

Handling of very large result sets

Due to the output validation and serialization requirements imposed by the GraphQL specification, it’s recommended to use large page sizes if the result sets are potentially very large. This way you will reduce the number of pages needed to iterate the result and overall data retrieval performance will improve. However, note that the page size could affect the amount of server memory used by the Denodo GraphQL Service.