Files
markitect-main/docs/graphql_interface.md
tegwick 2dd1704e51 feat: implement comprehensive GraphQL read interface (issue #9)
Adds a complete GraphQL API for querying MarkiTect database content including:

CORE FEATURES:
- Type-safe GraphQL schema with comprehensive field definitions
- Full database access: markdown files, schemas, ASTs, and metadata
- Advanced search capabilities with relevance scoring
- Pagination support for efficient data access
- Real-time schema introspection and development tools

IMPLEMENTATION:
- GraphQL schema definition with 6 core types (MarkdownFile, Schema, AST, etc.)
- Complete resolver implementation with database integration
- Flask-based GraphQL server with CORS support
- GraphQL Playground for interactive development
- Health check and schema introspection endpoints

CLI INTEGRATION:
- graphql-serve: Start GraphQL server with customizable options
- graphql-query: Execute queries from command line (local/remote)
- graphql-schema: Retrieve schema definition in SDL/JSON format
- graphql-examples: Comprehensive usage examples and documentation

API FEATURES:
- Single item queries (by ID or filename)
- List queries with filtering and pagination
- Full-text search across files and schemas
- Database statistics and analytics
- AST querying with JSONPath expressions
- Computed fields (word count, line count, etc.)

TESTING:
- Comprehensive test suite with 38 passing tests
- Unit tests for schema, resolvers, server, and client
- Integration tests for query execution
- Error handling and edge case coverage
- Mock and fixture support for isolated testing

DOCUMENTATION:
- Complete API documentation with examples
- Usage guide for all CLI commands
- Programming examples in Python and JavaScript
- Performance optimization guidelines
- Troubleshooting and security considerations

The GraphQL interface enables developers to build rich applications on top of
MarkiTect data with flexible, efficient querying capabilities.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-03 11:53:53 +02:00

12 KiB

GraphQL Read Interface for MarkiTect

Overview

The GraphQL read interface provides a powerful, type-safe way to query MarkiTect's database content including Markdown files, ASTs, schemas, and metadata. This interface enables developers to build rich applications on top of MarkiTect's data with flexible querying capabilities.

Features

  • Complete Type Safety: Strongly-typed GraphQL schema with comprehensive field definitions
  • Flexible Querying: Query exactly the data you need with GraphQL's selective field syntax
  • Rich Data Access: Access markdown files, schemas, ASTs, and computed fields
  • Search Capabilities: Full-text search across files and schemas with relevance scoring
  • Pagination Support: Efficient pagination for large datasets
  • Real-time Introspection: Schema introspection and GraphQL Playground for development
  • Multiple Access Methods: HTTP server, local execution, and CLI integration

Getting Started

Prerequisites

Install the required dependencies:

pip install graphene flask flask-cors jsonpath-ng requests

Starting the GraphQL Server

Start the GraphQL server using the CLI:

markitect graphql-serve

By default, this starts the server on http://localhost:5000. You can customize the host and port:

markitect graphql-serve --host 0.0.0.0 --port 8080

Accessing the GraphQL Playground

Once the server is running, visit http://localhost:5000/graphql in your browser to access the GraphQL Playground, an interactive development environment for testing queries.

GraphQL Schema

Core Types

MarkdownFile

Represents a Markdown file in the MarkiTect database:

type MarkdownFile {
  id: Int!
  filename: String!
  content: String
  frontMatter: [FrontMatter]
  frontMatterRaw: JSONString
  createdAt: DateTime
  wordCount: Int
  lineCount: Int
  hasFrontMatter: Boolean
}

Schema

Represents a JSON schema:

type Schema {
  id: Int!
  filename: String!
  title: String
  description: String
  schemaContent: JSONString!
  createdAt: DateTime
  updatedAt: DateTime
  schemaVersion: String
  propertyCount: Int
}

AST

Represents an Abstract Syntax Tree for a Markdown file:

type AST {
  fileId: Int
  filename: String!
  tree: [ASTNode]
  metadata: JSONString
  headingCount: Int
  linkCount: Int
  imageCount: Int
  codeBlockCount: Int
}

DatabaseStats

Provides statistics about the MarkiTect database:

type DatabaseStats {
  totalFiles: Int
  totalSchemas: Int
  totalSizeBytes: Int
  lastUpdated: DateTime
}

SearchResult

Represents search results across files and schemas:

type SearchResult {
  type: String!
  score: Float
  file: MarkdownFile
  schema: Schema
  highlight: String
}

Query Operations

Single Item Queries

Get a specific markdown file:

{
  markdownFile(id: 1) {
    id
    filename
    content
    wordCount
    hasFrontMatter
  }
}

Get a specific schema:

{
  schema(filename: "user-schema.json") {
    title
    description
    schemaVersion
    propertyCount
  }
}

Get AST for a file:

{
  ast(filename: "document.md") {
    headingCount
    linkCount
    tree {
      type
      value
      level
    }
  }
}

List Queries

Get all markdown files with pagination:

{
  markdownFiles(limit: 10, offset: 0) {
    id
    filename
    createdAt
    hasFrontMatter
  }
}

Filter files by front matter presence:

{
  markdownFiles(hasFrontMatter: true, limit: 5) {
    filename
    frontMatter {
      key
      value
    }
  }
}

Get all schemas:

{
  schemas(limit: 20) {
    filename
    title
    description
    propertyCount
  }
}

Search Queries

Search across all content:

{
  search(query: "documentation", type: "all", limit: 10) {
    type
    score
    file {
      filename
      content
    }
    schema {
      title
      description
    }
    highlight
  }
}

Search only in files:

{
  search(query: "API", type: "file", limit: 5) {
    score
    file {
      filename
      wordCount
    }
    highlight
  }
}

Database Statistics

Get database overview:

{
  databaseStats {
    totalFiles
    totalSchemas
    totalSizeBytes
    lastUpdated
  }
}

Advanced AST Queries

Query AST using JSONPath expressions:

{
  astQuery(
    filename: "document.md",
    jsonpath: "$.children[?(@.type=='heading')]"
  )
}

CLI Integration

Available Commands

graphql-serve

Start the GraphQL server:

markitect graphql-serve [OPTIONS]

Options:
  --host TEXT     Host to bind to (default: 127.0.0.1)
  --port INTEGER  Port to bind to (default: 5000)
  --debug         Enable debug mode
  --no-cors       Disable CORS

graphql-query

Execute GraphQL queries from the command line:

markitect graphql-query QUERY [OPTIONS]

Options:
  --variables TEXT    JSON string of query variables
  --endpoint TEXT     GraphQL endpoint URL
  --local            Execute query locally without HTTP
  --format [json|yaml|table]  Output format (default: json)

Examples:

# Execute a simple query locally
markitect graphql-query "{ databaseStats { totalFiles } }" --local

# Execute query with variables
markitect graphql-query "query($limit: Int) { markdownFiles(limit: $limit) { filename } }" --variables '{"limit": 5}' --local

# Execute query against remote server
markitect graphql-query "{ schemas { title } }" --endpoint http://localhost:5000/graphql

graphql-schema

Get the GraphQL schema definition:

markitect graphql-schema [OPTIONS]

Options:
  --format [sdl|json]  Schema format (default: sdl)
  --endpoint TEXT      GraphQL endpoint URL

graphql-examples

Show example queries and usage:

markitect graphql-examples

Programming API

Using the GraphQL Client

from markitect.graphql import GraphQLClient

# Create a client
client = GraphQLClient("http://localhost:5000/graphql")

# Execute a query
result = client.execute("""
{
  markdownFiles(limit: 5) {
    filename
    wordCount
  }
}
""")

print(result['data'])

Local Execution

from markitect.graphql import GraphQLClient

# Execute queries locally without HTTP
client = GraphQLClient()
result = client.execute_local("""
{
  databaseStats {
    totalFiles
    totalSchemas
  }
}
""")

print(result['data'])

Using the Server Directly

from markitect.graphql import GraphQLServer

# Create and start server
server = GraphQLServer(db_path="/path/to/markitect.db")
app = server.create_app()

# Start server
server.run(host="0.0.0.0", port=8080, debug=True)

API Endpoints

When running the GraphQL server, the following endpoints are available:

  • POST /graphql - Main GraphQL endpoint for queries
  • GET /graphql - GraphQL Playground interface
  • GET /schema - Schema introspection
  • GET /health - Health check endpoint

Health Check Response

{
  "status": "healthy",
  "database": "connected",
  "database_path": "/path/to/markitect.db"
}

Error Handling

The GraphQL interface provides comprehensive error handling:

Query Errors

Invalid GraphQL syntax or non-existent fields return structured errors:

{
  "data": null,
  "errors": [
    {
      "message": "Cannot query field 'nonexistentField' on type 'Query'"
    }
  ]
}

Database Errors

Database connectivity issues are handled gracefully:

{
  "data": {
    "databaseStats": null
  },
  "errors": [
    {
      "message": "Database connection error"
    }
  ]
}

Performance Considerations

Pagination

Always use pagination for large datasets:

{
  markdownFiles(limit: 50, offset: 0) {
    id
    filename
  }
}

Field Selection

Only query the fields you need:

# Good - selective fields
{
  markdownFiles {
    id
    filename
  }
}

# Avoid - requesting large content fields unnecessarily
{
  markdownFiles {
    id
    filename
    content  # Only include if needed
  }
}

Search Optimization

Use specific search types when possible:

# Better - search only files
{
  search(query: "API", type: "file", limit: 10) {
    file {
      filename
    }
  }
}

# Less efficient - search all types
{
  search(query: "API", type: "all", limit: 10) {
    type
    file { filename }
    schema { title }
  }
}

Security Considerations

Read-Only Interface

The GraphQL interface is read-only and does not support mutations, providing safe access to MarkiTect data.

CORS Configuration

CORS is enabled by default for browser access. Disable with --no-cors if needed:

markitect graphql-serve --no-cors

Database Access

The interface uses the same database path configuration as the main MarkiTect CLI, respecting the MARKITECT_DB environment variable.

Troubleshooting

Common Issues

"Flask is required" Error

Install Flask dependencies:

pip install flask flask-cors

"requests is required" Error

Install requests for HTTP client functionality:

pip install requests

Database Connection Errors

Check that your MarkiTect database exists and is accessible:

# Check database location
echo $MARKITECT_DB

# Verify database exists
ls -la ~/.markitect/markitect.db

GraphQL Syntax Errors

Use the GraphQL Playground at http://localhost:5000/graphql to validate your queries with real-time syntax checking and auto-completion.

Examples

Complete Data Export

Export all markdown files with metadata:

{
  markdownFiles {
    id
    filename
    content
    createdAt
    wordCount
    lineCount
    hasFrontMatter
    frontMatter {
      key
      value
    }
  }
}

Schema Analysis

Analyze all schemas in the database:

{
  schemas {
    filename
    title
    description
    schemaVersion
    propertyCount
    schemaContent
  }
}

Content Discovery

Find all documents containing specific terms:

{
  search(query: "authentication security", type: "all", limit: 20) {
    type
    score
    file {
      filename
      wordCount
      hasFrontMatter
    }
    schema {
      title
      description
    }
    highlight
  }
}

Database Overview

Get a complete overview of your MarkiTect database:

{
  databaseStats {
    totalFiles
    totalSchemas
    totalSizeBytes
    lastUpdated
  }
  recentFiles: markdownFiles(limit: 5) {
    filename
    createdAt
  }
  recentSchemas: schemas(limit: 5) {
    filename
    title
    createdAt
  }
}

Integration Examples

With JavaScript/TypeScript

interface DatabaseStats {
  totalFiles: number;
  totalSchemas: number;
  totalSizeBytes: number;
  lastUpdated: string;
}

async function getStats(): Promise<DatabaseStats> {
  const response = await fetch('http://localhost:5000/graphql', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      query: `
        {
          databaseStats {
            totalFiles
            totalSchemas
            totalSizeBytes
            lastUpdated
          }
        }
      `
    })
  });

  const { data } = await response.json();
  return data.databaseStats;
}

With Python

import requests
from typing import List, Dict, Any

def search_content(query: str, limit: int = 10) -> List[Dict[str, Any]]:
    """Search for content in MarkiTect database."""

    response = requests.post('http://localhost:5000/graphql', json={
        'query': '''
        query SearchContent($query: String!, $limit: Int!) {
          search(query: $query, type: "all", limit: $limit) {
            type
            score
            file {
              filename
              wordCount
            }
            schema {
              title
              description
            }
            highlight
          }
        }
        ''',
        'variables': {
            'query': query,
            'limit': limit
        }
    })

    return response.json()['data']['search']

# Usage
results = search_content("API documentation", limit=5)
for result in results:
    print(f"Found {result['type']}: {result['highlight']}")

This GraphQL interface provides a powerful, flexible way to access and query MarkiTect data, enabling rich integrations and applications built on top of your Markdown content management system.