# GWP
A standalone, pure Rust gRPC wire protocol for [GQL (ISO/IEC 39075)](https://www.iso.org/standard/76120.html) - the international standard query language for property graphs.
Any GQL-compatible database engine can plug in via the `GqlBackend` trait. GWP handles gRPC transport, session management, transactions, and the full GQL type system over the wire.
## Features
- **Spec-faithful:** Full GQL type system, GQLSTATUS codes, session/transaction semantics
- **Pure Rust:** No C/C++ dependencies, `#![forbid(unsafe_code)]`
- **Lightweight:** Minimal deps: tonic, prost, tokio
- **Fast:** Streaming results via server-side gRPC streaming
- **Embeddable:** Library-first design, usable by any Rust project
- **TLS:** Optional TLS via `tls` feature flag (rustls)
- **Auth:** Pluggable authentication via `AuthValidator` trait
- **Health checks:** Standard `grpc.health.v1.Health` service
- **Observability:** Structured tracing on all gRPC methods via `tracing` crate
- **Graceful shutdown:** Drain connections on signal with `.shutdown()`
## Quick Start
Add to your `Cargo.toml`:
```toml
[dependencies]
gwp = "0.1"
```
### Implementing a Backend
Implement the `GqlBackend` trait to connect your database:
```rust
use gwp::server::{GqlBackend, SessionHandle, TransactionHandle, SessionConfig};
use gwp::error::GqlError;
struct MyDatabase { /* ... */ }
#[tonic::async_trait]
impl GqlBackend for MyDatabase {
async fn create_session(&self, config: &SessionConfig) -> Result<SessionHandle, GqlError> {
// Create a session in your database
Ok(SessionHandle("session-1".to_owned()))
}
async fn execute(
&self,
session: &SessionHandle,
statement: &str,
parameters: &std::collections::HashMap<String, gwp::types::Value>,
transaction: Option<&TransactionHandle>,
) -> Result<std::pin::Pin<Box<dyn gwp::server::ResultStream>>, GqlError> {
// Execute GQL and return a result stream
todo!()
}
// ... other trait methods
}
```
### Starting the Server
```rust
use gwp::server::GqlServer;
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let backend = MyDatabase::new();
let addr = "127.0.0.1:50051".parse()?;
// Quick start with ctrl-c shutdown
GqlServer::start(backend, addr).await?;
Ok(())
}
```
Or use the builder for full control:
```rust
GqlServer::builder(backend)
.idle_timeout(Duration::from_secs(300))
.max_sessions(1000)
.shutdown(async { tokio::signal::ctrl_c().await.unwrap() })
.serve(addr)
.await?;
```
### Using the Client
```rust
use gwp::client::GqlConnection;
use std::collections::HashMap;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut conn = GqlConnection::connect("http://127.0.0.1:50051").await?;
let mut session = conn.create_session().await?;
let mut cursor = session.execute("MATCH (n:Person) RETURN n.name", HashMap::new()).await?;
while let Some(row) = cursor.next_row().await? {
println!("{row:?}");
}
session.close().await?;
Ok(())
}
```
## Architecture
```
Application (GQL statements, parameters, results)
|
v
gRPC Services
- SessionService: handshake, configure, reset, close, ping
- GqlService: execute, begin_transaction, commit, rollback
- CatalogService: schemas, graphs, graph types (catalog > schema > graph)
- AdminService: stats, WAL, validate, indexes
- SearchService: vector, text, hybrid search
- HealthService: grpc.health.v1.Health (check, watch)
|
v
Protocol Buffers (prost)
- Full GQL type system: Value, Node, Edge, Path, Record
- GQLSTATUS codes for structured error reporting
|
v
GqlBackend trait (your database plugs in here)
```
## GQL Type Support
| GQL Type | Wire Representation |
|----------|-------------------|
| `NULL`, `BOOLEAN`, `INTEGER`, `FLOAT`, `STRING`, `BYTES` | Native protobuf types |
| `DATE`, `TIME`, `DATETIME`, `DURATION` | Custom messages |
| `LIST`, `MAP` | Recursive `Value` containers |
| `NODE` | ID + labels + properties |
| `EDGE` | ID + type + endpoints + properties |
| `PATH` | Alternating nodes and edges |
| `BIGINTEGER`, `BIGFLOAT`, `DECIMAL` | String-encoded precision types |
## Modules
| Module | Description |
|--------|-------------|
| `proto` | Generated protobuf types and gRPC stubs |
| `types` | Ergonomic Rust wrappers over proto types |
| `server` | `GqlBackend` trait, session/transaction management, gRPC server |
| `client` | `GqlConnection`, `GqlSession`, `ResultCursor`, `Transaction`, `CatalogClient`, `AdminClient`, `SearchClient` |
| `error` | `GqlError` enum |
| `status` | GQLSTATUS code constants and helpers |
## Client Bindings
| Language | Package | Install |
| ---------- | ------- | ------- |
| Python | [gwp-py](https://pypi.org/project/gwp-py/) | `pip install gwp-py` |
| JavaScript/TypeScript | [gwp-js](https://www.npmjs.com/package/gwp-js) | `npm install gwp-js` |
| Go | `github.com/GrafeoDB/gwp/go` | `go get github.com/GrafeoDB/gwp/go` |
| Java | `dev.grafeo:gwp` | Maven Central |
All bindings include `GqlConnection`, `GqlSession`, `Transaction`, `ResultCursor`, and `CatalogClient`.
## Requirements
- Rust 1.85.0+ (edition 2024)
- `protoc` (Protocol Buffers compiler) - required at build time
## License
Licensed under either of [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) or [MIT license](http://opensource.org/licenses/MIT) at your option.