|
| 1 | +# GraphQL Mode (Experimental) |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The prx library now includes an experimental hybrid GraphQL+REST mode that significantly reduces GitHub API calls from 13+ to approximately 3-4 calls per pull request. This hybrid approach uses GraphQL for most data and selective REST calls for missing pieces (primarily check runs and rulesets), maintaining data completeness while optimizing API usage. |
| 6 | + |
| 7 | +This is especially useful when working with repositories that have many pull requests or when you're close to GitHub's API rate limits. |
| 8 | + |
| 9 | +## How to Enable |
| 10 | + |
| 11 | +Add the `WithGraphQL()` option when creating a client: |
| 12 | + |
| 13 | +```go |
| 14 | +import "github.com/codeGROOVE-dev/prx/pkg/prx" |
| 15 | + |
| 16 | +// REST mode (default) |
| 17 | +client := prx.NewClient(token) |
| 18 | + |
| 19 | +// GraphQL mode (experimental) |
| 20 | +client := prx.NewClient(token, prx.WithGraphQL()) |
| 21 | + |
| 22 | +// GraphQL with other options |
| 23 | +client := prx.NewClient(token, |
| 24 | + prx.WithGraphQL(), |
| 25 | + prx.WithNoCache(), |
| 26 | + prx.WithLogger(customLogger), |
| 27 | +) |
| 28 | +``` |
| 29 | + |
| 30 | +## API Call Comparison |
| 31 | + |
| 32 | +### REST Mode (Default) |
| 33 | +- **Total API Calls**: 13+ per pull request |
| 34 | +- Synchronous calls (5-6): |
| 35 | + - Pull request details |
| 36 | + - Combined status |
| 37 | + - Branch protection |
| 38 | + - Branch protection fallback |
| 39 | + - Repository rulesets |
| 40 | + - Workflow checks (if blocked) |
| 41 | +- Parallel calls (7): |
| 42 | + - Commits |
| 43 | + - Comments |
| 44 | + - Reviews |
| 45 | + - Review comments |
| 46 | + - Timeline events |
| 47 | + - Status checks |
| 48 | + - Check runs |
| 49 | + |
| 50 | +### Hybrid GraphQL+REST Mode |
| 51 | +- **Total API Calls**: 3-4 per pull request |
| 52 | +- Main GraphQL query (1 call) fetches: |
| 53 | + - Pull request details |
| 54 | + - All commits, comments, reviews |
| 55 | + - Timeline events (including draft/ready events) |
| 56 | + - Branch protection rules |
| 57 | + - Required status checks |
| 58 | +- Additional REST calls (2-3): |
| 59 | + - Check runs (GraphQL's statusCheckRollup is often null) |
| 60 | + - Repository rulesets (not available in GraphQL) |
| 61 | + - Permission verification for MEMBER users (if needed) |
| 62 | + |
| 63 | +## Benefits |
| 64 | + |
| 65 | +- **70-75% Reduction in API Calls**: From 13+ to 3-4 calls |
| 66 | +- **Data Completeness**: Hybrid approach maintains full data parity with REST |
| 67 | +- **Faster Performance**: Bulk data fetching via GraphQL |
| 68 | +- **Better Rate Limit Management**: Reduced REST API usage |
| 69 | +- **Reliability**: REST fallbacks for critical missing data |
| 70 | + |
| 71 | +## Testing & Comparison |
| 72 | + |
| 73 | +You can easily compare REST vs GraphQL output using Unix diff: |
| 74 | + |
| 75 | +```bash |
| 76 | +# Fetch with REST (default) |
| 77 | +prx https://github.com/owner/repo/pull/123 > rest.json |
| 78 | + |
| 79 | +# Fetch with GraphQL |
| 80 | +PRX_USE_GRAPHQL=1 prx https://github.com/owner/repo/pull/123 > graphql.json |
| 81 | + |
| 82 | +# Compare outputs |
| 83 | +diff rest.json graphql.json |
| 84 | +``` |
| 85 | + |
| 86 | +## Known Differences |
| 87 | + |
| 88 | +While we strive for parity, there are some minor differences: |
| 89 | + |
| 90 | +1. **Bot Detection**: GraphQL uses login pattern matching (`-bot`, `[bot]`, `-robot` suffixes) rather than the `type` field |
| 91 | +2. **Permissions**: MEMBER association requires an additional REST call for exact permission level |
| 92 | +3. **Event Ordering**: Events may be ordered slightly differently but all data is present |
| 93 | + |
| 94 | +## Limitations |
| 95 | + |
| 96 | +- Repository rulesets are not available via GraphQL (requires 1 REST call) |
| 97 | +- Some edge cases in bot detection may differ |
| 98 | +- Write access detection for MEMBER users is approximated |
| 99 | +- **Check Runs**: GraphQL has significant limitations fetching check runs: |
| 100 | + - `statusCheckRollup` is often null for many repositories |
| 101 | + - Check runs are not included in timeline events |
| 102 | + - Fork PRs may have null `headRef`, preventing status checks from being fetched |
| 103 | + - Draft PRs may have incomplete status information |
| 104 | + - REST API fetches check runs separately and more reliably |
| 105 | +- **Old PRs**: Check runs from old PRs (>90 days) may not be available via GraphQL |
| 106 | + - GitHub may not expose historical check run data consistently |
| 107 | + - REST API may have cached or different retention policies |
| 108 | + - For critical historical analysis, REST mode may be more reliable |
| 109 | +- **Event Completeness**: GraphQL may miss certain events: |
| 110 | + - Check run events are often missing entirely |
| 111 | + - Some timeline event types may not be captured |
| 112 | + |
| 113 | +## Stability |
| 114 | + |
| 115 | +This is an **experimental feature**. While it has been tested, you may encounter: |
| 116 | +- Minor data differences compared to REST |
| 117 | +- Edge cases not yet handled |
| 118 | +- Need to fall back to REST for certain operations |
| 119 | + |
| 120 | +Please report any issues or discrepancies you find. |
| 121 | + |
| 122 | +## Environment Variable |
| 123 | + |
| 124 | +You can also enable GraphQL mode via environment variable: |
| 125 | + |
| 126 | +```bash |
| 127 | +export PRX_USE_GRAPHQL=1 |
| 128 | +prx https://github.com/owner/repo/pull/123 |
| 129 | +``` |
| 130 | + |
| 131 | +## Metrics |
| 132 | + |
| 133 | +When GraphQL mode is enabled, the client logs the mode and number of API calls: |
| 134 | + |
| 135 | +``` |
| 136 | +INFO GraphQL mode enabled owner=golang repo=go pr=123 |
| 137 | +INFO successfully fetched pull request via GraphQL api_calls_made="2 (vs 13+ with REST)" |
| 138 | +``` |
| 139 | + |
| 140 | +## Future Improvements |
| 141 | + |
| 142 | +- Full GraphQL implementation without REST fallbacks |
| 143 | +- Better caching integration |
| 144 | +- Pagination support for very large PRs |
| 145 | +- WebSocket subscriptions for real-time updates |
0 commit comments