Install
openclaw skills install graphql-graph-mappingMap GraphQL queries and schemas to underlying graph database operations, enabling applications to access knowledge graph data through GraphQL APIs. Translates GraphQL schemas/queries to Cypher, Gremlin, SPARQL, and resolves results back to GraphQL response format.
openclaw skills install graphql-graph-mappingBridge GraphQL APIs and graph databases by translating GraphQL schemas and queries into graph database operations.
This skill enables seamless integration between GraphQL APIs and graph databases by translating GraphQL queries into native database queries (Cypher, Gremlin, SPARQL) and mapping results back to GraphQL response format. It allows developers to expose graph data through a clean GraphQL API layer.
GraphQL types map naturally to graph entities:
| GraphQL Concept | Graph Concept | Example |
|---|---|---|
| Object Type | Node Type/Label | type Person → :Person label |
| Field | Node Property | name: String → Person.name |
| Relationship Field | Edge/Relationship | friends: [Person] → KNOWS relationship |
| ID Field | Node Identifier | id: ID! → Node unique identifier |
| Query Root | Graph Traversal Entry | Query field returns starting nodes |
| Nested Fields | Graph Traversal | Nested fields resolve relationships |
GraphQL queries are translated to graph database queries following a systematic process:
{
person(id: "alice") {
name
age
knows {
name
}
}
}
person(id: "alice") → Find Person node with id="alice"name → Person.name propertyage → Person.age propertyknows → KNOWS relationship to other Person nodesCypher (Neo4j):
MATCH (p:Person {id: "alice"})
RETURN p.name, p.age,
[(p)-[:KNOWS]->(f:Person) | {name: f.name}] AS knows
Gremlin (JanusGraph, TigerGraph):
g.V().has("Person","id","alice")
.project("name","age","knows")
.by("name")
.by("age")
.by(out("KNOWS").has("Person"))
SPARQL (RDF):
SELECT ?name ?age ?friendName
WHERE {
ex:alice ex:name ?name ;
ex:age ?age ;
ex:knows ?friend .
?friend ex:name ?friendName .
}
{
person(id: "alice") {
name
email
}
}
Maps to: SELECT statement with specific properties
{
people(where: {age: {gt: 30}}) {
name
age
}
}
Maps to: WHERE clauses with comparison operators
{
person(id: "alice") {
name
worksAt {
name
industry
employees {
name
}
}
}
}
Maps to: Multi-hop graph traversals
{
alice: person(id: "alice") { name }
bob: person(id: "bob") { name }
}
Maps to: Multiple graph traversals with aliases
{
people(first: 10, after: "cursor123") {
nodes {
name
}
pageInfo {
hasNextPage
endCursor
}
}
}
Maps to: LIMIT and OFFSET clauses
{
personStats {
count
averageAge
byDepartment {
department
count
}
}
}
Maps to: AGGREGATION and GROUP BY operations
GraphQL:
{
person(id: "alice") {
name
friends {
name
}
}
}
Cypher Output:
MATCH (p:Person {id: "alice"})-[:KNOWS]->(f:Person)
RETURN p.name, collect(f.name) AS friends
Features:
Gremlin Output:
g.V().has("Person","id","alice")
.project("name","friends")
.by("name")
.by(out("KNOWS").has("Person").values("name").fold())
Features:
SPARQL Output:
PREFIX ex: <http://example.org/>
SELECT ?name ?friendName
WHERE {
ex:alice ex:name ?name ;
ex:knows ?friend .
?friend ex:name ?friendName .
}
Features:
type Person {
id: ID! # Unique identifier
name: String! # Property
age: Int # Property
email: String # Property
knows: [Person] # Relationship
worksAt: Company # Relationship
posts: [Post] # Relationship
}
Maps to graph:
Person → Node label/typeid → Node identifier propertyname, age, email → Node propertiesknows, worksAt, posts → Outgoing relationshipstype Person {
knows(first: Int, after: String): PersonConnection!
}
type PersonConnection {
nodes: [Person!]!
pageInfo: PageInfo!
}
Maps to:
Prevent expensive deep traversals:
Default max depth: 5 levels
Configurable per schema
Simple field: 1 point
Relationship traversal: 2 points
List field: multiplied by max items
Max allowed: 100-1000 points
| Error | Cause | Solution |
|---|---|---|
| Field not found | Property doesn't exist | Add property to graph schema |
| Invalid relationship | Relationship type mismatch | Update schema mapping |
| Query timeout | Expensive traversal | Add depth limit or filter |
| Missing node | ID doesn't exist | Return null or error |
| Type mismatch | Field type differs | Coerce or validate types |
✓ Use stable, meaningful identifiers - Base IDs on unique properties
✓ Implement query depth limits - Prevent expensive traversals
✓ Cache schema metadata - Avoid re-parsing
✓ Validate queries early - Fail fast on invalid queries
✓ Index frequently filtered fields - Improve query performance
✓ Document schema mappings - Keep API contract clear
✓ Test edge cases - Handle null relationships gracefully
✓ Monitor query performance - Track slow queries
✓ Implement query complexity scoring - Prevent abuse
✓ Version your GraphQL schema - Support schema evolution
This skill integrates with:
graphql-core - GraphQL query parsing and validationgraphene - Python GraphQL frameworkstrawberry - Modern Python GraphQLneo4j - Official Neo4j driverneo4j-graphql - GraphQL to Cypher translationneomodel - Python ORM for Neo4jpyparsing - Query string parsingsqlalchemy - Query builder patternssqlglot - SQL/Graph query translationpydantic - Data validationjsonschema - JSON schema validationmarshmallow - Schema validationVersion: 1.0.0