4e7604c
commit 4e7604c
1 file changed
+621 -0
Showing 1 changed file+621-0
βΌdocs/15-api-reference.md
+621-0
| @@ -0,0 +1,621 @@ | ||
1 | +# π API Reference | |
2 | + | |
3 | +Complete API documentation for OpenGrammar backend. | |
4 | + | |
5 | +--- | |
6 | + | |
7 | +## π Overview | |
8 | + | |
9 | +OpenGrammar provides a RESTful API for grammar checking, tone rewriting, and writing analysis. | |
10 | + | |
11 | +**Base URL:** `http://localhost:8787` (local) or your deployed URL | |
12 | + | |
13 | +**Content Type:** `application/json` | |
14 | + | |
15 | +--- | |
16 | + | |
17 | +## π Authentication | |
18 | + | |
19 | +Most endpoints don't require authentication for basic usage. However, AI-powered features require API keys configured in environment variables or passed in requests. | |
20 | + | |
21 | +--- | |
22 | + | |
23 | +## π€ Endpoints | |
24 | + | |
25 | +### Health Check | |
26 | + | |
27 | +#### `GET /health` | |
28 | + | |
29 | +Check server health and status. | |
30 | + | |
31 | +**Request:** | |
32 | +```bash | |
33 | +curl http://localhost:8787/health | |
34 | +``` | |
35 | + | |
36 | +**Response (200 OK):** | |
37 | +```json | |
38 | +{ | |
39 | + "status": "healthy", | |
40 | + "timestamp": "2026-03-14T12:00:00.000Z", | |
41 | + "environment": "production", | |
42 | + "version": "2.1.0" | |
43 | +} | |
44 | +``` | |
45 | + | |
46 | +**Response Fields:** | |
47 | +| Field | Type | Description | | |
48 | +|-------|------|-------------| | |
49 | +| `status` | string | Server status (`healthy`, `unhealthy`) | | |
50 | +| `timestamp` | string | ISO 8601 timestamp | | |
51 | +| `environment` | string | Environment name | | |
52 | +| `version` | string | API version | | |
53 | + | |
54 | +--- | |
55 | + | |
56 | +### List Providers | |
57 | + | |
58 | +#### `GET /providers` | |
59 | + | |
60 | +Get list of available AI providers. | |
61 | + | |
62 | +**Request:** | |
63 | +```bash | |
64 | +curl http://localhost:8787/providers | |
65 | +``` | |
66 | + | |
67 | +**Response (200 OK):** | |
68 | +```json | |
69 | +{ | |
70 | + "providers": [ | |
71 | + { | |
72 | + "id": "groq", | |
73 | + "name": "Groq", | |
74 | + "description": "Fast inference with free tier", | |
75 | + "models": ["llama-3.1-70b-versatile", "llama-3.1-8b-instant"], | |
76 | + "requiresApiKey": true, | |
77 | + "defaultModel": "llama-3.1-70b-versatile" | |
78 | + }, | |
79 | + { | |
80 | + "id": "openai", | |
81 | + "name": "OpenAI", | |
82 | + "description": "Best quality grammar checking", | |
83 | + "models": ["gpt-4o-mini", "gpt-4o", "gpt-3.5-turbo"], | |
84 | + "requiresApiKey": true, | |
85 | + "defaultModel": "gpt-4o-mini" | |
86 | + }, | |
87 | + { | |
88 | + "id": "ollama", | |
89 | + "name": "Ollama (Local)", | |
90 | + "description": "Run models locally", | |
91 | + "models": ["qwen2.5:1.5b", "phi4-mini:3.8b"], | |
92 | + "requiresApiKey": false, | |
93 | + "defaultModel": "qwen2.5:1.5b" | |
94 | + } | |
95 | + ] | |
96 | +} | |
97 | +``` | |
98 | + | |
99 | +--- | |
100 | + | |
101 | +### List Models | |
102 | + | |
103 | +#### `POST /models` | |
104 | + | |
105 | +Get available models for a specific provider. | |
106 | + | |
107 | +**Request:** | |
108 | +```bash | |
109 | +curl -X POST http://localhost:8787/models \ | |
110 | + -H "Content-Type: application/json" \ | |
111 | + -d '{ | |
112 | + "provider": "groq" | |
113 | + }' | |
114 | +``` | |
115 | + | |
116 | +**Response (200 OK):** | |
117 | +```json | |
118 | +{ | |
119 | + "provider": "groq", | |
120 | + "models": [ | |
121 | + { | |
122 | + "id": "llama-3.1-70b-versatile", | |
123 | + "name": "Llama 3.1 70B", | |
124 | + "description": "Best for grammar checking", | |
125 | + "contextWindow": 128000, | |
126 | + "speed": "fast", | |
127 | + "quality": "excellent" | |
128 | + }, | |
129 | + { | |
130 | + "id": "llama-3.1-8b-instant", | |
131 | + "name": "Llama 3.1 8B", | |
132 | + "description": "Fast inference", | |
133 | + "contextWindow": 128000, | |
134 | + "speed": "very fast", | |
135 | + "quality": "good" | |
136 | + } | |
137 | + ] | |
138 | +} | |
139 | +``` | |
140 | + | |
141 | +--- | |
142 | + | |
143 | +### Analyze Text | |
144 | + | |
145 | +#### `POST /analyze` | |
146 | + | |
147 | +Analyze text for grammar, spelling, and style issues. | |
148 | + | |
149 | +**Request:** | |
150 | +```bash | |
151 | +curl -X POST http://localhost:8787/analyze \ | |
152 | + -H "Content-Type: application/json" \ | |
153 | + -d '{ | |
154 | + "text": "me and him went to the store and buyed milks", | |
155 | + "provider": "groq", | |
156 | + "model": "llama-3.1-70b-versatile", | |
157 | + "apiKey": "gsk_xxx", | |
158 | + "options": { | |
159 | + "checkGrammar": true, | |
160 | + "checkSpelling": true, | |
161 | + "checkStyle": true, | |
162 | + "checkClarity": true | |
163 | + } | |
164 | + }' | |
165 | +``` | |
166 | + | |
167 | +**Request Fields:** | |
168 | +| Field | Type | Required | Description | | |
169 | +|-------|------|----------|-------------| | |
170 | +| `text` | string | Yes | Text to analyze (max 50,000 chars) | | |
171 | +| `provider` | string | No | AI provider (default: rule-based only) | | |
172 | +| `model` | string | No | Model to use | | |
173 | +| `apiKey` | string | No | API key (if not set in env) | | |
174 | +| `options` | object | No | Analysis options | | |
175 | + | |
176 | +**Response (200 OK):** | |
177 | +```json | |
178 | +{ | |
179 | + "issues": [ | |
180 | + { | |
181 | + "type": "grammar", | |
182 | + "severity": "error", | |
183 | + "original": "me and him", | |
184 | + "suggestion": "he and I", | |
185 | + "reason": "Subject pronoun error. Use subject pronouns for the subject of a sentence.", | |
186 | + "offset": 0, | |
187 | + "length": 9, | |
188 | + "category": "grammar" | |
189 | + }, | |
190 | + { | |
191 | + "type": "spelling", | |
192 | + "severity": "error", | |
193 | + "original": "buyed", | |
194 | + "suggestion": "bought", | |
195 | + "reason": "Irregular verb form. The past tense of 'buy' is 'bought'.", | |
196 | + "offset": 38, | |
197 | + "length": 5, | |
198 | + "category": "spelling" | |
199 | + } | |
200 | + ], | |
201 | + "metadata": { | |
202 | + "textLength": 49, | |
203 | + "issuesCount": 2, | |
204 | + "processingTimeMs": 245, | |
205 | + "provider": "groq", | |
206 | + "model": "llama-3.1-70b-versatile", | |
207 | + "ruleBasedCount": 0, | |
208 | + "aiBasedCount": 2 | |
209 | + } | |
210 | +} | |
211 | +``` | |
212 | + | |
213 | +**Response Fields:** | |
214 | +| Field | Type | Description | | |
215 | +|-------|------|-------------| | |
216 | +| `issues` | array | List of detected issues | | |
217 | +| `metadata` | object | Analysis metadata | | |
218 | + | |
219 | +**Issue Object:** | |
220 | +| Field | Type | Description | | |
221 | +|-------|------|-------------| | |
222 | +| `type` | string | Issue type (`grammar`, `spelling`, `style`, `clarity`) | | |
223 | +| `severity` | string | Severity (`error`, `warning`, `suggestion`) | | |
224 | +| `original` | string | Original text | | |
225 | +| `suggestion` | string | Suggested replacement | | |
226 | +| `reason` | string | Explanation | | |
227 | +| `offset` | number | Character offset in text | | |
228 | +| `length` | number | Length of issue | | |
229 | +| `category` | string | Category for grouping | | |
230 | + | |
231 | +**Error Responses:** | |
232 | + | |
233 | +**400 Bad Request:** | |
234 | +```json | |
235 | +{ | |
236 | + "error": "Text too long", | |
237 | + "message": "Maximum text length is 50,000 characters" | |
238 | +} | |
239 | +``` | |
240 | + | |
241 | +**401 Unauthorized:** | |
242 | +```json | |
243 | +{ | |
244 | + "error": "API key required", | |
245 | + "message": "Please provide an API key for this provider" | |
246 | +} | |
247 | +``` | |
248 | + | |
249 | +**500 Internal Server Error:** | |
250 | +```json | |
251 | +{ | |
252 | + "error": "Provider error", | |
253 | + "message": "Failed to connect to AI provider" | |
254 | +} | |
255 | +``` | |
256 | + | |
257 | +--- | |
258 | + | |
259 | +### Rewrite Text | |
260 | + | |
261 | +#### `POST /rewrite` | |
262 | + | |
263 | +Rewrite text in a specific tone or style. | |
264 | + | |
265 | +**Request:** | |
266 | +```bash | |
267 | +curl -X POST http://localhost:8787/rewrite \ | |
268 | + -H "Content-Type: application/json" \ | |
269 | + -d '{ | |
270 | + "text": "hey whats up can we talk", | |
271 | + "tone": "formal", | |
272 | + "provider": "groq", | |
273 | + "model": "llama-3.1-70b-versatile", | |
274 | + "apiKey": "gsk_xxx" | |
275 | + }' | |
276 | +``` | |
277 | + | |
278 | +**Request Fields:** | |
279 | +| Field | Type | Required | Description | | |
280 | +|-------|------|----------|-------------| | |
281 | +| `text` | string | Yes | Text to rewrite | | |
282 | +| `tone` | string | Yes | Target tone | | |
283 | +| `provider` | string | No | AI provider | | |
284 | +| `model` | string | No | Model to use | | |
285 | +| `apiKey` | string | No | API key | | |
286 | + | |
287 | +**Available Tones:** | |
288 | +- `formal` - Professional, academic | |
289 | +- `casual` - Relaxed, informal | |
290 | +- `professional` - Business appropriate | |
291 | +- `friendly` - Warm, approachable | |
292 | +- `concise` - Brief, to the point | |
293 | +- `detailed` - Comprehensive, thorough | |
294 | +- `persuasive` - Convincing, compelling | |
295 | +- `neutral` - Balanced, unbiased | |
296 | + | |
297 | +**Response (200 OK):** | |
298 | +```json | |
299 | +{ | |
300 | + "original": "hey whats up can we talk", | |
301 | + "rewritten": "Hello, how are you? May we have a conversation?", | |
302 | + "tone": "formal", | |
303 | + "provider": "groq", | |
304 | + "model": "llama-3.1-70b-versatile", | |
305 | + "metadata": { | |
306 | + "originalLength": 26, | |
307 | + "rewrittenLength": 49, | |
308 | + "processingTimeMs": 1250, | |
309 | + "confidenceScore": 0.95 | |
310 | + } | |
311 | +} | |
312 | +``` | |
313 | + | |
314 | +**Response Fields:** | |
315 | +| Field | Type | Description | | |
316 | +|-------|------|-------------| | |
317 | +| `original` | string | Original text | | |
318 | +| `rewritten` | string | Rewritten text | | |
319 | +| `tone` | string | Applied tone | | |
320 | +| `provider` | string | AI provider used | | |
321 | +| `model` | string | Model used | | |
322 | +| `metadata` | object | Additional information | | |
323 | + | |
324 | +--- | |
325 | + | |
326 | +### Get Statistics | |
327 | + | |
328 | +#### `POST /statistics` | |
329 | + | |
330 | +Get detailed writing statistics. | |
331 | + | |
332 | +**Request:** | |
333 | +```bash | |
334 | +curl -X POST http://localhost:8787/statistics \ | |
335 | + -H "Content-Type: application/json" \ | |
336 | + -d '{ | |
337 | + "text": "Your complete text here..." | |
338 | + }' | |
339 | +``` | |
340 | + | |
341 | +**Response (200 OK):** | |
342 | +```json | |
343 | +{ | |
344 | + "basic": { | |
345 | + "words": 1248, | |
346 | + "characters": 6542, | |
347 | + "charactersNoSpaces": 5421, | |
348 | + "sentences": 87, | |
349 | + "paragraphs": 12, | |
350 | + "syllables": 1876 | |
351 | + }, | |
352 | + "readability": { | |
353 | + "fleschReadingEase": 78.5, | |
354 | + "fleschKincaidGrade": 8.5, | |
355 | + "automatedReadabilityIndex": 9.2, | |
356 | + "readingLevel": "Excellent" | |
357 | + }, | |
358 | + "time": { | |
359 | + "readingTimeSeconds": 374, | |
360 | + "readingTimeFormatted": "6 min 14 sec", | |
361 | + "speakingTimeSeconds": 499, | |
362 | + "speakingTimeFormatted": "8 min 19 sec" | |
363 | + }, | |
364 | + "vocabulary": { | |
365 | + "uniqueWords": 542, | |
366 | + "vocabularyDiversity": 43.4, | |
367 | + "averageWordLength": 4.8, | |
368 | + "longWords": 156 | |
369 | + }, | |
370 | + "issues": { | |
371 | + "grammar": 3, | |
372 | + "spelling": 5, | |
373 | + "style": 7, | |
374 | + "clarity": 4, | |
375 | + "total": 19 | |
376 | + } | |
377 | +} | |
378 | +``` | |
379 | + | |
380 | +**Response Fields:** | |
381 | + | |
382 | +**Basic:** | |
383 | +| Field | Type | Description | | |
384 | +|-------|------|-------------| | |
385 | +| `words` | number | Total words | | |
386 | +| `characters` | number | Characters with spaces | | |
387 | +| `charactersNoSpaces` | number | Characters without spaces | | |
388 | +| `sentences` | number | Total sentences | | |
389 | +| `paragraphs` | number | Total paragraphs | | |
390 | +| `syllables` | number | Total syllables | | |
391 | + | |
392 | +**Readability:** | |
393 | +| Field | Type | Description | | |
394 | +|-------|------|-------------| | |
395 | +| `fleschReadingEase` | number | 0-100 score | | |
396 | +| `fleschKincaidGrade` | number | US grade level | | |
397 | +| `automatedReadabilityIndex` | number | ARI score | | |
398 | +| `readingLevel` | string | Text description | | |
399 | + | |
400 | +**Time:** | |
401 | +| Field | Type | Description | | |
402 | +|-------|------|-------------| | |
403 | +| `readingTimeSeconds` | number | Seconds to read | | |
404 | +| `readingTimeFormatted` | string | Human-readable | | |
405 | +| `speakingTimeSeconds` | number | Seconds to speak | | |
406 | +| `speakingTimeFormatted` | string | Human-readable | | |
407 | + | |
408 | +**Vocabulary:** | |
409 | +| Field | Type | Description | | |
410 | +|-------|------|-------------| | |
411 | +| `uniqueWords` | number | Different words | | |
412 | +| `vocabularyDiversity` | number | Percentage | | |
413 | +| `averageWordLength` | number | Mean characters | | |
414 | +| `longWords` | number | Words > 6 chars | | |
415 | + | |
416 | +--- | |
417 | + | |
418 | +## π Code Examples | |
419 | + | |
420 | +### JavaScript/TypeScript | |
421 | + | |
422 | +```typescript | |
423 | +// Analyze text | |
424 | +async function analyzeText(text: string) { | |
425 | + const response = await fetch('http://localhost:8787/analyze', { | |
426 | + method: 'POST', | |
427 | + headers: { 'Content-Type': 'application/json' }, | |
428 | + body: JSON.stringify({ | |
429 | + text: text, | |
430 | + provider: 'groq', | |
431 | + model: 'llama-3.1-70b-versatile' | |
432 | + }) | |
433 | + }); | |
434 | + | |
435 | + const data = await response.json(); | |
436 | + return data; | |
437 | +} | |
438 | + | |
439 | +// Rewrite text | |
440 | +async function rewriteText(text: string, tone: string) { | |
441 | + const response = await fetch('http://localhost:8787/rewrite', { | |
442 | + method: 'POST', | |
443 | + headers: { 'Content-Type': 'application/json' }, | |
444 | + body: JSON.stringify({ | |
445 | + text: text, | |
446 | + tone: tone | |
447 | + }) | |
448 | + }); | |
449 | + | |
450 | + const data = await response.json(); | |
451 | + return data.rewritten; | |
452 | +} | |
453 | +``` | |
454 | + | |
455 | +### Python | |
456 | + | |
457 | +```python | |
458 | +import requests | |
459 | + | |
460 | +# Analyze text | |
461 | +def analyze_text(text): | |
462 | + response = requests.post( | |
463 | + 'http://localhost:8787/analyze', | |
464 | + json={ | |
465 | + 'text': text, | |
466 | + 'provider': 'groq', | |
467 | + 'model': 'llama-3.1-70b-versatile' | |
468 | + } | |
469 | + ) | |
470 | + return response.json() | |
471 | + | |
472 | +# Rewrite text | |
473 | +def rewrite_text(text, tone): | |
474 | + response = requests.post( | |
475 | + 'http://localhost:8787/rewrite', | |
476 | + json={ | |
477 | + 'text': text, | |
478 | + 'tone': tone | |
479 | + } | |
480 | + ) | |
481 | + return response.json()['rewritten'] | |
482 | + | |
483 | +# Get statistics | |
484 | +def get_statistics(text): | |
485 | + response = requests.post( | |
486 | + 'http://localhost:8787/statistics', | |
487 | + json={'text': text} | |
488 | + ) | |
489 | + return response.json() | |
490 | +``` | |
491 | + | |
492 | +### cURL | |
493 | + | |
494 | +```bash | |
495 | +# Analyze | |
496 | +curl -X POST http://localhost:8787/analyze \ | |
497 | + -H "Content-Type: application/json" \ | |
498 | + -d '{"text": "me and him went", "provider": "groq"}' | |
499 | + | |
500 | +# Rewrite | |
501 | +curl -X POST http://localhost:8787/rewrite \ | |
502 | + -H "Content-Type: application/json" \ | |
503 | + -d '{"text": "hey", "tone": "formal"}' | |
504 | + | |
505 | +# Statistics | |
506 | +curl -X POST http://localhost:8787/statistics \ | |
507 | + -H "Content-Type: application/json" \ | |
508 | + -d '{"text": "Your text here"}' | |
509 | +``` | |
510 | + | |
511 | +--- | |
512 | + | |
513 | +## π§ Error Handling | |
514 | + | |
515 | +### Error Response Format | |
516 | + | |
517 | +```json | |
518 | +{ | |
519 | + "error": "Error type", | |
520 | + "message": "Detailed error message", | |
521 | + "code": "ERROR_CODE" | |
522 | +} | |
523 | +``` | |
524 | + | |
525 | +### Common Error Codes | |
526 | + | |
527 | +| Code | HTTP Status | Description | | |
528 | +|------|-------------|-------------| | |
529 | +| `INVALID_REQUEST` | 400 | Malformed request | | |
530 | +| `TEXT_TOO_LONG` | 400 | Text exceeds 50,000 chars | | |
531 | +| `API_KEY_REQUIRED` | 401 | API key needed | | |
532 | +| `INVALID_API_KEY` | 401 | API key invalid | | |
533 | +| `PROVIDER_ERROR` | 500 | AI provider error | | |
534 | +| `RATE_LIMITED` | 429 | Too many requests | | |
535 | +| `SERVICE_UNAVAILABLE` | 503 | Service down | | |
536 | + | |
537 | +--- | |
538 | + | |
539 | +## π Rate Limiting | |
540 | + | |
541 | +### Default Limits | |
542 | + | |
543 | +| Endpoint | Limit | Window | | |
544 | +|----------|-------|--------| | |
545 | +| `/analyze` | 100 req | 1 minute | | |
546 | +| `/rewrite` | 50 req | 1 minute | | |
547 | +| `/statistics` | 200 req | 1 minute | | |
548 | +| `/health` | Unlimited | - | | |
549 | + | |
550 | +### Rate Limit Response | |
551 | + | |
552 | +**429 Too Many Requests:** | |
553 | +```json | |
554 | +{ | |
555 | + "error": "Rate limit exceeded", | |
556 | + "message": "Too many requests. Please try again in 30 seconds.", | |
557 | + "retryAfter": 30 | |
558 | +} | |
559 | +``` | |
560 | + | |
561 | +--- | |
562 | + | |
563 | +## π Security | |
564 | + | |
565 | +### Input Validation | |
566 | + | |
567 | +- Maximum text length: 50,000 characters | |
568 | +- Sanitized input | |
569 | +- Type checking | |
570 | +- JSON validation | |
571 | + | |
572 | +### API Key Handling | |
573 | + | |
574 | +- Keys stored in environment variables | |
575 | +- Never logged | |
576 | +- Passed securely to providers | |
577 | +- Not retained by backend | |
578 | + | |
579 | +### CORS | |
580 | + | |
581 | +Configured for browser extensions: | |
582 | +```typescript | |
583 | +app.use('*', cors({ | |
584 | + origin: ['chrome-extension://*', 'moz-extension://*'], | |
585 | + credentials: true | |
586 | +})); | |
587 | +``` | |
588 | + | |
589 | +--- | |
590 | + | |
591 | +## π Performance | |
592 | + | |
593 | +### Response Times | |
594 | + | |
595 | +| Endpoint | Avg (ms) | P95 (ms) | P99 (ms) | | |
596 | +|----------|----------|----------|----------| | |
597 | +| `/health` | 10 | 20 | 50 | | |
598 | +| `/analyze` (rule-based) | 50 | 100 | 200 | | |
599 | +| `/analyze` (AI) | 1000 | 2000 | 3000 | | |
600 | +| `/rewrite` | 1500 | 2500 | 4000 | | |
601 | +| `/statistics` | 100 | 200 | 300 | | |
602 | + | |
603 | +### Optimization Tips | |
604 | + | |
605 | +1. **Use rule-based for simple checks** - Faster, no API cost | |
606 | +2. **Batch requests** - Combine multiple texts | |
607 | +3. **Cache results** - Store common analyses | |
608 | +4. **Use appropriate models** - Smaller models for simple tasks | |
609 | + | |
610 | +--- | |
611 | + | |
612 | +## π Related Documentation | |
613 | + | |
614 | +- [Backend Deployment](05-backend-deployment.md) - Deploy the API | |
615 | +- [AI Providers](07-ai-providers.md) - Configure providers | |
616 | +- [Troubleshooting](18-troubleshooting.md) - Fix issues | |
617 | + | |
618 | +--- | |
619 | + | |
620 | +**API Version:** 2.1.0 | |
621 | +**Last Updated:** March 2026 | |
0 | 622 | |