Created
March 9, 2024 23:43
-
-
Save alexdwagner/8c915d9571dddffadacbbd85f842fcbd to your computer and use it in GitHub Desktop.
Node.js Server for Key-Value Store and Journal Entries
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Node.js Server for Key-Value Store and Journal Entries | |
* | |
* This server provides in-memory storage for key-value pairs and structured journal entries. | |
* | |
* It listens on http://localhost:4000/, storing key-value pairs sent via http://localhost:4000/set?somekey=somevalue | |
* and retrieving values when requested via http://localhost:4000/get?key=somekey. | |
* | |
* It supports storing and retrieving data via HTTP POST and GET requests. Key features include: | |
* | |
* - Key-Value Store: Simple storage solution for configuration settings or generic data. | |
* - Journal Entries: Allows saving journal entries with timestamps and tags. | |
* - Tag-Based Search: Retrieve journal entries based on tags. | |
* | |
* Usage: | |
* - POST `/set` to store key-value pairs or journal entries. | |
* - GET `/get` with `key`, `id`, or `tag` query parameters to retrieve data. | |
* | |
* Designed for ease of use and quick integration into development projects. | |
*/ | |
const http = require('http'); | |
const url = require('url'); | |
let keyValueStore = {}; // Object to hold key-value pairs | |
// Journal entry schema | |
let journalEntries = {}; // Object to hold journal entries as key-value pairs | |
let tagsIndex = {}; // Object to map tags to entry IDs | |
let nextJournalId = 1; // Counter to generate unique IDs for journal entries | |
// Generates a unique ID for each journal entry | |
const generateJournalId = () => `entry-${nextJournalId++}`; | |
/** | |
* Saves a journal entry with associated tags. | |
* @param {string} entryText - The text of the journal entry. | |
* @param {Array} tags - An array of tags associated with the journal entry. | |
* @returns The unique ID of the saved journal entry. | |
*/ | |
function saveJournalEntry(entryText, tags = []) { | |
const journalId = generateJournalId(); | |
const timestamp = new Date().toISOString(); | |
// Saving the entry as a key-value pair | |
journalEntries[journalId] = { | |
entry: entryText, | |
timestamp: timestamp, | |
tags: tags | |
}; | |
// Update the tags index | |
updateTagsIndex(journalId, tags); | |
console.log(`\nJournal entry "${journalId}" saved with tags: ${tags.join(', ')}`); | |
return journalId; // For response purpose | |
} | |
/** | |
* Updates the index mapping tags to journal entry IDs. | |
* @param {string} entryId - The ID of the journal entry. | |
* @param {Array} tags - An array of tags to be indexed. | |
*/ | |
function updateTagsIndex(entryId, tags) { | |
tags.forEach(tag => { | |
if (!tagsIndex[tag]) { | |
tagsIndex[tag] = []; | |
} | |
tagsIndex[tag].push(entryId); | |
}); | |
} | |
/** | |
* Retrieves a journal entry by its ID. | |
* @param {string} entryId The ID of the journal entry. | |
* @returns The journal entry if found, or undefined. | |
*/ | |
function getEntryById(entryId) { | |
return journalEntries[entryId]; | |
} | |
/** | |
* Retrieves journal entries associated with a specific tag. | |
* @param {string} tag The tag used for filtering entries. | |
* @returns {Array} An array of journal entries associated with the tag. | |
*/ | |
function getEntriesByTag(tag) { | |
const entryIds = tagsIndex[tag] || []; | |
return entryIds.map(id => journalEntries[id]); | |
} | |
// Server request listener | |
const server = http.createServer((req, res) => { | |
const parsedUrl = url.parse(req.url, true); | |
// Handle POST requests for setting values or journal entries | |
if (req.method === 'POST' && parsedUrl.pathname === '/set') { | |
let body = ''; | |
req.on('data', chunk => body += chunk.toString()); | |
req.on('end', () => { | |
const data = JSON.parse(body); | |
// Distinguish between general key-value pairs and journal entry requests based on body content | |
if ('key' in data && 'value' in data) { | |
keyValueStore[data.key] = data.value; | |
res.writeHead(200, { 'Content-Type': 'application/json' }); | |
res.end(JSON.stringify({ message: 'Key-value pair saved successfully' })); | |
} else if ('entry' in data && 'tags' in data) { | |
const id = saveJournalEntry(data.entry, data.tags); | |
res.writeHead(200, { 'Content-Type': 'application/json' }); | |
res.end(JSON.stringify({ message: 'Journal entry saved successfully', id })); | |
} else { | |
res.writeHead(400, { 'Content-Type': 'application/json' }); | |
res.end(JSON.stringify({ error: 'Invalid request format' })); | |
} | |
}); | |
} | |
// Handle GET requests for retrieving values, journal entries, or entries by tag | |
else if (req.method === 'GET' && parsedUrl.pathname === '/get') { | |
const { key, id, tag } = parsedUrl.query; | |
if (key) { | |
// Return value from key-value store | |
if (key in keyValueStore) { | |
res.writeHead(200, { 'Content-Type': 'application/json' }); | |
res.end(JSON.stringify({ value: keyValueStore[key] })); | |
} else { | |
res.writeHead(404, { 'Content-Type': 'application/json' }); | |
res.end(JSON.stringify({ error: 'Key not found' })); | |
} | |
} else if (id) { | |
// Return specific journal entry by id | |
const entry = journalEntries[id]; | |
if (entry) { | |
res.writeHead(200, { 'Content-Type': 'application/json' }); | |
res.end(JSON.stringify(entry)); | |
} else { | |
res.writeHead(404, { 'Content-Type': 'application/json' }); | |
res.end(JSON.stringify({ error: 'Journal entry not found' })); | |
} | |
} else if (tag) { | |
// Return journal entries by tag | |
const entriesByTag = getEntriesByTag(tag); | |
if (entriesByTag.length > 0) { | |
res.writeHead(200, { 'Content-Type': 'application/json' }); | |
res.end(JSON.stringify(entriesByTag)); | |
} else { | |
res.writeHead(404, { 'Content-Type': 'application/json' }); | |
res.end(JSON.stringify({ error: 'No entries found for this tag' })); | |
} | |
} else { | |
res.writeHead(400, { 'Content-Type': 'application/json' }); | |
res.end(JSON.stringify({ error: 'Invalid query parameters' })); | |
} | |
} else { | |
// Fallback for unsupported paths or methods | |
res.writeHead(404, { 'Content-Type': 'application/json' }); | |
res.end(JSON.stringify({ error: 'Not Found' })); | |
} | |
}); | |
// Start the server | |
const port = 4000; | |
server.listen(port, () => { | |
console.log(`\n***-Server is running on http://localhost:${port}-***`); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment