blob: 12bad68e940e660ac6e203a9952cf4da7f2d49a0 [file] [view]
# Cypher API response compatibility
The Cypher endpoint is
`/graphspaces/{graphspace}/graphs/{graph}/cypher`. Submit one statement per
request. GET accepts the `cypher` query argument and does not accept a parameter
map; use POST for parameterized queries. POST with `Content-Type: application/json`
accepts a JSON object containing a nonblank string `cypher` and an optional
object `parameters`, for example:
```json
{
"cypher": "MATCH (n:person) WHERE n.name = $name RETURN n.name",
"parameters": {"name": "marko"}
}
```
Legacy raw Cypher bodies sent as `application/json` remain accepted. JSON arrays,
scalars, malformed JSON, missing/non-string/blank `cypher`, and a `parameters`
value of null, an array or a scalar are rejected by HTTP request validation.
Omitting `parameters` supplies an empty map. Additional request fields and extra
parameter names are allowed; every parameter referenced by the parsed query must
be present. Individual parameter values may explicitly be null.
Requests are limited to 16 top-level parameter names. This limit is fixed; see
[Cypher HTTP contracts](server-runtime.md#cypher-http-contracts) for the binding
limits and validation rules.
The Server checks missing bindings before executing the traversal, so GET, raw
POST and JSON POST with an absent referenced name fail with `Missing Cypher
parameter: name`. This uses the execution-failure envelope below, classified as
`HugeGraph.Cypher.ExecutionError` with an empty hint. The upstream translator's
standalone unbound-to-null behavior is not the Server request contract. Do not
send `?parameters=...` to bind a GET query. Invalid binding values, including the
reserved translator null marker, also fail before traversal execution; explicit
JSON null values are accepted and normalized by the Server.
## Authentication
Cypher follows the Server authentication mode. When authentication is disabled,
GET and POST requests do not require an `Authorization` header, and the Server
uses an anonymous Gremlin connection. Both the request's `Authorization` header
and credentials in `conf/remote-objects.yaml` are ignored. Mixed modes with REST
authentication disabled and Gremlin authentication enabled are unsupported.
When authentication is enabled, requests still need
valid Basic or Bearer credentials and retain the caller's graph permissions.
Use `bin/enable-auth.sh` to configure authentication consistently for both REST
and Gremlin; enabling only the REST authenticator does not protect the Gremlin
endpoint used to execute Cypher.
The Gremlin host and port in `conf/remote-objects.yaml` must point to the same
Server's Gremlin endpoint, including when using nondefault ports.
The API test runner exercises anonymous GET and POST before enabling
authentication, then runs the authenticated suite, including missing-header
rejection and a read-only user's write and cross-graph rejection cases.
## Response envelope
Responses retain the Gremlin-compatible top-level fields `requestId`, `status`
and `result`. There is no top-level `errors` field. Existing Java clients can
continue to deserialize both successful and failed queries without an upgrade.
A successful query has `status.code = 200`, an empty `status.attributes` map,
and its rows in `result.data`, for example:
```json
{
"requestId": "example-request",
"status": {"message": "", "code": 200, "attributes": {}},
"result": {"data": [{"value": 1}], "meta": {}}
}
```
When query submission or execution fails inside the Cypher client, the existing
HTTP 200 / `status.code = 400` convention and `status.message` are preserved.
Authentication, request validation and other HTTP-layer errors remain separate
and need not use this envelope. Consumers must inspect `status.code` instead of
relying only on the HTTP status.
Structured error metadata lives at `status.attributes.errors`, an array with
one entry for the failed query. Each entry contains a stable string `code`, the
translator/execution `message`, and a `hint` (empty when no specific guidance is
available). Message wording is not a stable contract. Example:
```json
{
"requestId": "example-request",
"status": {
"message": "Expected exactly one statement per query but got: 2",
"code": 400,
"attributes": {
"errors": [{
"code": "HugeGraph.Cypher.SyntaxError",
"message": "Expected exactly one statement per query but got: 2",
"hint": "Submit exactly one Cypher statement per request"
}]
}
},
"result": {"data": null, "meta": {}}
}
```
Clients that only consume `status.code`, `status.message` and `result` can ignore
the attributes. A failure with no mapped metadata may have empty attributes.
## Error codes and hints
| Code | Recognized failure | Hint |
| --- | --- | --- |
| `HugeGraph.Cypher.SyntaxError` | Parser invalid input, unknown function or semantic error with a `(line N, column M (offset: K))` suffix | Check the query syntax and function names supported by the built-in Cypher translator |
| `HugeGraph.Cypher.SyntaxError` | More or fewer than one statement | Submit exactly one Cypher statement per request |
| `HugeGraph.Cypher.SyntaxError` | `Variable` followed by a backtick-quoted name and `not defined` | Declare the variable in a MATCH, UNWIND or WITH clause before referencing it |
| `HugeGraph.Cypher.ExecutionError` | Undefined vertex label, edge label, property key or index label | Create the schema element via the schema API before running the query |
| `HugeGraph.Cypher.UnsupportedFeature` | Translator messages beginning `Unsupported clause:`, `Unsupported match pattern:`, `Unsupported create pattern:`, `Unsupported property type:`, `Multiple labels are not supported:` or `Custom functions and predicates are not supported on target implementation:` | This construct is not covered by the built-in translator, see the Cypher compatibility guide for supported syntax |
| `HugeGraph.Cypher.ExecutionError` | Other failures, including unrecognized translation failures | Empty string |
`ExecutionError` is also the fallback for unrecognized translation failures; it
does not mean traversal execution has started. For example, `reduce(...)` or
semantic rejections without a recognized position suffix may return this code
with an empty hint while preserving the original failure message. Classification
recognizes only the translation-1.0.4 forms above and does not cover every
translator failure; runtime errors such as `Unsupported predicate` and
`CONTAINS query ... is not supported` also fall back.
There is no `HugeGraph.Cypher.MissingParameter` contract.
This contract repairs the unreleased proposal in
[Server #3241](https://github.com/apache/hugegraph/pull/3241). The paired website
work is [Doc #499](https://github.com/apache/hugegraph-doc/pull/499); its author
must incorporate this response contract before coordinated publication.
Parameterized POST requests are already provided by merged
[Server #3289](https://github.com/apache/hugegraph/pull/3289).
The earlier [bound-query fork #238](https://github.com/hugegraph/hugegraph/pull/238)
is a historical reference; use the current request contract above.
## Temporal functions
The built-in translator has no temporal functions of its own. The Server folds
the `date()`, `datetime()` and `localdatetime()` constructors into native date
values before translation, so these calls work wherever a bound value is
accepted, for example `MATCH (n) WHERE n.birthday = date('2000-01-01') RETURN n`.
A constructor folds when it has no argument (the current date or date-time), a
string literal argument, or a parameter bound to a string; `date()` uses the
`yyyy-MM-dd` form and the other two use `yyyy-MM-ddTHH:mm:ss[.SSS]`. Arguments
that are not foldable, other temporal forms such as map or duration arguments,
and the remaining temporal functions (`time()`, `localtime()`, `duration()`)
keep failing translation with `Unknown function` as before.
Constructor names are case-insensitive like the rest of Cypher, and the bare
constructors of one statement read the clock once. EXPLAIN prints a folded
value as an explicit `new Date(...)` constructor instead of a stringified date.
## Regression checks
Run the mapper, real-parser and envelope tests from the repository root:
```sh
mvn test -pl hugegraph-server/hugegraph-test -am -P unit-test \
-Dtest=CypherErrorTest,CypherClientTest,CypherOpProcessorTest \
-Dsurefire.failIfNoSpecifiedTests=false
```
`CypherApiTest` also exercises malformed syntax, multiple statements, undefined
variables and missing schema through a running test server. Its `testParameters`
and `testMissingParameterHasFallbackError` cover bound JSON requests and missing
bindings. `CypherClientTest` checks outgoing query/binding transport, and
`CypherOpProcessorTest` covers request binding validation. The mapper's
translator-only unbound-parameter test bypasses that validation. Follow the normal
Server API-test setup using disposable test data.
The standalone `CypherClientCompatibilityTest` uses the actual Java Client
`Response` and `RestResult` classes. It is outside the Server reactor's source
roots to avoid a Server-to-Client dependency cycle. Supply an existing Client
jar (checked with locally available 1.7.0 and development 1.8.0 artifacts) and run from the repository root:
```sh
mvn -f hugegraph-server/hugegraph-api/pom.xml dependency:build-classpath \
-Dmdep.outputFile="$PWD/target/cypher-classpath.txt"
CYPHER_CLIENT_JAR="$HOME/.m2/repository/org/apache/hugegraph/hugegraph-client/1.7.0/hugegraph-client-1.7.0.jar"
CYPHER_CP="$CYPHER_CLIENT_JAR:$(cat target/cypher-classpath.txt)"
mkdir -p target/cypher-compatibility
javac -encoding UTF-8 -proc:none -cp "$CYPHER_CP" \
-d target/cypher-compatibility \
hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/cypher/CypherModel.java \
hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/cypher/CypherErrorMapper.java \
hugegraph-server/hugegraph-test/src/compatibility/java/CypherClientCompatibilityTest.java
java -cp "target/cypher-compatibility:$CYPHER_CP" \
org.junit.runner.JUnitCore CypherClientCompatibilityTest
```
These checks cover legacy envelopes, current success/failure deserialization,
status/message preservation, and a negative control proving that a top-level
`errors` field is rejected. They do not certify a live Hubble deployment or
matching-release-candidate acceptance.