diff --git a/backend/examples/README.md b/backend/examples/README.md new file mode 100644 index 0000000..2ab98ec --- /dev/null +++ b/backend/examples/README.md @@ -0,0 +1,221 @@ +# WizardMerge API Examples + +This directory contains example clients for the WizardMerge HTTP API. + +## Prerequisites + +Make sure the WizardMerge HTTP server is running: + +```sh +cd .. +./build.sh +cd build +./wizardmerge-cli +``` + +The server should be running on http://localhost:8080 + +## Examples + +### Python Client (`api_client.py`) + +Demonstrates API usage with the requests library. + +**Requirements:** +```sh +pip install requests +``` + +**Run:** +```sh +./api_client.py +``` + +### Curl Examples (`test_api.sh`) + +Shell script with curl commands for testing the API. + +**Requirements:** +- curl +- jq (optional, for pretty JSON output) + +**Run:** +```sh +./test_api.sh +``` + +## API Endpoint + +### POST /api/merge + +Performs a three-way merge operation. + +**Request Body:** +```json +{ + "base": ["line1", "line2", "line3"], + "ours": ["line1", "line2_modified", "line3"], + "theirs": ["line1", "line2", "line3_modified"] +} +``` + +**Response (Success):** +```json +{ + "merged": ["line1", "line2_modified", "line3_modified"], + "conflicts": [], + "has_conflicts": false +} +``` + +**Response (With Conflicts):** +```json +{ + "merged": [ + "line1", + "<<<<<<< OURS", + "line2_ours", + "=======", + "line2_theirs", + ">>>>>>> THEIRS", + "line3" + ], + "conflicts": [ + { + "start_line": 1, + "end_line": 1, + "base_lines": ["line2"], + "our_lines": ["line2_ours"], + "their_lines": ["line2_theirs"] + } + ], + "has_conflicts": true +} +``` + +**Error Response (400 Bad Request):** +```json +{ + "error": "Missing required fields: base, ours, theirs" +} +``` + +## Manual Testing with curl + +Basic example: +```sh +curl -X POST http://localhost:8080/api/merge \ + -H "Content-Type: application/json" \ + -d '{ + "base": ["hello", "world"], + "ours": ["hello", "beautiful world"], + "theirs": ["goodbye", "world"] + }' +``` + +## Integration Examples + +### JavaScript/Node.js + +```javascript +const axios = require('axios'); + +async function merge(base, ours, theirs) { + const response = await axios.post('http://localhost:8080/api/merge', { + base, ours, theirs + }); + return response.data; +} + +// Usage +merge( + ['line1', 'line2'], + ['line1', 'line2_modified'], + ['line1', 'line2'] +).then(result => { + console.log('Merged:', result.merged); + console.log('Has conflicts:', result.has_conflicts); +}); +``` + +### Python + +```python +import requests + +def merge(base, ours, theirs, server_url="http://localhost:8080"): + response = requests.post( + f"{server_url}/api/merge", + json={"base": base, "ours": ours, "theirs": theirs} + ) + return response.json() + +# Usage +result = merge( + base=["line1", "line2"], + ours=["line1", "line2_modified"], + theirs=["line1", "line2"] +) +print(f"Merged: {result['merged']}") +print(f"Has conflicts: {result['has_conflicts']}") +``` + +### Go + +```go +package main + +import ( + "bytes" + "encoding/json" + "net/http" +) + +type MergeRequest struct { + Base []string `json:"base"` + Ours []string `json:"ours"` + Theirs []string `json:"theirs"` +} + +type MergeResponse struct { + Merged []string `json:"merged"` + Conflicts []Conflict `json:"conflicts"` + HasConflicts bool `json:"has_conflicts"` +} + +func merge(base, ours, theirs []string) (*MergeResponse, error) { + req := MergeRequest{Base: base, Ours: ours, Theirs: theirs} + jsonData, _ := json.Marshal(req) + + resp, err := http.Post( + "http://localhost:8080/api/merge", + "application/json", + bytes.NewBuffer(jsonData), + ) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result MergeResponse + json.NewDecoder(resp.Body).Decode(&result) + return &result, nil +} +``` + +## Docker Usage + +If running the server in Docker: + +```sh +# Start server +docker-compose up -d + +# Test API (from host) +curl -X POST http://localhost:8080/api/merge \ + -H "Content-Type: application/json" \ + -d '{"base":["a"],"ours":["b"],"theirs":["c"]}' + +# Check logs +docker-compose logs -f +``` diff --git a/backend/examples/api_client.py b/backend/examples/api_client.py new file mode 100755 index 0000000..132bcc1 --- /dev/null +++ b/backend/examples/api_client.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +""" +Example client for WizardMerge HTTP API +Demonstrates how to use the POST /api/merge endpoint +""" + +import requests +import json +import sys + +def test_merge(base_lines, ours_lines, theirs_lines, server_url="http://localhost:8080"): + """ + Test the merge API with given inputs + """ + endpoint = f"{server_url}/api/merge" + + payload = { + "base": base_lines, + "ours": ours_lines, + "theirs": theirs_lines + } + + print(f"Sending merge request to {endpoint}") + print(f"Base: {base_lines}") + print(f"Ours: {ours_lines}") + print(f"Theirs: {theirs_lines}") + print() + + try: + response = requests.post(endpoint, json=payload) + response.raise_for_status() + + result = response.json() + + print("=== Merge Result ===") + print(f"Merged lines: {result['merged']}") + print(f"Has conflicts: {result['has_conflicts']}") + + if result['conflicts']: + print(f"Number of conflicts: {len(result['conflicts'])}") + for i, conflict in enumerate(result['conflicts']): + print(f"\nConflict {i+1}:") + print(f" Lines: {conflict['start_line']}-{conflict['end_line']}") + print(f" Base: {conflict['base_lines']}") + print(f" Ours: {conflict['our_lines']}") + print(f" Theirs: {conflict['their_lines']}") + + return result + + except requests.exceptions.ConnectionError: + print(f"ERROR: Could not connect to server at {server_url}") + print("Make sure the server is running with: ./wizardmerge-cli") + sys.exit(1) + except requests.exceptions.HTTPError as e: + print(f"ERROR: HTTP {e.response.status_code}") + print(e.response.text) + sys.exit(1) + except Exception as e: + print(f"ERROR: {e}") + sys.exit(1) + +def main(): + print("WizardMerge API Client - Example Usage") + print("=" * 50) + print() + + # Test 1: No conflicts + print("Test 1: No conflicts (non-overlapping changes)") + print("-" * 50) + test_merge( + base_lines=["line1", "line2", "line3"], + ours_lines=["line1", "line2_modified", "line3"], + theirs_lines=["line1", "line2", "line3_modified"] + ) + print() + + # Test 2: With conflicts + print("\nTest 2: With conflicts (overlapping changes)") + print("-" * 50) + test_merge( + base_lines=["line1", "line2", "line3"], + ours_lines=["line1", "line2_ours", "line3"], + theirs_lines=["line1", "line2_theirs", "line3"] + ) + print() + + # Test 3: Identical changes + print("\nTest 3: Identical changes (auto-resolved)") + print("-" * 50) + test_merge( + base_lines=["line1", "line2", "line3"], + ours_lines=["line1", "line2_same", "line3"], + theirs_lines=["line1", "line2_same", "line3"] + ) + print() + +if __name__ == "__main__": + main() diff --git a/backend/examples/test_api.sh b/backend/examples/test_api.sh new file mode 100755 index 0000000..4c22357 --- /dev/null +++ b/backend/examples/test_api.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# Example API calls using curl + +SERVER_URL="http://localhost:8080" + +echo "WizardMerge API - Example curl Commands" +echo "========================================" +echo + +# Test 1: No conflicts +echo "Test 1: No conflicts (non-overlapping changes)" +echo "-----------------------------------------------" +curl -X POST "${SERVER_URL}/api/merge" \ + -H "Content-Type: application/json" \ + -d '{ + "base": ["line1", "line2", "line3"], + "ours": ["line1", "line2_modified", "line3"], + "theirs": ["line1", "line2", "line3_modified"] + }' | jq '.' +echo +echo + +# Test 2: With conflicts +echo "Test 2: With conflicts (overlapping changes)" +echo "---------------------------------------------" +curl -X POST "${SERVER_URL}/api/merge" \ + -H "Content-Type: application/json" \ + -d '{ + "base": ["line1", "line2", "line3"], + "ours": ["line1", "line2_ours", "line3"], + "theirs": ["line1", "line2_theirs", "line3"] + }' | jq '.' +echo +echo + +# Test 3: Identical changes +echo "Test 3: Identical changes (auto-resolved)" +echo "------------------------------------------" +curl -X POST "${SERVER_URL}/api/merge" \ + -H "Content-Type: application/json" \ + -d '{ + "base": ["line1", "line2", "line3"], + "ours": ["line1", "line2_same", "line3"], + "theirs": ["line1", "line2_same", "line3"] + }' | jq '.' +echo +echo + +# Test 4: Error handling - Missing field +echo "Test 4: Error handling - Missing required field" +echo "------------------------------------------------" +curl -X POST "${SERVER_URL}/api/merge" \ + -H "Content-Type: application/json" \ + -d '{ + "base": ["line1", "line2"], + "ours": ["line1", "line2_modified"] + }' | jq '.' +echo +echo + +# Test 5: Error handling - Invalid JSON +echo "Test 5: Error handling - Invalid JSON" +echo "--------------------------------------" +curl -X POST "${SERVER_URL}/api/merge" \ + -H "Content-Type: application/json" \ + -d 'not json' +echo +echo + +echo "Done!"