Skip to main content

Transform to GraphQL requests

Overview

Relixy can rewrite the URL, body and headers from RESTful to GraphQL requests before forwarding them to the upstream and rewrite responses before returning them to the client. Transformations are configured per-operation using the x-rely-proxy-action vendor extension on an OpenAPI operation object.

The extension accepts one object with a type field plus optional request and response sections.

FieldRequiredDescription
typeYesAlways graphql for GraphQL operations.
requestNoTransformation applied to the outgoing request.
responseNoTransformation applied to the incoming response.

Transformation

Example

The following example shows an operation that:

  1. Rewrites the upstream path and transforms variables in the path template.
  2. Adds custom header derived from a path parameter.
  3. Transforms the request body to a different shape.
  4. Transforms the response to a different shape.
paths:
/characters/{id}:
get:
operationId: getCharacterById
description: "Get character by ID"
x-rely-proxy-action:
type: graphql
request:
url: "/graphql"
headers:
X-User-Id:
path: "param.id"
X-Query-Filter:
path: "query.filter"
X-Content-Type:
path: 'headers."content-type"'
query: |
query Character($id: ID!) {
character(id: $id) {
id
name
}
}
variables:
id:
type: field
path: param.id
extensions:
someExtension:
type: field
default:
value: someValue
response:
contentType: application/json
httpErrorCode: 400
body:
type: gotmpl
template: |
{
"id": "{{.body.account_id}}",
"displayName": "{{.body.display_name}}",
"email": "{{.body.contact.email}}"
}

Request

GraphQL query

The GraphQL query is mandatory for GraphQL requests. Variables in the query string are parsed and replaced with request parameters in the runtime. You can also define selection queries for variables.

x-rely-proxy-action:
type: graphql
request:
query: |
query Character($id: ID!) {
character(id: $id) {
id
name
}
}

Transform GraphQL variables

Variables are an object with selection fields that use JMESPath expression to select them from the request. In this example, the $id variable is selected from the id parameter in the request path.

x-rely-proxy-action:
type: graphql
request:
variables:
id:
type: field
path: param.id

The available input object for JMESPath expressions:

KeyTypeDescription
paramobjectPath parameters (e.g., param.id for {id})
queryobjectQuery string parameters
headersobjectRequest headers (keys are lowercased)
bodyanyParsed request body.

Override the request URL

Use request.url to replace the upstream URL. In most cases, you don't need to override the URL because the graphql URL is fixed. Setting the server URL is enough.

x-rely-proxy-action:
type: graphql
request:
url: "/graphql"

Transform headers

Use request.headers to add or override headers on the upstream request. Values are JMESPath expressions evaluated against the request data.

x-rely-proxy-action:
type: graphql
request:
headers:
X-User-Id:
path: "param.id"
X-Query-Filter:
path: "query.filter"
X-Content-Type:
path: 'headers."content-type"'

The available input object for JMESPath expressions:

KeyTypeDescription
paramobjectPath parameters (e.g., param.id for {id})
queryobjectQuery string parameters
headersobjectRequest headers (keys are lowercased)
bodyanyParsed request body

Transform request extensions

You can define optional extensions for GraphQL requests via the request.extensions object. Similar to variables, are an object with selection fields that use JMESPath expression to select them from the request.

x-rely-proxy-action:
type: graphql
request:
extensions:
someExtension:
type: field
default:
value: someValue

Response

Transform the response body

Use response.body with a Go template to rewrite the response body returned to the client.

x-rely-proxy-action:
type: graphql
response:
contentType: application/json
body:
type: gotmpl
template: |
{
"id": "{{.body.account_id}}",
"displayName": "{{.body.display_name}}",
"email": "{{.body.contact.email}}"
}

The template context for response transformations is the parsed JSON response body from the upstream, accessible as .body.

Transform HTTP status on error

GraphQL generally returns HTTP 200 status when errors happened. It causes confusion for users because the RESTful specification expects HTTP status to be 400 or larger. You can use response.httpErrorCode field to configure the default expected status for error responses.

x-rely-proxy-action:
type: graphql
response:
httpErrorCode: 400

You can indicate specific HTTP statuses for individual errors with evaluation rules that uses JMESPath expressions. If all rules aren't matched those expressions, the engine falls back to the default httpErrorCode.

x-rely-proxy-action:
type: graphql
response:
httpErrorCode: 400
httpErrors:
"404":
- 'errors[0].extensions.code == "NOT_FOUND"'
- 'errors[0].message == "Not found"'

For example, if the response body of GraphQL has NOT_FOUND code in extensions of the first error item, the response status will be transformed to 404 Not Found.

{
"errors": [
{
"message": "User not found",
"locations": [{ "line": 2, "column": 3 }],
"extensions": {
"code": "NOT_FOUND"
}
}
]
}