|
1 |
| -# HackMD API Clients |
| 1 | +# Add ETag Support to HackMD API Client |
2 | 2 |
|
3 |
| -This repository contains a set of packages for interacting with the [HackMD API](https://hackmd.io/). |
| 3 | +This repository contains a set of packages for interacting with the [HackMD API](https://hackmd.io/), forked from [upstream repository](https://github.com/hackmdio/api-client). |
4 | 4 |
|
5 |
| -## Node.JS |
| 5 | +## Summary |
| 6 | +This repo implements ETag support for HackMD API client operations, enabling conditional requests and response caching. |
6 | 7 |
|
7 |
| -See [README](./nodejs) |
| 8 | +## Technical Details |
| 9 | + - Added ETag support to GET, POST, and PATCH operations for user notes |
| 10 | + - ETags are now accessible in responses for `getNote`, `createNote`, `updateNote`, and `updateNoteContent` |
| 11 | + - Implemented proper handling of 304 Not Modified responses for conditional GET requests |
8 | 12 |
|
9 |
| -## LICENSE |
| 13 | +## Code Examples |
10 | 14 |
|
11 |
| -MIT |
| 15 | +### 1. Creating a note |
| 16 | +```typescript |
| 17 | +// Create a note and receive ETag in response |
| 18 | +const newNote = await client.createNote({ |
| 19 | +title: 'New Note', |
| 20 | +content: 'Initial content' |
| 21 | +}) |
| 22 | +console.log(newNote.etag) // 'W/"abc123"' |
| 23 | +``` |
| 24 | + |
| 25 | +### 2. Reading a note |
| 26 | +```typescript |
| 27 | +// Get the note and store its ETag |
| 28 | +const note = await client.getNote(newNote.id) |
| 29 | +console.log(note.etag) // 'W/"abc123"' |
| 30 | +``` |
| 31 | + |
| 32 | +### 3. Updating a note |
| 33 | +```typescript |
| 34 | +// Update the note and receive a new ETag |
| 35 | +const updatedNote = await client.updateNoteContent(note.id, 'Updated content') |
| 36 | +console.log(updatedNote.etag) // 'W/"xyz789"' (different from original) |
| 37 | +``` |
| 38 | + |
| 39 | +### 4. Conditional read with original ETag (will get new content) |
| 40 | +```typescript |
| 41 | +// Try reading with the original ETag |
| 42 | +const result1 = await client.getNote(note.id, { |
| 43 | +etag: note.etag // original ETag that's now outdated |
| 44 | +}) |
| 45 | + |
| 46 | +// Content has changed, so we get the new version |
| 47 | +console.log(result1.status) // undefined (normal 200 response) |
| 48 | +console.log(result1.content) // 'Updated content' |
| 49 | +console.log(result1.etag) // 'W/"xyz789"' |
| 50 | +``` |
| 51 | + |
| 52 | +### 5. Conditional read with updated ETag (will get 304) |
| 53 | +```typescript |
| 54 | +// Try reading with the latest ETag |
| 55 | +const result2 = await client.getNote(note.id, { |
| 56 | +etag: updatedNote.etag // current ETag |
| 57 | +}) |
| 58 | + |
| 59 | +// Content hasn't changed, so we get 304 Not Modified |
| 60 | +console.log(result2.status) // 304 |
| 61 | +console.log(result2.content) // undefined |
| 62 | +console.log(result2.etag) // 'W/"xyz789"' (same as before) |
| 63 | +``` |
| 64 | + |
| 65 | +## Limitations |
| 66 | + - The HackMD API server does not currently support If-Match headers in PATCH requests, limiting conditional updates |
| 67 | + - Current implementation focuses on user notes operations - the most commonly used endpoints. |
| 68 | + |
| 69 | +## Implementation Approach |
| 70 | + - Made ETag usage optional to preserve backward compatibility |
| 71 | + - Included ETags automatically in responses when available |
| 72 | + - Required explicit opt-in for conditional requests via the options parameter |
| 73 | + - Focused implementation on user notes operations only (not team notes) |
| 74 | + - Comprehensive test suite verifies all ETag functionality scenarios |
| 75 | + |
| 76 | +## Security |
| 77 | + - Updated dependencies to fix vulnerabilities |
0 commit comments