Skip to main content

RESTified Endpoints Plugin for Hasura DDN

Overview

Relixy can be an alternative for Hasura's RESTified Endpoints Plugin that allows you to add RESTified GraphQL endpoints to DDN. This can be used to add custom REST endpoints to DDN that will execute a specified GraphQL query on the DDN GraphQL API and return the response.

The plugin integrates with Hasura DDN as a pre-route plugin and can be deployed as an HTTP service to cloud services that support containers such as Cloud Run, Docker, and Kubernetes.

Get Started

Disclaimer

This example is borrowed from the official Hasura DDN docs so you can easily migrate from RESTified Endpoints Plugin to Relixy and vice versa.

In this example, we're going to use a Docker image to configure Relixy as a RESTified Endpoints Plugin for Hasura DDN. You can use similar configurations to deploy the plugin using Kubernetes or any other container orchestration tool.

1. Set up plugin for local development

Add the following service to your root-level compose.yaml file (this is the one located at <project-root>/compose.yaml). Add this new service at the same level as your existing services entries:

restified-endpoints:
image: ghcr.io/relychan/relixy-ddn:latest
ports:
- 8787:8080
environment:
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://local.hasura.dev:4317}
GRAPHQL_SERVER_URL: http://engine:3000/graphql
RELIXY_CONFIG_PATH: /plugin_config/relixy.yaml
HASURA_M_AUTH: ${HASURA_M_AUTH}
volumes:
- type: bind
source: ./relixy
target: /plugin_config
read_only: true
labels:
io.hasura.ddn.service-name: restified-endpoints
extra_hosts:
- local.hasura.dev:host-gateway

Here, we're setting up the restified-endpoints service from the relixy-ddn image. We're also forwarding the plugin_config directory to the container. This directory will contain the configuration for the plugin. Here is the structure of the plugin_config directory:

plugin_config/
├── relixy.yaml
└── resources
└── my-api.yaml

Create plugin_config/relixy.yaml in your project directory with the minimum configurations:

definition:
include:
- "./resources/*.yaml"

2. Create an OpenAPI resource

Create plugin_config/resources/my-api.yaml for API definitions:

version: v1
kind: OpenAPI
metadata:
name: my-api
definition:
settings:
headers: {}
forwardHeaders:
request: ["X-Hasura-Role", "Authorization", "X-Hasura-ddn-token"]
response: []
spec:
servers:
- # Define a static URL
# url: http://engine:3000/graphql
# Or as an environment variable
url: "{GRAPHQL_SERVER_URL}"
paths:
/v1/api/rest/artistbyname/{name}:
get:
operationId: artistByName
x-rely-proxy-action:
type: graphql
request:
query: |
query artistByName($name: string!) {
artist(where: {
name: { _eq: $name }
}) {
name
}
}
# (optional) In the case if you need to customize variables mapping.
# variables:
# name:
# path: param.name
/v1/api/rest/artists:
get:
operationId: artists
x-rely-proxy-action:
type: graphql
request:
query: |
query artists($limit: Int = 10, $offset: Int = 0) {
artist(limit: $limit, offset: $offset) {
name
}
}
# (optional) In the case if you need to customize variables mapping.
# variables:
# limit:
# path: query.limit[0]
# default:
# value: 19
# offset:
# path: query.offset[0]
# default:
# value: 0

The configuration of OpenAPI resource includes:

  • settings: Global configurations for resource:
    • headers: Additional headers to be sent to the GraphQL server.
    • forwardHeaders: Headers to be forwarded:
      • request: Headers to be forwarded from the request to the GraphQL server.
      • response: Headers to be forwarded from the GraphQL server to the response.
  • spec: defines specification of REST APIs. The specification follows the schema structure of the OpenAPI 3.x specification with extensions:
    • servers: Defines server endpoints. The endpoint can be a static string or an environment variable named in {braces}.
    • paths: Similar to OpenAPI v3, it holds the relative paths to the individual endpoints and their operations. The path is appended to the URL from the Server Object in order to construct the full URL:
      • <method>: Defines the operation for a HTTP method. The operation follows the Operation Object of OpenAPI v3 with extensions:
        • x-rely-proxy-action: defines the behavior of the operation:
          • type: Type of the action. In this example, we use graphql.
          • request: Defines the request body of GraphQL request:
            • query: The GraphQL query string for constructing the GraphQL request.
            • variables: Defines mapping rules for variables object. If you don't explicitly set variables, Relixy will automatically map path and query parameters to this object.
              • <key>:
                • path: Define the mapping rule from REST request to GraphQL variables using JMESPath expression.
                • default: Define the default value if the field does not exist in the request:
                  • value: A literal value.
                  • env: Or an environment variable.

3. Create a RelyAuth resource

Create plugin_config/resources/auth.yaml for authentication:

version: v1
kind: RelyAuth
definition:
settings: {}
modes:
- mode: apiKey
tokenLocation:
in: header
name: hasura-m-auth
value:
env: HASURA_M_AUTH
sessionVariables: {}

Because Relixy is an internal plugin that receives requests from Hasura DDN engine, we configure a simple API key mode for machine-to-machine authentication. In this example, the API key should be in the hasura-m-auth header. You can use any strong key here to authenticate the plugin. The value is from HASURA_M_AUTH environment variable.

4. Add the plugin configuration

We'll let the engine know about the plugin and to execute it as a pre-route plugin by creating a new metadata file. In your global subgraph's metadata directory, create a new file named globals/restified-endpoints.hml and add the following configuration.

kind: LifecyclePluginHook
version: v1
definition:
pre: route
name: restified_endpoints
url:
valueFromEnv: RESTIFIED_ENDPOINTS_URL
config:
matchPath: "/v1/api/rest/*"
matchMethods: ["GET", "POST"]
request:
method: POST
headers:
forward:
- Authorization
- x-hasura-role
- x-hasura-ddn-token
additional:
hasura-m-auth:
valueFromEnv: M_AUTH_KEY
rawRequest:
path: {}
query: {}
method: {}
body: {}
response:
headers:
additional:
content-type:
value: application/json

Next, update the subgraph.yaml file to include the environment variables.

kind: Subgraph
version: v2
definition:
name: globals
...
includePaths:
...
envMapping:
RESTIFIED_ENDPOINTS_URL:
fromEnv: RESTIFIED_ENDPOINTS_URL
M_AUTH_KEY:
fromEnv: M_AUTH_KEY

Finally, we need to add the environment variables to the .env file.

RESTIFIED_ENDPOINTS_URL="http://local.hasura.dev:8787"
M_AUTH_KEY="your-strong-m-auth-key"

5. Run everything

At this point, you can run the following command to build and start local development:

ddn supergraph build local
ddn run docker-start

You can now test the plugin by making a request to the RESTified GraphQL endpoints defined in the plugin's configuration.

After making changes to the plugin configuration, you should restart the docker services to take effect.