Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
* Updated all default Gremlin Server configs to remove Groovy dependency from initialization.
* Added script engine allowlist to Gremlin Server - the `scriptEngines` YAML configuration now restricts which engines can serve requests; `gremlin-lang` is always available.
* Modified request parameters from `Map<String, Object>` to gremlin-lang compatible `String`.
* Renamed the request `bindings` field to `parameters` across the HTTP request body, GraphBinary, and GraphSON, standardizing terminology for query parameters.
* Modified HTTP API to expect gremlin-lang strings for parameters and update all GLVs to send requests in new format.
* Added string parameter parsing to `GremlinServer` to prevent traversal injection and excessive nesting depths.
* Modified all GLVs to detect unsupported types in `GremlinLang` and throw consistent error for that case.
Expand Down
4 changes: 2 additions & 2 deletions docs/src/dev/io/graphson.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -2751,7 +2751,7 @@ The following `RequestMessage` is an example of a simple sessionless request for
"@value": 1000
},
"g": "g",
"bindings": {
"parameters": {
"@type": "g:Map",
"@value": [
"x",
Expand All @@ -2772,7 +2772,7 @@ The following `RequestMessage` is an example of a simple sessionless request for
"materializeProperties": "tokens",
"timeoutMs": 1000,
"g": "g",
"bindings": {
"parameters": {
"x": 1
},
"language": "gremlin-groovy"
Expand Down
6 changes: 3 additions & 3 deletions docs/src/dev/provider/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -1198,7 +1198,7 @@ Gremlin-Hints: <hints>
{
"gremlin": string,
"timeoutMs": number,
"bindings": string,
"parameters": string,
"g": string,
"language" : string,
"materializeProperties": string,
Expand Down Expand Up @@ -1258,7 +1258,7 @@ the serializer specified by the `Content-Type` header. The following are the key
|Key |Description |Value |Required
|gremlin |The Gremlin query to execute. |String containing script |Yes
|timeoutMs |The maximum time a query is allowed to execute in milliseconds. |Number between 0 and 2^31-1 |No
|bindings |A gremlin-lang string that contains a map used during query execution. Its usage depends on "language". For "gremlin-groovy", these are the variable bindings. For "gremlin-lang", these are the parameter bindings. |Object (Map) |No
|parameters |A gremlin-lang string that encodes a map of key/value pairs used during query execution. Its usage depends on "language". For "gremlin-groovy", these are applied as script variable bindings. For "gremlin-lang", these are the query parameters. |String containing a gremlin-lang map literal |No
|g |The name of the graph traversal source to which the query applies. Default: "g" |String containing traversal source name |No
|language |The name of the ScriptEngine to use to parse the gremlin query. Default: "gremlin-lang" |String containing ScriptEngine name |No
|materializeProperties |Whether to include all properties for results. One of "tokens" or "all". |String |No
Expand All @@ -1270,7 +1270,7 @@ the serializer specified by the `Content-Type` header. The following are the key

When Gremlin Server receives that request, it will decode it given the "mime type", and execute it using the
`ScriptEngine` specified by the `language` field. In this case, it will evaluate the script `g.V(x).out()` using the
`bindings` supplied in the `args` and stream back the results in HTTP chunks. When the chunks are combined, they will
`parameters` supplied in the `args` and stream back the results in HTTP chunks. When the chunks are combined, they will
form a single `ResponseMessage`. The HTTP response containing the `ResponseMessage` has the following form:

[source,text]
Expand Down
23 changes: 8 additions & 15 deletions docs/src/reference/gremlin-applications.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ list = g.V().has("person","name","marko").out("knows").toList()
// script
client, err := NewClient("http://localhost:8182/gremlin")
resultSet, err := client.SubmitWithOptions("g.V().has('person','name',name).out('knows')",
new(RequestOptionsBuilder).AddBinding("name", "marko").Create())
new(RequestOptionsBuilder).AddParameter("name", "marko").Create())
result, err := resultSet.All()

// traversal
Expand Down Expand Up @@ -805,21 +805,14 @@ returns:

`POST` is the only supported method for this endpoint. This means that `GET` with query parameters is not supported.

It is also preferred that Gremlin scripts be parameterized when possible via `bindings`:
It is also preferred that Gremlin scripts be parameterized when possible via `parameters`:

[source,text]
curl -X POST -d "{\"gremlin\":\"100-x\", \"bindings\":{\"x\":1}}" "http://localhost:8182"
curl -X POST -d "{\"gremlin\":\"100-x\", \"parameters\":\"[x:1]\"}" "http://localhost:8182"

The `bindings` argument is a `Map` of variables where the keys become available as variables in the Gremlin script.
Note that parameterization of requests is critical to performance, as repeated script compilation can be avoided on
each request.

NOTE: It is possible to pass bindings via `GET` based requests. Query string arguments prefixed with "bindings." will
be treated as parameters, where that prefix will be removed and the value following the period will become the
parameter name. In other words, `bindings.x` will create a parameter named "x" that can be referenced in the submitted
Gremlin script. The caveat is that these arguments will always be treated as `String` values. To ensure that data
types are preserved or to pass complex objects such as lists or maps, use `POST` which will at least support the
allowed JSON data types.
The `parameters` argument is a gremlin-lang string that encodes a map of key/value pairs where the keys become available
as variables in the Gremlin script. Note that parameterization of requests is critical to performance, as repeated
script compilation can be avoided on each request.

NOTE: The Gremlin Server does not support link:https://en.wikipedia.org/wiki/HTTP_pipelining[HTTP pipelining]. Sending
a second request on the same connection before the first response completes will cause the server to close the
Expand All @@ -845,7 +838,7 @@ Finally, as Gremlin Server can host multiple `ScriptEngine` instances (e.g. `gre
possible to define the language to utilize to process the request:

[source,text]
curl -X POST -d "{\"gremlin\":\"100-x\", \"language\":\"gremlin-groovy\", \"bindings\":{\"x\":1}}" "http://localhost:8182"
curl -X POST -d "{\"gremlin\":\"100-x\", \"language\":\"gremlin-groovy\", \"parameters\":\"[x:1]\"}" "http://localhost:8182"

By default this value is set to `gremlin-groovy`. If using a `GET` operation, this value can be set as a query
string argument with by setting the `language` key.
Expand Down Expand Up @@ -1769,7 +1762,7 @@ continuously:
client = Cluster.build("localhost").port(8182).create().connect()
==>org.apache.tinkerpop.gremlin.driver.Client$ClusteredClient@42ff9a77
client.submit("while(true) { }")
org.apache.tinkerpop.gremlin.driver.exception.ResponseException: A timeout occurred during traversal evaluation of [RequestMessage{, fields={bindings={}, language=gremlin-groovy, batchSize=64}, gremlin=while(true) { }}] - consider increasing the limit given to evaluationTimeout
org.apache.tinkerpop.gremlin.driver.exception.ResponseException: A timeout occurred during traversal evaluation of [RequestMessage{, fields={parameters={}, language=gremlin-groovy, batchSize=64}, gremlin=while(true) { }}] - consider increasing the limit given to evaluationTimeout

The `GroovyCompilerGremlinPlugin` has a number of configuration options:

Expand Down
6 changes: 3 additions & 3 deletions docs/src/reference/gremlin-variants.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -518,14 +518,14 @@ options := new(RequestOptionsBuilder).
SetEvaluationTimeout(5000).
SetBatchSize(32).
SetMaterializeProperties("tokens").
AddBinding("x", 100).
AddParameter("x", 100).
Create()
resultSet, err := client.SubmitWithOptions("g.V(x).count()", options)
----

The following options are allowed on a per-request basis in this fashion: `batchSize`, `bulkResults`, `userAgent`,
`evaluationTimeout` and `materializeProperties`.
`RequestOptions` may also contain a map of variable `bindings` to be applied to the supplied
`RequestOptions` may also contain a map of query `parameters` to be applied to the supplied
traversal string.

[source,go]
Expand Down Expand Up @@ -2316,7 +2316,7 @@ for await (const item of client.stream('g.V()', null)) {
}
----

`client.stream()` accepts the same parameters as `client.submit()`: a script string, optional bindings, and optional
`client.stream()` accepts the same arguments as `client.submit()`: a script string, optional parameters, and optional
per-request settings.

[source,javascript]
Expand Down
33 changes: 33 additions & 0 deletions docs/src/upgrade/release-4.x.x.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,39 @@ complete list of all the modifications that are part of this release.

=== Upgrading for Users

==== Bindings are now Parameters

The map of named values substituted into a Gremlin query was previously called "bindings" in some places and
"parameters" in others. TinkerPop now refers to these consistently as *query parameters*, reserving "bindings" for
the distinct concept of `ScriptEngine` variable bindings. As a result, the driver methods for supplying query
parameters have been renamed. Update any code that sets them:

- Java: `RequestMessage.Builder.addBindings(...)` is now `addParameters(...)`.
- Python: `client.submit(..., bindings=...)` is now `submit(..., parameters=...)`, and the `request_options`
key `bindings` is now `parameters`.
- Go: `SetBindings`/`SetBindingsString`/`AddBinding` are now
`SetParameters`/`SetParametersString`/`AddParameter`.
- .NET: `AddBinding`/`AddBindings`/`AddBindingsString` are now
`AddParameter`/`AddParameters`/`AddParametersString`.
- JavaScript: `addBinding`/`addBindings`/`addBindingsString` are now
`addParameter`/`addParameters`/`addParametersString`, and the `RequestOptions.bindings` field is now `parameters`.

For example, in the Java driver:

[source,java]
----
final Map<String, Object> params = new HashMap<>();
params.put("x", 1);

// 3.x
RequestMessage.build("g.V(x)").addBindings(params).create();

// 4.x
RequestMessage.build("g.V(x)").addParameters(params).create();
----

See: link:https://issues.apache.org/jira/browse/TINKERPOP-3262[TINKERPOP-3262]

==== Standardizing GLV Connection Options

TinkerPop 4.x standardizes connection option names and defaults across all five Gremlin Language Variants (Java, Python,
Expand Down
26 changes: 13 additions & 13 deletions gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClientExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace Gremlin.Net.Driver
public static class GremlinClientExtensions
{
/// <summary>
/// Submits a request message that consists of a script with bindings as an asynchronous operation where only a single
/// Submits a request message that consists of a script with parameters as an asynchronous operation where only a single
/// result gets returned.
/// </summary>
/// <remarks>
Expand All @@ -44,7 +44,7 @@ public static class GremlinClientExtensions
/// <typeparam name="T">The type of the expected result.</typeparam>
/// <param name="gremlinClient">The <see cref="IGremlinClient" /> that submits the request.</param>
/// <param name="requestScript">The Gremlin request script to send.</param>
/// <param name="bindings">Bindings for parameters used in the requestScript.</param>
/// <param name="parameters">Parameters used in the requestScript.</param>
/// <param name="cancellationToken">The token to cancel the operation. The default value is None.</param>
/// <returns>A single result received from the Gremlin Server.</returns>
/// <exception cref="Exceptions.ResponseException">
Expand All @@ -53,10 +53,10 @@ public static class GremlinClientExtensions
/// </exception>
public static async Task<T?> SubmitWithSingleResultAsync<T>(this IGremlinClient gremlinClient,
string requestScript,
Dictionary<string, object>? bindings = null,
Dictionary<string, object>? parameters = null,
CancellationToken cancellationToken = default)
{
await using var resultSet = await gremlinClient.SubmitAsync<T>(requestScript, bindings, cancellationToken)
await using var resultSet = await gremlinClient.SubmitAsync<T>(requestScript, parameters, cancellationToken)
.ConfigureAwait(false);
await foreach (var item in resultSet.WithCancellation(cancellationToken).ConfigureAwait(false))
{
Expand Down Expand Up @@ -94,22 +94,22 @@ public static class GremlinClientExtensions
}

/// <summary>
/// Submits a request message that consists of a script with bindings as an asynchronous operation without returning
/// Submits a request message that consists of a script with parameters as an asynchronous operation without returning
/// the result received from the Gremlin Server.
/// </summary>
/// <param name="gremlinClient">The <see cref="IGremlinClient" /> that submits the request.</param>
/// <param name="requestScript">The Gremlin request script to send.</param>
/// <param name="bindings">Bindings for parameters used in the requestScript.</param>
/// <param name="parameters">Parameters used in the requestScript.</param>
/// <param name="cancellationToken">The token to cancel the operation. The default value is None.</param>
/// <returns>The task object representing the asynchronous operation.</returns>
/// <exception cref="Exceptions.ResponseException">
/// Thrown when a response is received from Gremlin Server that indicates
/// that an error occurred.
/// </exception>
public static async Task SubmitAsync(this IGremlinClient gremlinClient, string requestScript,
Dictionary<string, object>? bindings = null, CancellationToken cancellationToken = default)
Dictionary<string, object>? parameters = null, CancellationToken cancellationToken = default)
{
await using var resultSet = await gremlinClient.SubmitAsync<object>(requestScript, bindings, cancellationToken).ConfigureAwait(false);
await using var resultSet = await gremlinClient.SubmitAsync<object>(requestScript, parameters, cancellationToken).ConfigureAwait(false);
// Drain the stream to ensure the background task completes and resources are released.
await foreach (var _ in resultSet.WithCancellation(cancellationToken).ConfigureAwait(false))
{
Expand Down Expand Up @@ -139,12 +139,12 @@ public static async Task SubmitAsync(this IGremlinClient gremlinClient, RequestM
}

/// <summary>
/// Submits a request message that consists of a script with bindings as an asynchronous operation.
/// Submits a request message that consists of a script with parameters as an asynchronous operation.
/// </summary>
/// <typeparam name="T">The type of the expected results.</typeparam>
/// <param name="gremlinClient">The <see cref="IGremlinClient" /> that submits the request.</param>
/// <param name="requestScript">The Gremlin request script to send.</param>
/// <param name="bindings">Bindings for parameters used in the requestScript.</param>
/// <param name="parameters">Parameters used in the requestScript.</param>
/// <param name="cancellationToken">The token to cancel the operation. The default value is None.</param>
/// <returns>A <see cref="ResultSet{T}"/> containing the data and status attributes returned from the server.</returns>
/// <exception cref="Exceptions.ResponseException">
Expand All @@ -153,12 +153,12 @@ public static async Task SubmitAsync(this IGremlinClient gremlinClient, RequestM
/// </exception>
public static async Task<ResultSet<T>> SubmitAsync<T>(this IGremlinClient gremlinClient,
string requestScript,
Dictionary<string, object>? bindings = null,
Dictionary<string, object>? parameters = null,
CancellationToken cancellationToken = default)
{
var msgBuilder = RequestMessage.Build(requestScript);
if (bindings != null)
msgBuilder.AddBindings(bindings);
if (parameters != null)
msgBuilder.AddParameters(parameters);
var msg = msgBuilder.Create();
return await gremlinClient.SubmitAsync<T>(msg, cancellationToken).ConfigureAwait(false);
}
Expand Down
Loading
Loading