Some checks failed
Test Suite / performance-tests (push) Has been cancelled
Test Suite / unit-tests (3.11) (push) Has been cancelled
Test Suite / unit-tests (3.12) (push) Has been cancelled
Test Suite / integration-tests (push) Has been cancelled
Test Suite / e2e-tests (push) Has been cancelled
Test Suite / code-quality (push) Has been cancelled
Test Suite / security-scan (push) Has been cancelled
Test Suite / test-summary (push) Has been cancelled
Added comprehensive GraphQL mutations for CRUD operations on markdown files and schemas. Key features: - Complete mutation schema with structured payload types - Markdown file mutations: add, update with front matter support - Schema mutations: add, update, delete with JSON validation - CLI integration with `graphql-mutate` command - Comprehensive error handling and validation - Full test coverage with 24 test cases - Updated documentation with mutation examples and API usage Resolves issue #10: Expose a GraphQL Write Interface 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1176 lines
22 KiB
Markdown
1176 lines
22 KiB
Markdown
# GraphQL Interface for MarkiTect
|
|
|
|
## Overview
|
|
|
|
The GraphQL interface provides a powerful, type-safe way to query and modify 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 and complete CRUD operations.
|
|
|
|
## 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
|
|
- **Full CRUD Operations**: Create, read, update, and delete markdown files and schemas via mutations
|
|
- **Structured Error Handling**: Comprehensive error responses with validation and success indicators
|
|
|
|
## Getting Started
|
|
|
|
### Prerequisites
|
|
|
|
Install the required dependencies:
|
|
|
|
```bash
|
|
pip install graphene flask flask-cors jsonpath-ng requests
|
|
```
|
|
|
|
### Starting the GraphQL Server
|
|
|
|
Start the GraphQL server using the CLI:
|
|
|
|
```bash
|
|
markitect graphql-serve
|
|
```
|
|
|
|
By default, this starts the server on `http://localhost:5000`. You can customize the host and port:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```graphql
|
|
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:
|
|
|
|
```graphql
|
|
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:
|
|
|
|
```graphql
|
|
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:
|
|
|
|
```graphql
|
|
type DatabaseStats {
|
|
totalFiles: Int
|
|
totalSchemas: Int
|
|
totalSizeBytes: Int
|
|
lastUpdated: DateTime
|
|
}
|
|
```
|
|
|
|
#### SearchResult
|
|
Represents search results across files and schemas:
|
|
|
|
```graphql
|
|
type SearchResult {
|
|
type: String!
|
|
score: Float
|
|
file: MarkdownFile
|
|
schema: Schema
|
|
highlight: String
|
|
}
|
|
```
|
|
|
|
### Query Operations
|
|
|
|
#### Single Item Queries
|
|
|
|
Get a specific markdown file:
|
|
```graphql
|
|
{
|
|
markdownFile(id: 1) {
|
|
id
|
|
filename
|
|
content
|
|
wordCount
|
|
hasFrontMatter
|
|
}
|
|
}
|
|
```
|
|
|
|
Get a specific schema:
|
|
```graphql
|
|
{
|
|
schema(filename: "user-schema.json") {
|
|
title
|
|
description
|
|
schemaVersion
|
|
propertyCount
|
|
}
|
|
}
|
|
```
|
|
|
|
Get AST for a file:
|
|
```graphql
|
|
{
|
|
ast(filename: "document.md") {
|
|
headingCount
|
|
linkCount
|
|
tree {
|
|
type
|
|
value
|
|
level
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### List Queries
|
|
|
|
Get all markdown files with pagination:
|
|
```graphql
|
|
{
|
|
markdownFiles(limit: 10, offset: 0) {
|
|
id
|
|
filename
|
|
createdAt
|
|
hasFrontMatter
|
|
}
|
|
}
|
|
```
|
|
|
|
Filter files by front matter presence:
|
|
```graphql
|
|
{
|
|
markdownFiles(hasFrontMatter: true, limit: 5) {
|
|
filename
|
|
frontMatter {
|
|
key
|
|
value
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Get all schemas:
|
|
```graphql
|
|
{
|
|
schemas(limit: 20) {
|
|
filename
|
|
title
|
|
description
|
|
propertyCount
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Search Queries
|
|
|
|
Search across all content:
|
|
```graphql
|
|
{
|
|
search(query: "documentation", type: "all", limit: 10) {
|
|
type
|
|
score
|
|
file {
|
|
filename
|
|
content
|
|
}
|
|
schema {
|
|
title
|
|
description
|
|
}
|
|
highlight
|
|
}
|
|
}
|
|
```
|
|
|
|
Search only in files:
|
|
```graphql
|
|
{
|
|
search(query: "API", type: "file", limit: 5) {
|
|
score
|
|
file {
|
|
filename
|
|
wordCount
|
|
}
|
|
highlight
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Database Statistics
|
|
|
|
Get database overview:
|
|
```graphql
|
|
{
|
|
databaseStats {
|
|
totalFiles
|
|
totalSchemas
|
|
totalSizeBytes
|
|
lastUpdated
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Advanced AST Queries
|
|
|
|
Query AST using JSONPath expressions:
|
|
```graphql
|
|
{
|
|
astQuery(
|
|
filename: "document.md",
|
|
jsonpath: "$.children[?(@.type=='heading')]"
|
|
)
|
|
}
|
|
```
|
|
|
|
## Mutation Operations
|
|
|
|
The GraphQL interface supports full CRUD operations for markdown files and schemas through mutations. All mutations return structured payloads with success indicators and error handling.
|
|
|
|
### Mutation Types
|
|
|
|
#### Markdown File Mutations
|
|
|
|
##### Add Markdown File
|
|
Create a new markdown file in the database:
|
|
|
|
```graphql
|
|
mutation {
|
|
addMarkdownFile(
|
|
filename: "new-document.md"
|
|
content: "# New Document\n\nThis is a new markdown file."
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
filename
|
|
content
|
|
wordCount
|
|
hasFrontMatter
|
|
createdAt
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Add Markdown File with Front Matter
|
|
Create a file with YAML front matter:
|
|
|
|
```graphql
|
|
mutation {
|
|
addMarkdownFile(
|
|
filename: "blog-post.md"
|
|
content: """---
|
|
title: "My Blog Post"
|
|
date: "2024-01-15"
|
|
tags: ["tech", "api"]
|
|
---
|
|
|
|
# My Blog Post
|
|
|
|
Content goes here.
|
|
"""
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
filename
|
|
frontMatter {
|
|
key
|
|
value
|
|
}
|
|
hasFrontMatter
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Update Markdown File
|
|
Update an existing markdown file:
|
|
|
|
```graphql
|
|
mutation {
|
|
updateMarkdownFile(
|
|
id: 1
|
|
content: "# Updated Document\n\nThis content has been updated."
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
filename
|
|
content
|
|
wordCount
|
|
lineCount
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Schema Mutations
|
|
|
|
##### Add JSON Schema
|
|
Create a new JSON schema:
|
|
|
|
```graphql
|
|
mutation {
|
|
addSchema(
|
|
filename: "user-schema.json"
|
|
schemaContent: {
|
|
"type": "object",
|
|
"title": "User Schema",
|
|
"description": "Schema for user objects",
|
|
"properties": {
|
|
"name": {"type": "string"},
|
|
"email": {"type": "string", "format": "email"},
|
|
"age": {"type": "integer", "minimum": 0}
|
|
},
|
|
"required": ["name", "email"]
|
|
}
|
|
) {
|
|
success
|
|
schema {
|
|
id
|
|
filename
|
|
title
|
|
description
|
|
propertyCount
|
|
schemaVersion
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Update JSON Schema
|
|
Update an existing schema:
|
|
|
|
```graphql
|
|
mutation {
|
|
updateSchema(
|
|
id: 1
|
|
schemaContent: {
|
|
"type": "object",
|
|
"title": "Updated User Schema",
|
|
"description": "Updated schema for user objects",
|
|
"properties": {
|
|
"name": {"type": "string"},
|
|
"email": {"type": "string", "format": "email"},
|
|
"age": {"type": "integer", "minimum": 0},
|
|
"country": {"type": "string"}
|
|
},
|
|
"required": ["name", "email"]
|
|
}
|
|
) {
|
|
success
|
|
schema {
|
|
id
|
|
filename
|
|
title
|
|
propertyCount
|
|
updatedAt
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Delete Schema
|
|
Remove a schema from the database:
|
|
|
|
```graphql
|
|
mutation {
|
|
deleteSchema(filename: "old-schema.json") {
|
|
success
|
|
deletedFilename
|
|
errors
|
|
}
|
|
}
|
|
```
|
|
|
|
### Mutation Payload Types
|
|
|
|
All mutations return structured payload types with the following pattern:
|
|
|
|
#### AddMarkdownFilePayload
|
|
```graphql
|
|
type AddMarkdownFilePayload {
|
|
success: Boolean!
|
|
markdownFile: MarkdownFile
|
|
errors: [String!]!
|
|
}
|
|
```
|
|
|
|
#### UpdateMarkdownFilePayload
|
|
```graphql
|
|
type UpdateMarkdownFilePayload {
|
|
success: Boolean!
|
|
markdownFile: MarkdownFile
|
|
errors: [String!]!
|
|
}
|
|
```
|
|
|
|
#### AddSchemaPayload
|
|
```graphql
|
|
type AddSchemaPayload {
|
|
success: Boolean!
|
|
schema: Schema
|
|
errors: [String!]!
|
|
}
|
|
```
|
|
|
|
#### UpdateSchemaPayload
|
|
```graphql
|
|
type UpdateSchemaPayload {
|
|
success: Boolean!
|
|
schema: Schema
|
|
errors: [String!]!
|
|
}
|
|
```
|
|
|
|
#### DeleteSchemaPayload
|
|
```graphql
|
|
type DeleteSchemaPayload {
|
|
success: Boolean!
|
|
deletedFilename: String
|
|
errors: [String!]!
|
|
}
|
|
```
|
|
|
|
### Error Handling in Mutations
|
|
|
|
Mutations provide comprehensive error handling:
|
|
|
|
#### Validation Errors
|
|
Invalid input data returns structured errors:
|
|
|
|
```graphql
|
|
mutation {
|
|
addMarkdownFile(filename: "", content: "test") {
|
|
success # false
|
|
markdownFile # null
|
|
errors # ["Filename cannot be empty"]
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Duplicate Filename Handling
|
|
Attempting to create files with existing names:
|
|
|
|
```graphql
|
|
mutation {
|
|
addMarkdownFile(filename: "existing.md", content: "test") {
|
|
success # false
|
|
errors # ["File with filename 'existing.md' already exists"]
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Not Found Errors
|
|
Updating non-existent resources:
|
|
|
|
```graphql
|
|
mutation {
|
|
updateMarkdownFile(id: 999, content: "test") {
|
|
success # false
|
|
errors # ["Markdown file with ID 999 not found"]
|
|
}
|
|
}
|
|
```
|
|
|
|
### Complete CRUD Workflow Example
|
|
|
|
Here's a complete example showing the full lifecycle of a markdown file:
|
|
|
|
```graphql
|
|
# 1. Create a new file
|
|
mutation CreateFile {
|
|
addMarkdownFile(
|
|
filename: "api-guide.md"
|
|
content: """---
|
|
title: "API Usage Guide"
|
|
version: "1.0"
|
|
---
|
|
|
|
# API Usage Guide
|
|
|
|
Basic API documentation.
|
|
"""
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
filename
|
|
hasFrontMatter
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
|
|
# 2. Query the created file
|
|
{
|
|
markdownFile(filename: "api-guide.md") {
|
|
id
|
|
content
|
|
wordCount
|
|
frontMatter {
|
|
key
|
|
value
|
|
}
|
|
}
|
|
}
|
|
|
|
# 3. Update the file content
|
|
mutation UpdateFile {
|
|
updateMarkdownFile(
|
|
id: 1
|
|
content: """---
|
|
title: "API Usage Guide"
|
|
version: "2.0"
|
|
updated: "2024-01-15"
|
|
---
|
|
|
|
# API Usage Guide
|
|
|
|
Comprehensive API documentation with examples.
|
|
|
|
## Authentication
|
|
...
|
|
"""
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
wordCount
|
|
lineCount
|
|
frontMatter {
|
|
key
|
|
value
|
|
}
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
|
|
# 4. Verify the update
|
|
{
|
|
markdownFile(id: 1) {
|
|
filename
|
|
wordCount
|
|
frontMatter {
|
|
key
|
|
value
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## CLI Integration
|
|
|
|
### Available Commands
|
|
|
|
#### graphql-serve
|
|
Start the GraphQL server:
|
|
```bash
|
|
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:
|
|
```bash
|
|
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:
|
|
```bash
|
|
# 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-mutate
|
|
Execute GraphQL mutations from the command line:
|
|
```bash
|
|
markitect graphql-mutate MUTATION [OPTIONS]
|
|
|
|
Options:
|
|
--variables TEXT JSON string of mutation variables
|
|
--endpoint TEXT GraphQL endpoint URL
|
|
--local Execute mutation locally without HTTP
|
|
--format [json|yaml|table] Output format (default: json)
|
|
```
|
|
|
|
Examples:
|
|
```bash
|
|
# Add a new markdown file locally
|
|
markitect graphql-mutate 'mutation { addMarkdownFile(filename: "test.md", content: "# Test") { success markdownFile { id filename } errors } }' --local
|
|
|
|
# Add markdown file with variables
|
|
markitect graphql-mutate 'mutation($filename: String!, $content: String!) { addMarkdownFile(filename: $filename, content: $content) { success errors } }' --variables '{"filename": "doc.md", "content": "# Documentation"}' --local
|
|
|
|
# Update a file remotely
|
|
markitect graphql-mutate 'mutation { updateMarkdownFile(id: 1, content: "# Updated") { success errors } }' --endpoint http://localhost:5000/graphql
|
|
|
|
# Add a JSON schema
|
|
markitect graphql-mutate 'mutation { addSchema(filename: "user.json", schemaContent: {"type": "object", "properties": {"name": {"type": "string"}}}) { success schema { id title } errors } }' --local
|
|
|
|
# Delete a schema
|
|
markitect graphql-mutate 'mutation { deleteSchema(filename: "old-schema.json") { success deletedFilename errors } }' --local
|
|
```
|
|
|
|
#### graphql-schema
|
|
Get the GraphQL schema definition:
|
|
```bash
|
|
markitect graphql-schema [OPTIONS]
|
|
|
|
Options:
|
|
--format [sdl|json] Schema format (default: sdl)
|
|
--endpoint TEXT GraphQL endpoint URL
|
|
```
|
|
|
|
#### graphql-examples
|
|
Show example queries and usage:
|
|
```bash
|
|
markitect graphql-examples
|
|
```
|
|
|
|
## Programming API
|
|
|
|
### Using the GraphQL Client
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
from markitect.graphql import GraphQLClient
|
|
|
|
# Execute queries locally without HTTP
|
|
client = GraphQLClient()
|
|
result = client.execute_local("""
|
|
{
|
|
databaseStats {
|
|
totalFiles
|
|
totalSchemas
|
|
}
|
|
}
|
|
""")
|
|
|
|
print(result['data'])
|
|
```
|
|
|
|
### Executing Mutations
|
|
|
|
```python
|
|
from markitect.graphql import GraphQLClient
|
|
|
|
# Create a client
|
|
client = GraphQLClient("http://localhost:5000/graphql")
|
|
|
|
# Add a new markdown file
|
|
create_mutation = """
|
|
mutation {
|
|
addMarkdownFile(
|
|
filename: "api-docs.md"
|
|
content: "# API Documentation\\n\\nComprehensive API guide."
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
filename
|
|
wordCount
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
"""
|
|
|
|
result = client.execute(create_mutation)
|
|
if result['data']['addMarkdownFile']['success']:
|
|
file_id = result['data']['addMarkdownFile']['markdownFile']['id']
|
|
print(f"Created file with ID: {file_id}")
|
|
else:
|
|
print("Errors:", result['data']['addMarkdownFile']['errors'])
|
|
|
|
# Update the file
|
|
update_mutation = """
|
|
mutation UpdateFile($id: Int!, $content: String!) {
|
|
updateMarkdownFile(id: $id, content: $content) {
|
|
success
|
|
markdownFile {
|
|
wordCount
|
|
lineCount
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
"""
|
|
|
|
variables = {
|
|
"id": file_id,
|
|
"content": "# API Documentation\\n\\nUpdated comprehensive API guide with examples."
|
|
}
|
|
|
|
result = client.execute(update_mutation, variables=variables)
|
|
print("Update result:", result['data']['updateMarkdownFile']['success'])
|
|
```
|
|
|
|
### Local Mutation Execution
|
|
|
|
```python
|
|
from markitect.graphql import GraphQLClient
|
|
|
|
# Execute mutations locally without HTTP
|
|
client = GraphQLClient()
|
|
|
|
# Add a JSON schema locally
|
|
schema_mutation = """
|
|
mutation {
|
|
addSchema(
|
|
filename: "product-schema.json"
|
|
schemaContent: {
|
|
"type": "object",
|
|
"title": "Product Schema",
|
|
"properties": {
|
|
"name": {"type": "string"},
|
|
"price": {"type": "number", "minimum": 0},
|
|
"category": {"type": "string"}
|
|
},
|
|
"required": ["name", "price"]
|
|
}
|
|
) {
|
|
success
|
|
schema {
|
|
id
|
|
title
|
|
propertyCount
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
"""
|
|
|
|
result = client.execute_local(schema_mutation)
|
|
if result['data']['addSchema']['success']:
|
|
schema_info = result['data']['addSchema']['schema']
|
|
print(f"Created schema: {schema_info['title']} with {schema_info['propertyCount']} properties")
|
|
```
|
|
|
|
### Using the Server Directly
|
|
|
|
```python
|
|
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
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{
|
|
"data": null,
|
|
"errors": [
|
|
{
|
|
"message": "Cannot query field 'nonexistentField' on type 'Query'"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Database Errors
|
|
Database connectivity issues are handled gracefully:
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"databaseStats": null
|
|
},
|
|
"errors": [
|
|
{
|
|
"message": "Database connection error"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Performance Considerations
|
|
|
|
### Pagination
|
|
Always use pagination for large datasets:
|
|
|
|
```graphql
|
|
{
|
|
markdownFiles(limit: 50, offset: 0) {
|
|
id
|
|
filename
|
|
}
|
|
}
|
|
```
|
|
|
|
### Field Selection
|
|
Only query the fields you need:
|
|
|
|
```graphql
|
|
# 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:
|
|
|
|
```graphql
|
|
# 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
|
|
|
|
### Write Operations Security
|
|
The GraphQL interface supports both read and write operations through mutations. Write operations require careful consideration:
|
|
|
|
- **Data Validation**: All mutations include comprehensive input validation and structured error responses
|
|
- **Transaction Safety**: Database operations are wrapped in transactions to ensure data consistency
|
|
- **File Overwrites**: Duplicate filenames in the same mutation will overwrite existing files
|
|
- **Schema Validation**: JSON schemas are validated before storage to ensure they are well-formed
|
|
- **Error Handling**: Failed operations return detailed error messages without exposing internal system details
|
|
|
|
### CORS Configuration
|
|
CORS is enabled by default for browser access. Disable with `--no-cors` if needed:
|
|
|
|
```bash
|
|
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:
|
|
```bash
|
|
pip install flask flask-cors
|
|
```
|
|
|
|
#### "requests is required" Error
|
|
Install requests for HTTP client functionality:
|
|
```bash
|
|
pip install requests
|
|
```
|
|
|
|
#### Database Connection Errors
|
|
Check that your MarkiTect database exists and is accessible:
|
|
```bash
|
|
# 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:
|
|
|
|
```graphql
|
|
{
|
|
markdownFiles {
|
|
id
|
|
filename
|
|
content
|
|
createdAt
|
|
wordCount
|
|
lineCount
|
|
hasFrontMatter
|
|
frontMatter {
|
|
key
|
|
value
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Schema Analysis
|
|
Analyze all schemas in the database:
|
|
|
|
```graphql
|
|
{
|
|
schemas {
|
|
filename
|
|
title
|
|
description
|
|
schemaVersion
|
|
propertyCount
|
|
schemaContent
|
|
}
|
|
}
|
|
```
|
|
|
|
### Content Discovery
|
|
Find all documents containing specific terms:
|
|
|
|
```graphql
|
|
{
|
|
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:
|
|
|
|
```graphql
|
|
{
|
|
databaseStats {
|
|
totalFiles
|
|
totalSchemas
|
|
totalSizeBytes
|
|
lastUpdated
|
|
}
|
|
recentFiles: markdownFiles(limit: 5) {
|
|
filename
|
|
createdAt
|
|
}
|
|
recentSchemas: schemas(limit: 5) {
|
|
filename
|
|
title
|
|
createdAt
|
|
}
|
|
}
|
|
```
|
|
|
|
## Integration Examples
|
|
|
|
### With JavaScript/TypeScript
|
|
|
|
```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
|
|
|
|
```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. |