# User Guide Complete guide to using the Wiki.js Python SDK for common tasks and workflows. ## Table of Contents - [Getting Started](#getting-started) - [Authentication](#authentication) - [Working with Pages](#working-with-pages) - [Advanced Features](#advanced-features) - [Best Practices](#best-practices) - [Troubleshooting](#troubleshooting) --- ## Getting Started ### Installation ```bash pip install wikijs-python-sdk ``` ### Basic Setup ```python from wikijs import WikiJSClient # Initialize the client client = WikiJSClient( base_url="https://your-wiki.example.com", auth="your-api-key" ) # Test the connection if client.test_connection(): print("Connected successfully!") else: print("Connection failed") ``` ### Your First API Call ```python # Get all pages pages = client.pages.list() print(f"Found {len(pages)} pages") # Get a specific page page = client.pages.get(1) print(f"Page title: {page.title}") ``` --- ## Authentication ### API Key Authentication The simplest way to authenticate is with an API key: ```python from wikijs import WikiJSClient client = WikiJSClient( base_url="https://wiki.example.com", auth="your-api-key-here" ) ``` **Getting an API Key:** 1. Log into your Wiki.js admin panel 2. Go to Administration → API Keys 3. Create a new API key with appropriate permissions 4. Copy the generated key ### JWT Authentication For username/password authentication: ```python from wikijs import WikiJSClient from wikijs.auth import JWTAuth auth = JWTAuth( username="your-username", password="your-password" ) client = WikiJSClient( base_url="https://wiki.example.com", auth=auth ) ``` ### Custom Authentication You can also create custom authentication handlers: ```python from wikijs.auth import AuthHandler class CustomAuth(AuthHandler): def __init__(self, token): self.token = token def get_headers(self): return {"Authorization": f"Bearer {self.token}"} def validate_credentials(self): if not self.token: raise ValueError("Token is required") client = WikiJSClient( base_url="https://wiki.example.com", auth=CustomAuth("your-custom-token") ) ``` --- ## Working with Pages ### Listing Pages #### Basic Listing ```python # Get all pages all_pages = client.pages.list() # Get first 10 pages first_10 = client.pages.list(limit=10) # Get pages 11-20 (pagination) next_10 = client.pages.list(limit=10, offset=10) ``` #### Filtering and Searching ```python # Search by content search_results = client.pages.search("getting started") # Filter by tags tutorial_pages = client.pages.get_by_tags(["tutorial", "guide"]) # Filter by author author_pages = client.pages.list(author_id=1) # Filter by locale french_pages = client.pages.list(locale="fr") ``` #### Sorting ```python # Sort by title (A-Z) pages_by_title = client.pages.list( order_by="title", order_direction="ASC" ) # Sort by most recently updated recent_pages = client.pages.list( order_by="updated_at", order_direction="DESC", limit=10 ) # Sort by creation date (oldest first) oldest_pages = client.pages.list( order_by="created_at", order_direction="ASC" ) ``` ### Getting Individual Pages #### By ID ```python # Get page with ID 123 page = client.pages.get(123) print(f"Title: {page.title}") print(f"Content: {page.content}") ``` #### By Path ```python # Get page by its path page = client.pages.get_by_path("getting-started") # Get page in specific locale french_page = client.pages.get_by_path("guide-utilisateur", locale="fr") ``` ### Creating Pages #### Basic Page Creation ```python from wikijs.models import PageCreate # Create a simple page new_page = PageCreate( title="My New Page", path="my-new-page", content="# Welcome\n\nThis is my new page content!" ) created_page = client.pages.create(new_page) print(f"Created page with ID: {created_page.id}") ``` #### Advanced Page Creation ```python from wikijs.models import PageCreate # Create a comprehensive page new_page = PageCreate( title="Complete Guide to Wiki.js", path="guides/wikijs-complete-guide", content="""# Complete Guide to Wiki.js ## Introduction This guide covers everything you need to know about Wiki.js. ## Getting Started 1. Installation 2. Configuration 3. First steps ## Advanced Topics - Custom themes - Plugin development - API integration """, description="A comprehensive guide covering all aspects of Wiki.js", tags=["guide", "tutorial", "wikijs", "documentation"], is_published=True, is_private=False, locale="en", editor="markdown" ) created_page = client.pages.create(new_page) ``` #### Creating from Dictionary ```python # You can also use a dictionary page_data = { "title": "Quick Note", "path": "quick-note", "content": "This is a quick note.", "tags": ["note", "quick"] } created_page = client.pages.create(page_data) ``` ### Updating Pages #### Partial Updates ```python from wikijs.models import PageUpdate # Update only specific fields update_data = PageUpdate( title="Updated Title", tags=["updated", "modified"] ) updated_page = client.pages.update(123, update_data) ``` #### Full Content Update ```python from wikijs.models import PageUpdate # Update content and metadata update_data = PageUpdate( title="Revised Guide", content="""# Revised Guide This guide has been completely updated with new information. ## What's New - Updated examples - New best practices - Latest features ## Migration Guide If you're upgrading from the previous version... """, description="Updated guide with latest information", tags=["guide", "updated", "v2"], is_published=True ) updated_page = client.pages.update(123, update_data) ``` ### Deleting Pages ```python # Delete a page by ID success = client.pages.delete(123) if success: print("Page deleted successfully") else: print("Failed to delete page") ``` **⚠️ Warning:** Page deletion is permanent and cannot be undone! --- ## Advanced Features ### Working with Page Metadata ```python # Get a page page = client.pages.get(123) # Access metadata print(f"Word count: {page.word_count}") print(f"Reading time: {page.reading_time} minutes") print(f"Author: {page.author_name}") print(f"Created: {page.created_at}") print(f"Last updated: {page.updated_at}") # Check tags if page.has_tag("tutorial"): print("This is a tutorial page") # Extract headings headings = page.extract_headings() print("Page structure:") for heading in headings: print(f"- {heading}") ``` ### Batch Operations #### Creating Multiple Pages ```python from wikijs.models import PageCreate # Prepare multiple pages pages_to_create = [ PageCreate( title=f"Chapter {i}", path=f"guide/chapter-{i}", content=f"# Chapter {i}\n\nContent for chapter {i}", tags=["guide", f"chapter-{i}"] ) for i in range(1, 6) ] # Create them one by one created_pages = [] for page_data in pages_to_create: try: created_page = client.pages.create(page_data) created_pages.append(created_page) print(f"Created: {created_page.title}") except Exception as e: print(f"Failed to create page: {e}") print(f"Successfully created {len(created_pages)} pages") ``` #### Bulk Updates ```python from wikijs.models import PageUpdate # Get pages to update tutorial_pages = client.pages.get_by_tags(["tutorial"]) # Update all tutorial pages update_data = PageUpdate( tags=["tutorial", "updated-2024"] ) updated_count = 0 for page in tutorial_pages: try: client.pages.update(page.id, update_data) updated_count += 1 except Exception as e: print(f"Failed to update page {page.id}: {e}") print(f"Updated {updated_count} tutorial pages") ``` ### Content Migration ```python def migrate_content_format(page): """Convert old format to new format.""" old_content = page.content # Example: Convert old-style headers new_content = old_content.replace("==", "##") new_content = new_content.replace("===", "###") return new_content # Get pages to migrate pages_to_migrate = client.pages.list(search="old-format") for page in pages_to_migrate: try: new_content = migrate_content_format(page) update_data = PageUpdate( content=new_content, tags=page.tags + ["migrated"] ) client.pages.update(page.id, update_data) print(f"Migrated: {page.title}") except Exception as e: print(f"Failed to migrate {page.title}: {e}") ``` ### Template System ```python from wikijs.models import PageCreate def create_from_template(title, path, template_data): """Create a page from a template.""" # Define templates templates = { "meeting_notes": """# {meeting_title} **Date:** {date} **Attendees:** {attendees} ## Agenda {agenda} ## Discussion Points {discussion} ## Action Items {actions} ## Next Meeting {next_meeting} """, "project_doc": """# {project_name} ## Overview {overview} ## Requirements {requirements} ## Timeline {timeline} ## Resources {resources} ## Status - [ ] Planning - [ ] Development - [ ] Testing - [ ] Deployment """ } template = templates.get(template_data["template_type"]) if not template: raise ValueError(f"Unknown template: {template_data['template_type']}") # Format template content = template.format(**template_data) # Create page page_data = PageCreate( title=title, path=path, content=content, tags=template_data.get("tags", []) ) return client.pages.create(page_data) # Use template meeting_page = create_from_template( title="Weekly Team Meeting - Jan 15", path="meetings/2024-01-15-weekly", template_data={ "template_type": "meeting_notes", "meeting_title": "Weekly Team Meeting", "date": "January 15, 2024", "attendees": "Alice, Bob, Charlie", "agenda": "- Project updates\n- Q1 planning\n- Process improvements", "discussion": "TBD", "actions": "TBD", "next_meeting": "January 22, 2024", "tags": ["meeting", "weekly", "team"] } ) ``` --- ## Best Practices ### Error Handling ```python from wikijs.exceptions import ( APIError, AuthenticationError, ValidationError, ConnectionError, TimeoutError ) def safe_page_operation(operation_func): """Wrapper for safe page operations with proper error handling.""" try: return operation_func() except AuthenticationError: print("❌ Authentication failed. Check your API key.") return None except ValidationError as e: print(f"❌ Invalid input: {e}") return None except ConnectionError: print("❌ Cannot connect to Wiki.js. Check your URL and network.") return None except TimeoutError: print("❌ Request timed out. Try again later.") return None except APIError as e: print(f"❌ API error: {e}") return None # Usage result = safe_page_operation(lambda: client.pages.get(123)) if result: print(f"✅ Got page: {result.title}") ``` ### Resource Management ```python # Always use context managers for automatic cleanup with WikiJSClient("https://wiki.example.com", auth="api-key") as client: # Do your work here pages = client.pages.list() # Connection automatically closed when exiting the block # Or manually manage resources client = WikiJSClient("https://wiki.example.com", auth="api-key") try: pages = client.pages.list() finally: client.close() # Always close when done ``` ### Configuration Management ```python import os from wikijs import WikiJSClient # Use environment variables for configuration def create_client(): """Create a properly configured client from environment variables.""" base_url = os.getenv("WIKIJS_URL") api_key = os.getenv("WIKIJS_API_KEY") if not base_url or not api_key: raise ValueError("WIKIJS_URL and WIKIJS_API_KEY environment variables are required") return WikiJSClient( base_url=base_url, auth=api_key, timeout=int(os.getenv("WIKIJS_TIMEOUT", "30")), verify_ssl=os.getenv("WIKIJS_VERIFY_SSL", "true").lower() == "true" ) # Usage client = create_client() ``` ### Logging ```python import logging from wikijs import WikiJSClient # Set up logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def create_page_with_logging(client, page_data): """Create a page with proper logging.""" logger.info(f"Creating page: {page_data.title}") try: created_page = client.pages.create(page_data) logger.info(f"Successfully created page with ID: {created_page.id}") return created_page except Exception as e: logger.error(f"Failed to create page '{page_data.title}': {e}") raise # Usage with WikiJSClient("https://wiki.example.com", auth="api-key") as client: page_data = PageCreate( title="Logged Page", path="logged-page", content="This creation is logged." ) create_page_with_logging(client, page_data) ``` ### Performance Optimization ```python # Efficient pagination def get_all_pages_efficiently(client, batch_size=100): """Get all pages with efficient pagination.""" all_pages = [] offset = 0 while True: # Get a batch batch = client.pages.list(limit=batch_size, offset=offset) if not batch: break # No more pages all_pages.extend(batch) offset += batch_size # Optional: Add a small delay to be nice to the server # time.sleep(0.1) return all_pages # Use server-side filtering def get_recent_tutorials(client, days=30): """Get recent tutorial pages efficiently.""" from datetime import datetime, timedelta # Let the server do the filtering pages = client.pages.get_by_tags(["tutorial"]) # Only filter by date client-side if necessary cutoff_date = datetime.now() - timedelta(days=days) recent_pages = [ page for page in pages if page.updated_at > cutoff_date ] return recent_pages ``` --- ## Troubleshooting ### Common Issues #### Authentication Problems ```python # Test your authentication try: client = WikiJSClient("https://wiki.example.com", auth="your-api-key") if client.test_connection(): print("✅ Authentication successful") else: print("❌ Authentication failed") except AuthenticationError as e: print(f"❌ Authentication error: {e}") print("💡 Check your API key and permissions") ``` #### Connection Issues ```python # Test connection with detailed error info try: client = WikiJSClient("https://wiki.example.com", auth="api-key") client.test_connection() except ConnectionError as e: print(f"❌ Connection failed: {e}") print("💡 Possible solutions:") print(" - Check if the URL is correct") print(" - Verify the server is running") print(" - Check your network connection") print(" - Try with verify_ssl=False if using self-signed certificates") ``` #### SSL Certificate Issues ```python # For development or self-signed certificates client = WikiJSClient( base_url="https://wiki.example.com", auth="api-key", verify_ssl=False # Only for development! ) ``` #### Timeout Issues ```python # Increase timeout for slow connections client = WikiJSClient( base_url="https://wiki.example.com", auth="api-key", timeout=60 # 60 seconds ) ``` ### Debugging #### Enable Debug Logging ```python import logging # Enable debug logging for the wikijs library logging.getLogger('wikijs').setLevel(logging.DEBUG) logging.getLogger('urllib3').setLevel(logging.DEBUG) # Enable debug logging for requests logging.basicConfig(level=logging.DEBUG) ``` #### Inspect Raw Responses ```python # You can inspect the raw HTTP responses for debugging import requests # Make a manual request to see the raw response response = requests.get( "https://wiki.example.com/graphql", headers={"Authorization": "Bearer your-api-key"}, json={"query": "{ pages { id title } }"} ) print(f"Status: {response.status_code}") print(f"Headers: {response.headers}") print(f"Content: {response.text}") ``` ### Getting Help If you encounter issues: 1. **Check the logs** - Enable debug logging to see what's happening 2. **Verify your setup** - Ensure URL, credentials, and network connectivity 3. **Check the Wiki.js server** - Look at server logs for errors 4. **Test with curl** - Verify the API works outside of Python 5. **Create an issue** - Report bugs on the GitHub repository #### Testing with curl ```bash # Test your Wiki.js GraphQL endpoint curl -X POST https://wiki.example.com/graphql \ -H "Authorization: Bearer your-api-key" \ -H "Content-Type: application/json" \ -d '{"query": "{ pages { id title } }"}' ``` --- ## Next Steps - Explore the [API Reference](api_reference.md) for detailed information - Check out the [Examples](../examples/) directory for more code samples - Read the [Contributing Guide](CONTRIBUTING.md) to help improve the SDK - Visit the [Wiki.js documentation](https://docs.js.wiki/) to learn more about the platform