2018-11-23 16:02:46 +03:00
Remote schemas
==============
2018-12-03 15:12:24 +03:00
.. contents :: Table of contents
:backlinks: none
:depth: 2
:local:
2019-01-18 07:18:54 +03:00
Hasura gives you CRUD + realtime GraphQL APIs with authorization & access control. However, in many cases, you will
need to write APIs (queries, mutations) that contain custom logic. For example, implementing a payment API, or
querying data that is not in your database.
2018-11-23 16:02:46 +03:00
Hasura has the ability to merge remote GraphQL schemas and provide a unified GraphQL API. Think of it
2019-01-18 07:18:54 +03:00
like automated schema stitching. All you need to do is build your own GraphQL service and then provide the HTTP
endpoint to Hasura. Your GraphQL service can be written in any language or framework.
2018-11-23 16:02:46 +03:00
This is what Hasura running with "Remote schemas" looks like:
2019-03-13 13:03:45 +03:00
.. thumbnail :: ../../../img/graphql/manual/remote-schemas/remote-schemas-arch.png
2018-11-23 16:02:46 +03:00
:class: no-shadow
2019-03-13 13:03:45 +03:00
:width: 75%
2020-01-08 16:20:18 +03:00
:alt: Architecture of Hasura with remote schemas
2018-11-23 16:02:46 +03:00
.. note ::
2019-01-18 07:18:54 +03:00
This is a new feature under active development. Please do give us feedback, bug-reports and ask us questions on
2019-01-15 13:49:58 +03:00
our `discord <https://discord.gg/vBPpJkS> `__ or on `github <https://github.com/hasura/graphql-engine> `__ .
2018-11-23 16:02:46 +03:00
2019-09-11 10:17:14 +03:00
Use cases
2018-11-23 16:02:46 +03:00
---------
- Custom business logic, like a payment API
- Querying data that is not available in your database
2019-09-11 10:17:14 +03:00
You can handle these use cases by writing resolvers in a custom GraphQL server
2019-01-18 07:18:54 +03:00
and making Hasura merge this "remote schema" with the existing auto-generated
2018-12-12 15:01:18 +03:00
schema. You can also add multiple remote schemas. Think of the merged schema as
a union of top-level nodes from each of the sub-schemas.
2019-01-18 07:18:54 +03:00
.. note ::
2018-11-23 16:02:46 +03:00
2019-01-18 07:18:54 +03:00
If you are looking for adding authorization & access control for your
app users to the GraphQL APIs that are auto-generated via Hasura, head to
2019-05-17 15:03:35 +03:00
:doc: `../auth/index`
2018-11-23 16:02:46 +03:00
2019-01-18 07:18:54 +03:00
Adding a remote schema
----------------------
2018-11-23 16:02:46 +03:00
2019-09-11 10:17:14 +03:00
Follow the steps below to add a "remote schema" to the Hasura GraphQL engine:
2018-11-23 16:02:46 +03:00
2019-01-18 07:18:54 +03:00
Step 1: Write a custom GraphQL server
2018-11-23 16:02:46 +03:00
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You need to create a custom GraphQL server with a schema and corresponding resolvers that solve your use case
2019-01-18 07:18:54 +03:00
(*if you already have a functional GraphQL server that meets your requirements, you can skip this step* ).
2018-11-23 16:02:46 +03:00
2019-01-18 07:18:54 +03:00
You can use any language/framework of your choice to author this server and deploy it anywhere. A great way to get
started is to use one of our boilerplates:
2018-12-12 15:01:18 +03:00
2019-01-18 07:18:54 +03:00
- `Boilerplates <https://github.com/hasura/graphql-engine/tree/master/community/boilerplates/remote-schemas> `__
2018-11-23 16:02:46 +03:00
2019-05-06 14:27:34 +03:00
.. _merge_remote_schema:
2019-01-18 07:18:54 +03:00
Step 2: Merge remote schema
2018-11-23 16:02:46 +03:00
^^^^^^^^^^^^^^^^^^^^^^^^^^^
2019-09-11 10:17:14 +03:00
To merge your remote schema with the GraphQL engine's auto-generated schema:
2019-01-18 07:18:54 +03:00
2019-09-11 10:17:14 +03:00
Head to the `` Remote Schemas `` tab of the console and click on the `` Add `` button.
2018-11-23 16:02:46 +03:00
2019-03-13 13:03:45 +03:00
.. thumbnail :: ../../../img/graphql/manual/business-logic/add-remote-schemas-interface.png
2020-01-08 16:20:18 +03:00
:alt: Merge remote schema
2018-11-23 16:02:46 +03:00
You need to enter the following information:
2019-09-11 10:17:14 +03:00
- **Remote Schema name** : an alias for the remote schema that must be unique on an instance of the GraphQL engine.
2018-11-23 16:02:46 +03:00
- **GraphQL server URL** : the endpoint at which your remote GraphQL server is available. This value can be entered
2019-03-06 11:58:04 +03:00
manually or by specifying an environment variable that contains this information.
.. note ::
2019-10-04 09:49:58 +03:00
During **local development** with the remote schema server on localhost, ensure that the Hasura Docker container can reach
the server endpoint on the host. A common way to do this is to use the domain `` host.docker.internal `` on Docker for Mac and Windows or the Docker bridge IP on Linux (typically `` 172.17.0.1 `` - the IP address of `` docker0 `` interface. use `` ip addr show docker0 `` ) instead of `` 127.0.0.1 `` .
Similarly, if you are adding the URL using env variable, then run the Hasura docker container with the env variable added during `docker run` . Example `` -e REMOTE_SCHEMA_ENDPOINT=http://host.docker.internal:4000/mycustomgraphql ``
2019-03-06 11:58:04 +03:00
2019-09-11 10:17:14 +03:00
- **Headers** : configure the headers to be sent to your custom GraphQL server:
2018-11-23 16:02:46 +03:00
- Toggle forwarding all headers sent by the client (when making a GraphQL query) to your remote GraphQL server.
2019-09-11 10:17:14 +03:00
- Send additional headers to your remote server - these can be static header name-value pairs; and/or pairs of
"header name-environment variable name". You can specify the value of the header to be picked up from the environment
2019-01-18 07:18:54 +03:00
variable.
2018-11-23 16:02:46 +03:00
2019-01-18 07:18:54 +03:00
**Example** : Let's say your remote GraphQL server needs a `` X-Api-Key `` as a header. As this value contains
2019-09-11 10:17:14 +03:00
sensitive data (like API key in this example), you can configure the name of an environment variable which will hold
the value. This environment variable needs to be present when you start the GraphQL engine. When Hasura sends
2019-01-18 07:18:54 +03:00
requests to your remote server, it will pick up the value from this environment variable.
2018-11-23 16:02:46 +03:00
2019-01-18 07:18:54 +03:00
.. admonition :: Using environment variables
2018-11-23 16:02:46 +03:00
2019-01-18 07:18:54 +03:00
If you are using environment variables in the remote schema configuration - either
for URL or headers - **the environment variables need to be present** with valid values
2019-09-11 10:17:14 +03:00
when adding the remote schema i.e. the GraphQL engine should be started with these environment variables.
2018-11-23 16:02:46 +03:00
Click on the `` Add Remote Schema `` button to merge the remote schema.
2019-01-18 07:18:54 +03:00
Step 3: Make queries to the remote server from Hasura
2018-11-23 16:02:46 +03:00
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2019-01-18 07:18:54 +03:00
Now you can head to the `` GraphiQL `` tab and make queries to your remote server from Hasura.
2018-11-23 16:02:46 +03:00
2019-05-10 09:05:11 +03:00
You can query your remote server by making requests to the Hasura GraphQL endpoint (`` /v1/graphql `` ).
2018-11-23 16:02:46 +03:00
2019-01-18 07:18:54 +03:00
Points to remember
------------------
2018-11-23 16:02:46 +03:00
2019-01-18 07:18:54 +03:00
Remote schema fields nomenclature
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2018-11-23 16:02:46 +03:00
2019-01-18 07:18:54 +03:00
- Top-level field names need to be unique across all merged schemas (*case-sensitive match* ).
- Types with the *exact same name and structure* will be merged. But types with the *same name but different
structure* will result in type conflicts.
2018-11-23 16:02:46 +03:00
2019-07-08 08:51:41 +03:00
Schema refreshing
^^^^^^^^^^^^^^^^^
For versions <= `` v1.0.0-beta.2 `` , GraphQL schema of each added remote server is refreshed every time a
metadata modifying operation like adding tables/functions, defining relationships/permissions etc. is done.
From `` v1.0.0-beta.3 `` onwards, a remote server's GraphQL schema is cached and refreshed only when user
2019-09-11 10:17:14 +03:00
explicitly reloads remote schema by clicking the `` Reload `` button on the console or
by making a :doc: `reload_remote_schema<../api-reference/schema-metadata-api/remote-schemas>` metadata API request
2019-07-08 08:51:41 +03:00
2019-01-18 07:18:54 +03:00
Current limitations
^^^^^^^^^^^^^^^^^^^
- Nodes from different GraphQL servers cannot be used in the same query/mutation. All top-level fields have to be
from the same GraphQL server.
- Subscriptions on remote GraphQL servers are not supported.
These limitations will be addressed in upcoming versions.
2018-11-23 16:02:46 +03:00
2019-01-18 07:18:54 +03:00
Extending the auto-generated GraphQL schema fields
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2019-09-11 10:17:14 +03:00
For some use cases, you may need to extend the GraphQL schema fields exposed by the Hasura GraphQL engine
2019-01-18 07:18:54 +03:00
(*and not merely augment as we have done above* ) with a custom schema/server. To support them, you can use
2019-09-11 10:17:14 +03:00
community tooling to write your own client-facing GraphQL gateway that interacts with the GraphQL engine.
2019-01-18 07:18:54 +03:00
.. note ::
2019-09-11 10:17:14 +03:00
**Adding an additional layer on top of the Hasura GraphQL engine significantly impacts the performance provided by
it out of the box** (* by as much as 4x*). If you need any help with remodelling these kinds of use cases to use the
2019-01-18 07:18:54 +03:00
built-in remote schemas feature, please get in touch with us on `Discord <https://discord.gg/vBPpJkS> `__ .
2019-05-06 14:27:34 +03:00
Authorization in your remote schema server
------------------------------------------
Hasura will forward the resolved `` x-hasura-* `` values as headers to your remote
schema. You can use this information to apply authorization rules in your
server. You don't have to redo authentication in your remote schema server.
You can also configure Hasura to have (as shown :ref: `above <merge_remote_schema>` ):
1. static header values that are sent to the remote server
2. forward all headers from the client (like `` Authorization `` , `` Cookie `` headers etc.)
In case there are multiple headers with same name, the order of precedence is:
2019-09-11 10:17:14 +03:00
configuration headers > resolved user (`` x-hasura-* `` ) variables > client headers.
2019-05-06 14:27:34 +03:00
2019-09-11 10:17:14 +03:00
So for example, if the client sends an `` Authorization `` header, and the
configuration also has an `` Authorization `` header, the configuration header value
2019-05-06 14:27:34 +03:00
will selected.
.. note ::
2019-09-11 10:17:14 +03:00
The headers from the client behave similarly to the authorization system. If
2019-05-06 14:27:34 +03:00
`` x-hasura-admin-secret `` is sent, then all `` x-hasura-* `` values from the
client are respected, otherwise they are ignored.
2019-06-04 13:10:28 +03:00
Cookie header from your remote GraphQL servers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`` Set-Cookie `` headers from your remote schema servers are sent back to the
2019-09-11 10:17:14 +03:00
client over HTTP transport. **Over websocket transport there exists no means
of sending headers after a query/mutation and hence the `` Set-Cookie `` headers are
not sent to the client.** Use HTTP transport if your remote servers set cookies.
2019-06-04 13:10:28 +03:00
2019-05-06 14:27:34 +03:00
2019-01-18 07:18:54 +03:00
Bypassing Hasura's authorization system for remote schema queries
-----------------------------------------------------------------
It might be necessary sometimes to bypass Hasura's authorization system (calling
the configured webhook, or validating the JWT), for queries that are for a
remote GraphQL server.
**For example** , you have a remote GraphQL server which does authentication,
i.e. signup and login, and you have added it as a remote schema. In this case,
you would not want to perform Hasura's authorization when the user is making a
login/signup request.
There is no first-class option to currently do this via any configuration in
2019-09-11 10:17:14 +03:00
Hasura. However a similar solution can be achieved by the following workarounds:
2019-01-18 07:18:54 +03:00
Bypassing webhook authorization
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2019-05-17 15:03:35 +03:00
If you have a :doc: `webhook authorization setup <../auth/authentication/webhook>` , in the normal scenario, your authorization
2019-01-18 07:18:54 +03:00
webhook would return `` 200 `` on success and `` 401 `` if it is either unable to authorize the current request or if
the authorization information is absent (like cookie, authorization header etc.)
To bypass the webhook auth:
- the webhook should respond with `` 200 `` and `` x-hasura-role: anonymous `` instead of a `` 401 `` when the
authorization information is absent or if it fails to resolve the authorization information.
- when adding the remote schema, check the `` Forward all headers from client `` option so that the remote server
will get the relevant cookie/header (from the client) and the role `` anonymous `` .
Bypassing JWT authorization
^^^^^^^^^^^^^^^^^^^^^^^^^^^
2019-05-17 15:03:35 +03:00
If you have a :doc: `JWT authorization setup <../auth/authentication/jwt>` , to bypass the JWT auth:
2019-01-18 07:18:54 +03:00
- your authentication server should generate a static JWT token for `` anonymous `` i.e. unauthenticated users.
- when adding the remote schema, check the `` Forward all headers from client `` option so that the remote server
will get the JWT (from the client).
For example, the generated JWT can be:
.. code-block :: json
{
"sub": "0000000000",
"iat": 1516239022,
"role": "anonymous",
"https://hasura.io/jwt/claims": {
"x-hasura-allowed-roles": ["anonymous"],
"x-hasura-default-role": "anonymous"
}
}
Hasura will get this JWT and successfully validate it. When your remote server receives this JWT, it should
2019-09-11 10:17:14 +03:00
specifically validate the JWT and, for example, check for the `` role `` key in the JWT. If it is set to `` anonymous `` ,
2019-01-18 07:18:54 +03:00
then it should consider the request as unauthenticated.