Skip to content

Commit

Permalink
experimental externalisation on the router service via configuration (#…
Browse files Browse the repository at this point in the history
…2229)

fixes: #1916 

Simplified externalisation configuration:

```
plugins:
  experimental.external:
    url: http://127.0.0.1:8081
    timeout: 2s
    stages:
      router:
        request:
          headers: true
          context: true
          body: true
          sdl: true
        response:
          headers: true
```
The biggest pro is that it's just so simple it's very easy to configure.
The biggest con is lack of control: e.g. no control over header
propagation. The only supported stage at this moment is "router".
  • Loading branch information
garypen authored Dec 19, 2022
1 parent dba6ffb commit e19eccf
Show file tree
Hide file tree
Showing 20 changed files with 1,275 additions and 26 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 27 additions & 1 deletion NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,35 @@ By [@bnjjj](https://github.com/bnjjj) in https://github.com/apollographql/router

## 🥼 Experimental


### Introduce a `router_service` ([Issue #1496](https://github.com/apollographql/router/issues/1496))

A `router_service` is now part of our service stack, which allows plugin developers to process raw http requests and raw http responses, that wrap the already available `supergraph_service`

By [@o0Ignition0o](https://github.com/o0Ignition0o) in https://github.com/apollographql/router/pull/2170

### Introduce an externalization mechanism based on `router_service` ([Issue #1916](https://github.com/apollographql/router/issues/1916))

If external extensibility is configured, then a block of data is transmitted (encoded as JSON) to an endpoint via an HTTP POST request. The router will process the response to the POST request before resuming execution.

Conceptually, an external co-processor performs the same functionality as you may provide via a rust plugin or a rhai script within the router. The difference is the protocol which governs the interaction between the router and the co-processor.

Sample configuration:

```yaml
plugins:
experimental.external:
url: http://127.0.0.1:8081 # mandatory URL which is the address of the co-processor
timeout: 2s # optional timeout (2 seconds in this example). If not set, defaults to 1 second
stages: # In future, multiple stages may be configurable
router: # Currently, the only valid value is router
request: # What data should we transmit to the co-processor from the router request?
headers: true # All of these data content attributes are optional and false by default.
context: true
body: true
sdl: true
response: # What data should we transmit to the co-processor from the router response?
headers: true
context: true
```
By [@garypen](https://github.com/garypen) in https://github.com/apollographql/router/pull/2229
1 change: 1 addition & 0 deletions apollo-router/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ serde_json = { version = "1.0.89", features = ["preserve_order"] }
serde_urlencoded = "0.7.1"
serde_yaml = "0.8.26"
static_assertions = "1.1.0"
strum_macros = "0.24.3"
sys-info = "0.9.1"
thiserror = "1.0.37"
tokio = { version = "1.23.0", features = ["full"] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,81 @@ expression: "&schema"
"properties": {
"experimental.expose_query_plan": {
"type": "boolean"
},
"experimental.external": {
"type": "object",
"required": [
"url"
],
"properties": {
"stages": {
"default": null,
"type": "object",
"properties": {
"router": {
"default": null,
"type": "object",
"properties": {
"request": {
"default": null,
"type": "object",
"properties": {
"body": {
"default": false,
"type": "boolean"
},
"context": {
"default": false,
"type": "boolean"
},
"headers": {
"default": false,
"type": "boolean"
},
"sdl": {
"default": false,
"type": "boolean"
}
},
"nullable": true
},
"response": {
"default": null,
"type": "object",
"properties": {
"body": {
"default": false,
"type": "boolean"
},
"context": {
"default": false,
"type": "boolean"
},
"headers": {
"default": false,
"type": "boolean"
},
"sdl": {
"default": false,
"type": "boolean"
}
},
"nullable": true
}
},
"nullable": true
}
},
"nullable": true
},
"timeout": {
"default": null,
"type": "string"
},
"url": {
"type": "string"
}
}
}
},
"additionalProperties": false
Expand Down
5 changes: 4 additions & 1 deletion apollo-router/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::time::Instant;
use dashmap::mapref::multiple::RefMulti;
use dashmap::mapref::multiple::RefMutMulti;
use dashmap::DashMap;
use serde::Deserialize;
use serde::Serialize;
use tower::BoxError;

Expand All @@ -27,12 +28,14 @@ pub(crate) type Entries = Arc<DashMap<String, Value>>;
/// provide [`crate::SubgraphRequest`] or [`crate::SubgraphResponse`] processing. At such times,
/// plugins should restrict themselves to the [`Context::get`] and [`Context::upsert`]
/// functions to minimise the possibility of mis-sequenced updates.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Context {
// Allows adding custom entries to the context.
entries: Entries,

/// Creation time
#[serde(skip)]
#[serde(default = "Instant::now")]
pub(crate) created_at: Instant,
}

Expand Down
9 changes: 9 additions & 0 deletions apollo-router/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,3 +443,12 @@ impl ParseErrors {
};
}
}

/// Error types for licensing.
#[derive(Error, Display, Debug, Clone, Serialize, Deserialize)]
pub(crate) enum LicenseError {
/// Apollo graph reference is missing
MissingGraphReference,
/// Apollo key is missing
MissingKey,
}
Loading

0 comments on commit e19eccf

Please sign in to comment.