From 3bcae89fb942b83c9a2ebf314cbd6422a887b81a Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Thu, 22 Jan 2026 13:03:02 +0100 Subject: [PATCH 01/23] routes: all messages, liked messages, messages containing happy --- server.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/server.js b/server.js index f47771bd..42f61f27 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ import cors from "cors" import express from "express" +import data from "./data.json" // Defines the port the app will run on. Defaults to 8080, but can be overridden // when starting the server. Example command to overwrite PORT env variable value: @@ -16,6 +17,23 @@ app.get("/", (req, res) => { res.send("Hello Technigo!") }) +// returns all messages in array +app.get("/messages", (req, res) => { + res.json(data) +}) + +// filters messages and returns all liked messages +app.get("/messages/liked", (req, res) => { + let likedMessages = data.filter(message => message.hearts > 0) + res.json(likedMessages) +}) + +// filters messages and returns those containing the word happy +app.get("/messages/happy", (req, res) => { + let happyMessages = data.filter(message => message.message.toLowerCase().includes("happy")) + res.json(happyMessages) +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From c02207ff0c792d1fe589097fb74f2de68d13dcde Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Thu, 22 Jan 2026 13:51:20 +0100 Subject: [PATCH 02/23] return single message according to id. Error message displayed if id does not exist --- package.json | 2 ++ server.js | 22 ++++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index bf25bb68..1b2103ff 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "project-api", "version": "1.0.0", "description": "Project API", + "type": "module", "scripts": { "start": "babel-node server.js", "dev": "nodemon server.js --exec babel-node" @@ -14,6 +15,7 @@ "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", "express": "^4.17.3", + "express-list-endpoints": "^7.1.1", "nodemon": "^3.0.1" } } diff --git a/server.js b/server.js index 42f61f27..73427d04 100644 --- a/server.js +++ b/server.js @@ -1,10 +1,9 @@ import cors from "cors" import express from "express" -import data from "./data.json" +import data from "./data.json" with { type: "json" } +import listEndpoints from "express-list-endpoints" // Defines the port the app will run on. Defaults to 8080, but can be overridden -// when starting the server. Example command to overwrite PORT env variable value: -// PORT=9000 npm start const port = process.env.PORT || 8080 const app = express() @@ -14,7 +13,11 @@ app.use(express.json()) // Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Technigo!") + const endpoints = listEndpoints(app) + res.json({ + message: "Welcome to tha happy thoughts API", + endpoints: endpoints, + }) }) // returns all messages in array @@ -34,6 +37,17 @@ app.get("/messages/happy", (req, res) => { res.json(happyMessages) }) +// returns a single message with specific id, displays error message if id does not exist +app.get("/messages/:id", (req, res) => { + const message = data.find(message => message._id === req.params.id) + + if (!message) { + return res.status(404).json({ error: "no message with that id" }) + } + + res.json(message) +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From a2d7f47d1306363f636ad96dc75e0b01b5306617 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Fri, 23 Jan 2026 13:49:19 +0100 Subject: [PATCH 03/23] added route for query param, filter messages that are liked --- server.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index 73427d04..60e03310 100644 --- a/server.js +++ b/server.js @@ -11,33 +11,33 @@ const app = express() app.use(cors()) app.use(express.json()) -// Start defining your routes here +// ROUTES + +// Path params app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json({ - message: "Welcome to tha happy thoughts API", + message: "Welcome to the happy thoughts API. Here is a list of all endpoints", endpoints: endpoints, }) }) -// returns all messages in array app.get("/messages", (req, res) => { res.json(data) }) -// filters messages and returns all liked messages app.get("/messages/liked", (req, res) => { let likedMessages = data.filter(message => message.hearts > 0) + res.json(likedMessages) }) -// filters messages and returns those containing the word happy app.get("/messages/happy", (req, res) => { let happyMessages = data.filter(message => message.message.toLowerCase().includes("happy")) + res.json(happyMessages) }) -// returns a single message with specific id, displays error message if id does not exist app.get("/messages/:id", (req, res) => { const message = data.find(message => message._id === req.params.id) @@ -48,6 +48,17 @@ app.get("/messages/:id", (req, res) => { res.json(message) }) +// query params +app.get("/hearts", (req, res) => { + let result = data + + if (req.query.liked === "true") { + result = result.filter(message => message.hearts > 0) + } + + res.json(result) + }) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From c9e77c7f6783692954e03029776a16bd6f74f777 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Wed, 28 Jan 2026 13:38:18 +0100 Subject: [PATCH 04/23] connected mongoose, build schema for message and model based on schema --- package.json | 1 + server.js | 27 ++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1b2103ff..30e8b868 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "cors": "^2.8.5", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", + "mongoose": "^9.1.5", "nodemon": "^3.0.1" } } diff --git a/server.js b/server.js index 60e03310..6491f364 100644 --- a/server.js +++ b/server.js @@ -2,18 +2,36 @@ import cors from "cors" import express from "express" import data from "./data.json" with { type: "json" } import listEndpoints from "express-list-endpoints" +import mongoose from "mongoose" + +// NOTE - add .env file? +const mongoUrl = process.env.MONGO_URL || "mongodb://127.0.0.1/project-api" +mongoose.connect(mongoUrl) -// Defines the port the app will run on. Defaults to 8080, but can be overridden const port = process.env.PORT || 8080 const app = express() -// Add middlewares to enable cors and json body parsing app.use(cors()) app.use(express.json()) -// ROUTES +// Message schema +const messageSchema = new mongoose.Schema({ + message: { + type: String, + required: true, + minlength: 1, + }, + hearts: { + type: Number, + default: 0 + }, + // timestamps? +}) -// Path params +// Model based on schema +const Message = mongoose.model('Message', messageSchema) + +// ROUTES app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json({ @@ -48,7 +66,6 @@ app.get("/messages/:id", (req, res) => { res.json(message) }) -// query params app.get("/hearts", (req, res) => { let result = data From b85aa64e43236c73096fca35a9b26dd3d72274d9 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Wed, 28 Jan 2026 14:49:47 +0100 Subject: [PATCH 05/23] post request, post message --- server.js | 90 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 15 deletions(-) diff --git a/server.js b/server.js index 6491f364..4d147ecc 100644 --- a/server.js +++ b/server.js @@ -1,11 +1,11 @@ import cors from "cors" -import express from "express" -import data from "./data.json" with { type: "json" } +import express, { application } from "express" +// import data from "./data.json" with { type: "json" } import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" // NOTE - add .env file? -const mongoUrl = process.env.MONGO_URL || "mongodb://127.0.0.1/project-api" +const mongoUrl = process.env.MONGO_URL || "mongodb://127.0.0.1/messages" mongoose.connect(mongoUrl) const port = process.env.PORT || 8080 @@ -25,13 +25,38 @@ const messageSchema = new mongoose.Schema({ type: Number, default: 0 }, - // timestamps? + createdAt: { + type: Date, + default: () => Date.now() + } }) -// Model based on schema +// Model const Message = mongoose.model('Message', messageSchema) -// ROUTES +if (process.env.RESET_DATABASE) { + // create messages in database + const seedDatabase = async () => { + // Avoid content in api from being duplicated on refresh + await Message.deleteMany() + + const testMessage = new Message({ + message: 'I am testing', + hearts: 3 + }) + await testMessage.save() + + const testMessageTwo = new Message({ + message: 'is it working?', + hearts: 10 + }) + await testMessageTwo.save() + + } + seedDatabase() +} + +// ROUTES GET app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json({ @@ -40,22 +65,38 @@ app.get("/", (req, res) => { }) }) -app.get("/messages", (req, res) => { - res.json(data) +// GET all messages +app.get("/messages", async (req, res) => { + const messages = await Message.find() + res.json(messages) }) +// GET liked messages app.get("/messages/liked", (req, res) => { let likedMessages = data.filter(message => message.hearts > 0) res.json(likedMessages) }) +// GET liked messages (query param) +app.get("/hearts", (req, res) => { + let result = data + + if (req.query.liked === "true") { + result = result.filter(message => message.hearts > 0) + } + + res.json(result) + }) + +// GET messages including word happy app.get("/messages/happy", (req, res) => { let happyMessages = data.filter(message => message.message.toLowerCase().includes("happy")) res.json(happyMessages) }) +// GET a single message app.get("/messages/:id", (req, res) => { const message = data.find(message => message._id === req.params.id) @@ -66,17 +107,36 @@ app.get("/messages/:id", (req, res) => { res.json(message) }) -app.get("/hearts", (req, res) => { - let result = data +// ROUTES POST - if (req.query.liked === "true") { - result = result.filter(message => message.hearts > 0) - } +// TODO: Liking a thought + +// POST a message (authenticated?) +app.post('/messages', async (req, res) => { + const message = new Message({ + message: req.body.message, + hearts: req.body.hearts + }) + await message.save() + res.json(message) +}) + +// TODO: Update a message (authenticated) + +// TODO: Delete a message + +// TODO: Signing up + +// TODO: signing in - res.json(result) - }) // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) }) + +// TODO +// 1. Connect input (messages) from happy thoughts app to api +// 2. Your API should validate user input and return appropriate errors if the input is invalid. +// 3. You should implement error handling for all your routes, with proper response statuses. +// 4. Your frontend should be updated with the possibility to Update and Delete a thought. \ No newline at end of file From 604cf95552b6be4e45c5ca33a300974254d82d71 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Thu, 29 Jan 2026 16:25:35 +0100 Subject: [PATCH 06/23] error handling added to get routes --- package.json | 1 + server.js | 117 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 78 insertions(+), 40 deletions(-) diff --git a/package.json b/package.json index 30e8b868..beb6cc03 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", + "dotenv": "^17.2.3", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", "mongoose": "^9.1.5", diff --git a/server.js b/server.js index 4d147ecc..6a21d156 100644 --- a/server.js +++ b/server.js @@ -3,6 +3,7 @@ import express, { application } from "express" // import data from "./data.json" with { type: "json" } import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" +import "dotenv/config" // NOTE - add .env file? const mongoUrl = process.env.MONGO_URL || "mongodb://127.0.0.1/messages" @@ -31,32 +32,39 @@ const messageSchema = new mongoose.Schema({ } }) -// Model +// Model based on schema const Message = mongoose.model('Message', messageSchema) +// Seed database if (process.env.RESET_DATABASE) { - // create messages in database + const seedDatabase = async () => { // Avoid content in api from being duplicated on refresh await Message.deleteMany() const testMessage = new Message({ - message: 'I am testing', - hearts: 3 + message: 'Backend is fun!', + hearts: 5 }) await testMessage.save() const testMessageTwo = new Message({ - message: 'is it working?', - hearts: 10 + message: 'I get happy when it is working!', + hearts: 1 }) await testMessageTwo.save() + const testMessageThree = new Message({ + message: 'Snow today, yay!!', + hearts: 0 + }) + await testMessageThree.save() + } seedDatabase() } -// ROUTES GET +// ROUTES (GET) app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json({ @@ -67,51 +75,80 @@ app.get("/", (req, res) => { // GET all messages app.get("/messages", async (req, res) => { - const messages = await Message.find() - res.json(messages) + try { + const messages = await Message.find() + res.json(messages) + } catch (error) { + res.status(500).json({ error: "Failed to fetch messages "}) + } }) // GET liked messages -app.get("/messages/liked", (req, res) => { - let likedMessages = data.filter(message => message.hearts > 0) - - res.json(likedMessages) +app.get("/messages/liked", async (req, res) => { + try { + let likedMessages = await Message.find ({ hearts: { $gt: 0 } }) + + if (likedMessages.length === 0) { + return res.status(404).json ({ error: "No liked messages found" }) + } + + res.json(likedMessages) + } catch (error) { + res.status(500).json({ error: "Failed to get liked messages" }) + } }) // GET liked messages (query param) -app.get("/hearts", (req, res) => { - let result = data +// TODO Error handling +// app.get("/hearts", (req, res) => { +// let result = data - if (req.query.liked === "true") { - result = result.filter(message => message.hearts > 0) - } +// if (req.query.liked === "true") { +// result = result.filter(message => message.hearts > 0) +// } - res.json(result) - }) +// res.json(result) +// }) // GET messages including word happy -app.get("/messages/happy", (req, res) => { - let happyMessages = data.filter(message => message.message.toLowerCase().includes("happy")) - - res.json(happyMessages) -}) +app.get("/messages/happy", async (req, res) => { + try { + let happyMessages = await Message.find({ message: { $regex: "happy" } }) + + if (happyMessages.length === 0) { + return res.status(404).json({ error: "No messages including the word happy" }) + } + + res.json(happyMessages) + + } catch (error) { + res.status(500).json({ error: "Failed to get messages including the word happy" }) + } + }) -// GET a single message -app.get("/messages/:id", (req, res) => { - const message = data.find(message => message._id === req.params.id) +// GET a single message +app.get("/messages/:id", async (req, res) => { + try { + const message = await Message.findById(req.params.id) - if (!message) { - return res.status(404).json({ error: "no message with that id" }) + if (message) { + res.json(message) + + } else { + return res.status(404).json({ error: "no message with that id found" }) + } + } catch (error) { + res.status(400).json ({ error: "Invalid user id"}) } - res.json(message) }) -// ROUTES POST +// ROUTES (POST) // TODO: Liking a thought // POST a message (authenticated?) +// TODO Error handling app.post('/messages', async (req, res) => { const message = new Message({ message: req.body.message, @@ -123,11 +160,11 @@ app.post('/messages', async (req, res) => { // TODO: Update a message (authenticated) -// TODO: Delete a message +// TODO: Delete a message (frontend) -// TODO: Signing up +// TODO: Signing up (next week) -// TODO: signing in +// TODO: signing in (next week) // Start the server @@ -135,8 +172,8 @@ app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) }) -// TODO -// 1. Connect input (messages) from happy thoughts app to api -// 2. Your API should validate user input and return appropriate errors if the input is invalid. -// 3. You should implement error handling for all your routes, with proper response statuses. -// 4. Your frontend should be updated with the possibility to Update and Delete a thought. \ No newline at end of file +// TODO Today +// 2. Validate data both in the model (Mongoose) and in your POST routes +// 4. Frontend should be updated with the possibility to Update and Delete a thought. +// 5. Deploy database on Render +// 6. Connect happy thoughts frontend to new API \ No newline at end of file From e655ba07ce7c55722ea627232efcfca092853b25 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Fri, 30 Jan 2026 11:03:50 +0100 Subject: [PATCH 07/23] error handling added to post message route --- package.json | 1 + server.js | 41 ++++++++++++++++++++--------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index beb6cc03..148436c5 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "dotenv": "^17.2.3", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", + "mongodb": "^7.0.0", "mongoose": "^9.1.5", "nodemon": "^3.0.1" } diff --git a/server.js b/server.js index 6a21d156..36512af5 100644 --- a/server.js +++ b/server.js @@ -5,7 +5,6 @@ import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" import "dotenv/config" -// NOTE - add .env file? const mongoUrl = process.env.MONGO_URL || "mongodb://127.0.0.1/messages" mongoose.connect(mongoUrl) @@ -28,7 +27,7 @@ const messageSchema = new mongoose.Schema({ }, createdAt: { type: Date, - default: () => Date.now() + default: Date.now } }) @@ -76,8 +75,9 @@ app.get("/", (req, res) => { // GET all messages app.get("/messages", async (req, res) => { try { - const messages = await Message.find() + const messages = await Message.find().sort({ createdAt: 'desc' }) res.json(messages) + } catch (error) { res.status(500).json({ error: "Failed to fetch messages "}) } @@ -147,26 +147,21 @@ app.get("/messages/:id", async (req, res) => { // TODO: Liking a thought -// POST a message (authenticated?) -// TODO Error handling +// POST a message app.post('/messages', async (req, res) => { - const message = new Message({ - message: req.body.message, - hearts: req.body.hearts - }) - await message.save() - res.json(message) + try { + const message = new Message({ + message: req.body.message, + hearts: req.body.hearts + }) + await message.save() + res.status(200).json(message) + } catch (error) { + res.status(400).json({ message: 'Could not save the message', errors:error.errors }) + } + }) -// TODO: Update a message (authenticated) - -// TODO: Delete a message (frontend) - -// TODO: Signing up (next week) - -// TODO: signing in (next week) - - // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) @@ -176,4 +171,8 @@ app.listen(port, () => { // 2. Validate data both in the model (Mongoose) and in your POST routes // 4. Frontend should be updated with the possibility to Update and Delete a thought. // 5. Deploy database on Render -// 6. Connect happy thoughts frontend to new API \ No newline at end of file +// 6. Connect happy thoughts frontend to new API + +// TODO: Signing up (next week) + +// TODO: signing in (next week) \ No newline at end of file From 77a1bf204bd7302db2c688f38ba21786c9b4426c Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Fri, 30 Jan 2026 13:58:08 +0100 Subject: [PATCH 08/23] RESET_DATABASE set to false --- server.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/server.js b/server.js index 36512af5..6bb08604 100644 --- a/server.js +++ b/server.js @@ -19,7 +19,8 @@ const messageSchema = new mongoose.Schema({ message: { type: String, required: true, - minlength: 1, + minlength: 5, + // not matching frontend }, hearts: { type: Number, @@ -145,8 +146,6 @@ app.get("/messages/:id", async (req, res) => { // ROUTES (POST) -// TODO: Liking a thought - // POST a message app.post('/messages', async (req, res) => { try { @@ -168,11 +167,10 @@ app.listen(port, () => { }) // TODO Today -// 2. Validate data both in the model (Mongoose) and in your POST routes -// 4. Frontend should be updated with the possibility to Update and Delete a thought. -// 5. Deploy database on Render -// 6. Connect happy thoughts frontend to new API +// 1. Frontend should be updated with the possibility to Update and Delete a thought. +// 2. Liking a thought route -// TODO: Signing up (next week) + +// TODO: Signing up (next week) // TODO: signing in (next week) \ No newline at end of file From 832639e374612cdac74ef6d8ea0374a22457bec9 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Sun, 1 Feb 2026 15:43:06 +0100 Subject: [PATCH 09/23] Route for sending likes added. With error handling --- server.js | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/server.js b/server.js index 6bb08604..8b4ed15e 100644 --- a/server.js +++ b/server.js @@ -144,8 +144,30 @@ app.get("/messages/:id", async (req, res) => { }) -// ROUTES (POST) +// ROUTES (PATCH) +// send likes +app.patch("/messages/:id/like", async (req, res) => { + try { + const message = await Message.findByIdAndUpdate( + req.params.id, + { $inc: { hearts: 1 } }, + { new: true } + ) + + if (!message) { + return res.status(404).json({ error: "Messsage not found" }) + } + + res.json(message) + + } catch (error) { + res.status(400).json({ error: "could not update likes" }) + } +}) + +// TODO UPDATE a message +// ROUTES (POST) // POST a message app.post('/messages', async (req, res) => { try { @@ -161,16 +183,15 @@ app.post('/messages', async (req, res) => { }) +// TODO DELETE a message + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) }) -// TODO Today -// 1. Frontend should be updated with the possibility to Update and Delete a thought. -// 2. Liking a thought route - - - -// TODO: Signing up (next week) -// TODO: signing in (next week) \ No newline at end of file +// TODOS +// Frontend should be updated with the possibility to Update a thought. +// Problems with timestamps. not correct timeAgo showed +// Signing up (next week) +// signing in (next week) \ No newline at end of file From 5d3d87f5ceacce95264eff3d3cfca256f681943b Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Mon, 2 Feb 2026 17:00:23 +0100 Subject: [PATCH 10/23] route for deleting message --- server.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 8b4ed15e..e57a7cc9 100644 --- a/server.js +++ b/server.js @@ -183,7 +183,19 @@ app.post('/messages', async (req, res) => { }) -// TODO DELETE a message +// DELETE a message +app.delete("/messages/:id", async (req, res) => { + try { + const deletedMessage = await Message.findByIdAndDelete(req.params.id) + + if (!deletedMessage) { + return res.status(404).json({ error: "Message not found" }) + } + res.status(200).json(deletedMessage) + } catch (error) { + res.status(400).json({ error: "Invalid message id" }) + } +}) // Start the server app.listen(port, () => { From 277c3fd9860cd41112b839a6c95f169108374837 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Tue, 3 Feb 2026 14:25:40 +0100 Subject: [PATCH 11/23] user model, routes for athenticating user --- package.json | 1 + server.js | 94 +++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 83 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 148436c5..83f106aa 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@babel/core": "^7.17.9", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", + "bcrypt": "^6.0.0", "cors": "^2.8.5", "dotenv": "^17.2.3", "express": "^4.17.3", diff --git a/server.js b/server.js index e57a7cc9..ad02e749 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,8 @@ import express, { application } from "express" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" import "dotenv/config" +import crypto from "crypto" +import bcrypt from "bcrypt" const mongoUrl = process.env.MONGO_URL || "mongodb://127.0.0.1/messages" mongoose.connect(mongoUrl) @@ -20,7 +22,6 @@ const messageSchema = new mongoose.Schema({ type: String, required: true, minlength: 5, - // not matching frontend }, hearts: { type: Number, @@ -32,9 +33,45 @@ const messageSchema = new mongoose.Schema({ } }) -// Model based on schema +// Message model const Message = mongoose.model('Message', messageSchema) +// User schema +const userSchema = new mongoose.Schema({ + name: { + type: String, + unique: true + }, + email: { + type: String, + unique: true + }, + password: { + type: String, + required: true + }, + accessToken: { + type: String, + default: () => crypto.randomBytes(128).toString('hex') + // default access token using crypto library + } +}) + +// User model +const User = mongoose.model('User', userSchema) + +// Look up user based on the access token stored in the header +const authenticateUser = async (req, res, next) => { + const user = await User.findOne({ accessToken: req.header('Authorization') }) + if (user){ + req.user = user + // next function allows the protected endpoint to continue execution + next() + } else { + res.status(401).json({loggedOut: true}) + } +} + // Seed database if (process.env.RESET_DATABASE) { @@ -64,7 +101,7 @@ if (process.env.RESET_DATABASE) { seedDatabase() } -// ROUTES (GET) +// Show all available endpoints app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json({ @@ -73,7 +110,42 @@ app.get("/", (req, res) => { }) }) -// GET all messages +// POST-route: register user +// user registers with name, email and password. We get an access token when they log in +app.post('/users', async (req, res) => { + try { + const { name, email, password } = req.body + + const salt = bcrypt.genSaltSync() + const user = new User({ name, email, password: bcrypt.hashSync(password, salt) }) + + user.save() + + res.status(201).json({ id:user._id, accessToken: user.accessToken }) + + } catch(error) { + res.status(400).json({ message: 'Could not create user', errors:error.errors }) + } +}) + +// +app.get('/secrets', authenticateUser) +app.get('/secrets', (req, res) => { + res.json({secret: 'This is a super secret message'}) +}) + +// POST-route: log in (doesnt create the user, it finds one) +app.post('/sessions', async(req, res) => { + const user = await User.findOne({ email: req.body.email }) + + if (user && bcrypt.compareSync(req.body.password, user.password)) { + res.json({ userID: user._id , accessToken: user.accessToken}) + } else { + res.json({ notFound: true }) + } +}) + +// GET-route: show all messages app.get("/messages", async (req, res) => { try { const messages = await Message.find().sort({ createdAt: 'desc' }) @@ -84,7 +156,7 @@ app.get("/messages", async (req, res) => { } }) -// GET liked messages +// GET-route: show liked messages app.get("/messages/liked", async (req, res) => { try { let likedMessages = await Message.find ({ hearts: { $gt: 0 } }) @@ -111,7 +183,7 @@ app.get("/messages/liked", async (req, res) => { // res.json(result) // }) -// GET messages including word happy +// GET-route: show messages including word happy app.get("/messages/happy", async (req, res) => { try { let happyMessages = await Message.find({ message: { $regex: "happy" } }) @@ -127,7 +199,7 @@ app.get("/messages/happy", async (req, res) => { } }) -// GET a single message +// GET-route: show a single message according to id app.get("/messages/:id", async (req, res) => { try { const message = await Message.findById(req.params.id) @@ -144,8 +216,7 @@ app.get("/messages/:id", async (req, res) => { }) -// ROUTES (PATCH) -// send likes +// PATCH-route: send likes app.patch("/messages/:id/like", async (req, res) => { try { const message = await Message.findByIdAndUpdate( @@ -167,8 +238,7 @@ app.patch("/messages/:id/like", async (req, res) => { // TODO UPDATE a message -// ROUTES (POST) -// POST a message +// POST-route: post a message app.post('/messages', async (req, res) => { try { const message = new Message({ @@ -183,7 +253,7 @@ app.post('/messages', async (req, res) => { }) -// DELETE a message +// DELETE-route: delete a message app.delete("/messages/:id", async (req, res) => { try { const deletedMessage = await Message.findByIdAndDelete(req.params.id) From eb1d31bdf15b442bd15fa2b35ebf1887a6cffef9 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Wed, 4 Feb 2026 12:01:52 +0100 Subject: [PATCH 12/23] error handling login + sign up routes --- server.js | 108 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 29 deletions(-) diff --git a/server.js b/server.js index ad02e749..0cf0d3a0 100644 --- a/server.js +++ b/server.js @@ -38,13 +38,10 @@ const Message = mongoose.model('Message', messageSchema) // User schema const userSchema = new mongoose.Schema({ - name: { - type: String, - unique: true - }, email: { type: String, - unique: true + required: true, + unique: true, }, password: { type: String, @@ -62,13 +59,22 @@ const User = mongoose.model('User', userSchema) // Look up user based on the access token stored in the header const authenticateUser = async (req, res, next) => { - const user = await User.findOne({ accessToken: req.header('Authorization') }) - if (user){ - req.user = user - // next function allows the protected endpoint to continue execution - next() - } else { - res.status(401).json({loggedOut: true}) + try { + const user = await User.findOne({ + accessToken: req.header('Authorization').replace("Bearer ", ""), + }) + if (user){ + req.user = user + // next function allows the protected endpoint to continue execution + next() + } else { + res.status(401).json({ + message: "Authentication mossing or invalid", + loggedOut: true + }) + } + } catch (error) { + res.status(500).json({ message: "Internal server error", error: error.message }) } } @@ -101,6 +107,8 @@ if (process.env.RESET_DATABASE) { seedDatabase() } +// ROUTES + // Show all available endpoints app.get("/", (req, res) => { const endpoints = listEndpoints(app) @@ -112,19 +120,41 @@ app.get("/", (req, res) => { // POST-route: register user // user registers with name, email and password. We get an access token when they log in -app.post('/users', async (req, res) => { +app.post('/signup', async (req, res) => { try { - const { name, email, password } = req.body + const { email, password } = req.body + const existingUser = await User.findOne({ + email: email.toLowerCase() }) + + if (existingUser) { + return res.status(400).json({ + success: false, + message: "Could not create user" + }) + } + const salt = bcrypt.genSaltSync() - const user = new User({ name, email, password: bcrypt.hashSync(password, salt) }) - - user.save() - - res.status(201).json({ id:user._id, accessToken: user.accessToken }) - - } catch(error) { - res.status(400).json({ message: 'Could not create user', errors:error.errors }) + const hashedPassword = bcrypt.hashSync(password.salt) + const user = new User({ email, password: hashedPassword }) + + await user.save() + + res.status(201).json({ + success: true, + message: "User created successfully", + response: { + email: user.email, + id: user._id, + accessToken: user.accessToken, + }, + }) + } catch(error) { + res.status(400).json({ + success: false, + message: 'Could not create user', + response: error, + }) } }) @@ -135,13 +165,33 @@ app.get('/secrets', (req, res) => { }) // POST-route: log in (doesnt create the user, it finds one) -app.post('/sessions', async(req, res) => { - const user = await User.findOne({ email: req.body.email }) - - if (user && bcrypt.compareSync(req.body.password, user.password)) { - res.json({ userID: user._id , accessToken: user.accessToken}) - } else { - res.json({ notFound: true }) +app.post('/login', async (req, res) => { + try { + const user = await User.findOne({ email: req.body.email.toLowerCase() }) + + if (user && bcrypt.compareSync(req.body.password, user.password)) { + res.json({ + success: true, + message: "Logged in successfully", + response: { + email: user.email, + id: user._id, + accessToken: user.accessToken + }, + }) + } else { + res.status(401).json({ + success:false, + message: "Email or password invalid", + response: null, + }) + } + } catch (error) { + res.status(500).json({ + success: false, + message: "Something went wrong", + response: error + }) } }) From dda12e428587851ba3fa09a3fd1e44ca736348c1 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Wed, 4 Feb 2026 15:51:41 +0100 Subject: [PATCH 13/23] bug fix in signup route --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 0cf0d3a0..3208a975 100644 --- a/server.js +++ b/server.js @@ -135,7 +135,7 @@ app.post('/signup', async (req, res) => { } const salt = bcrypt.genSaltSync() - const hashedPassword = bcrypt.hashSync(password.salt) + const hashedPassword = bcrypt.hashSync(password, salt) const user = new User({ email, password: hashedPassword }) await user.save() From 4a996507aefb68d147eda341e5f26b0bd5ab65eb Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Wed, 4 Feb 2026 17:43:31 +0100 Subject: [PATCH 14/23] update login and signup routes to /users/login, /users/signup --- server.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/server.js b/server.js index 3208a975..6bbe813f 100644 --- a/server.js +++ b/server.js @@ -6,6 +6,7 @@ import mongoose from "mongoose" import "dotenv/config" import crypto from "crypto" import bcrypt from "bcrypt" +import 'dotenv/config' const mongoUrl = process.env.MONGO_URL || "mongodb://127.0.0.1/messages" mongoose.connect(mongoUrl) @@ -50,7 +51,7 @@ const userSchema = new mongoose.Schema({ accessToken: { type: String, default: () => crypto.randomBytes(128).toString('hex') - // default access token using crypto library + // random access token created using crypto library } }) @@ -120,7 +121,7 @@ app.get("/", (req, res) => { // POST-route: register user // user registers with name, email and password. We get an access token when they log in -app.post('/signup', async (req, res) => { +app.post('users/signup', async (req, res) => { try { const { email, password } = req.body @@ -130,7 +131,7 @@ app.post('/signup', async (req, res) => { if (existingUser) { return res.status(400).json({ success: false, - message: "Could not create user" + message: "User with this email already exists" }) } @@ -140,7 +141,7 @@ app.post('/signup', async (req, res) => { await user.save() - res.status(201).json({ + res.status(200).json({ success: true, message: "User created successfully", response: { @@ -165,11 +166,12 @@ app.get('/secrets', (req, res) => { }) // POST-route: log in (doesnt create the user, it finds one) -app.post('/login', async (req, res) => { +app.post('users/login', async (req, res) => { try { - const user = await User.findOne({ email: req.body.email.toLowerCase() }) + const { email, password } = req.body + const user = await User.findOne({ email: email.toLowerCase() }) - if (user && bcrypt.compareSync(req.body.password, user.password)) { + if (user && bcrypt.compareSync(password, user.password)) { res.json({ success: true, message: "Logged in successfully", From f55bf5de6e5c7994ad8923097554d52c3d933b71 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Wed, 4 Feb 2026 18:05:59 +0100 Subject: [PATCH 15/23] missing / in signup and login routes added --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 6bbe813f..99ae761c 100644 --- a/server.js +++ b/server.js @@ -121,7 +121,7 @@ app.get("/", (req, res) => { // POST-route: register user // user registers with name, email and password. We get an access token when they log in -app.post('users/signup', async (req, res) => { +app.post('/users/signup', async (req, res) => { try { const { email, password } = req.body @@ -166,7 +166,7 @@ app.get('/secrets', (req, res) => { }) // POST-route: log in (doesnt create the user, it finds one) -app.post('users/login', async (req, res) => { +app.post('/users/login', async (req, res) => { try { const { email, password } = req.body const user = await User.findOne({ email: email.toLowerCase() }) From 9276754442e8c764f1dabcd6b693adbd3f630d40 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Wed, 4 Feb 2026 19:12:46 +0100 Subject: [PATCH 16/23] authenticate user --- server.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/server.js b/server.js index 99ae761c..ab5c04a3 100644 --- a/server.js +++ b/server.js @@ -70,7 +70,7 @@ const authenticateUser = async (req, res, next) => { next() } else { res.status(401).json({ - message: "Authentication mossing or invalid", + message: "Authentication missing or invalid", loggedOut: true }) } @@ -159,11 +159,10 @@ app.post('/users/signup', async (req, res) => { } }) -// -app.get('/secrets', authenticateUser) -app.get('/secrets', (req, res) => { - res.json({secret: 'This is a super secret message'}) -}) +// app.get('/secrets', authenticateUser) +// app.get('/secrets', (req, res) => { +// res.json({secret: 'This is a super secret message'}) +// }) // POST-route: log in (doesnt create the user, it finds one) app.post('/users/login', async (req, res) => { @@ -291,7 +290,7 @@ app.patch("/messages/:id/like", async (req, res) => { // TODO UPDATE a message // POST-route: post a message -app.post('/messages', async (req, res) => { +app.post('/messages', authenticateUser, async (req, res) => { try { const message = new Message({ message: req.body.message, From 58aa0a42b98f12782cc15db2a6c68d7994444627 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Wed, 4 Feb 2026 20:04:10 +0100 Subject: [PATCH 17/23] non functional authentication commented out temporarily --- server.js | 71 ++++++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/server.js b/server.js index ab5c04a3..cccbf764 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,5 @@ import cors from "cors" import express, { application } from "express" -// import data from "./data.json" with { type: "json" } import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" import "dotenv/config" @@ -59,25 +58,25 @@ const userSchema = new mongoose.Schema({ const User = mongoose.model('User', userSchema) // Look up user based on the access token stored in the header -const authenticateUser = async (req, res, next) => { - try { - const user = await User.findOne({ - accessToken: req.header('Authorization').replace("Bearer ", ""), - }) - if (user){ - req.user = user - // next function allows the protected endpoint to continue execution - next() - } else { - res.status(401).json({ - message: "Authentication missing or invalid", - loggedOut: true - }) - } - } catch (error) { - res.status(500).json({ message: "Internal server error", error: error.message }) - } -} +// const authenticateUser = async (req, res, next) => { +// try { +// const user = await User.findOne({ +// accessToken: req.header('Authorization').replace("Bearer ", ""), +// }) +// if (user){ +// req.user = user +// // next function allows the protected endpoint to continue execution +// next() +// } else { +// res.status(401).json({ +// message: "Authentication missing or invalid", +// loggedOut: true +// }) +// } +// } catch (error) { +// res.status(500).json({ message: "Internal server error", error: error.message }) +// } +// } // Seed database if (process.env.RESET_DATABASE) { @@ -222,18 +221,6 @@ app.get("/messages/liked", async (req, res) => { } }) -// GET liked messages (query param) -// TODO Error handling -// app.get("/hearts", (req, res) => { -// let result = data - -// if (req.query.liked === "true") { -// result = result.filter(message => message.hearts > 0) -// } - -// res.json(result) -// }) - // GET-route: show messages including word happy app.get("/messages/happy", async (req, res) => { try { @@ -277,7 +264,7 @@ app.patch("/messages/:id/like", async (req, res) => { ) if (!message) { - return res.status(404).json({ error: "Messsage not found" }) + return res.status(404).json({ error: "Message not found" }) } res.json(message) @@ -323,8 +310,16 @@ app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) }) -// TODOS -// Frontend should be updated with the possibility to Update a thought. -// Problems with timestamps. not correct timeAgo showed -// Signing up (next week) -// signing in (next week) \ No newline at end of file + + +// GET liked messages (query param) +// TODO Error handling +// app.get("/hearts", (req, res) => { +// let result = data + +// if (req.query.liked === "true") { +// result = result.filter(message => message.hearts > 0) +// } + +// res.json(result) +// }) \ No newline at end of file From 0bb4d23893fec9136feef7a22edb13e31f2ac524 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Wed, 4 Feb 2026 20:09:21 +0100 Subject: [PATCH 18/23] user authentication temporarily commented out --- server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index cccbf764..ef1700e9 100644 --- a/server.js +++ b/server.js @@ -277,7 +277,8 @@ app.patch("/messages/:id/like", async (req, res) => { // TODO UPDATE a message // POST-route: post a message -app.post('/messages', authenticateUser, async (req, res) => { +// TODO: authenticateUser +app.post('/messages', async (req, res) => { try { const message = new Message({ message: req.body.message, From 8a46a55a83ce51e6386bfb794ebed7ebc4ded4f0 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Fri, 6 Feb 2026 10:37:47 +0100 Subject: [PATCH 19/23] authurization --- server.js | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/server.js b/server.js index ef1700e9..703a5ed5 100644 --- a/server.js +++ b/server.js @@ -1,11 +1,10 @@ import cors from "cors" -import express, { application } from "express" +import express from "express" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" import "dotenv/config" import crypto from "crypto" import bcrypt from "bcrypt" -import 'dotenv/config' const mongoUrl = process.env.MONGO_URL || "mongodb://127.0.0.1/messages" mongoose.connect(mongoUrl) @@ -50,7 +49,6 @@ const userSchema = new mongoose.Schema({ accessToken: { type: String, default: () => crypto.randomBytes(128).toString('hex') - // random access token created using crypto library } }) @@ -58,25 +56,25 @@ const userSchema = new mongoose.Schema({ const User = mongoose.model('User', userSchema) // Look up user based on the access token stored in the header -// const authenticateUser = async (req, res, next) => { -// try { -// const user = await User.findOne({ -// accessToken: req.header('Authorization').replace("Bearer ", ""), -// }) -// if (user){ -// req.user = user -// // next function allows the protected endpoint to continue execution -// next() -// } else { -// res.status(401).json({ -// message: "Authentication missing or invalid", -// loggedOut: true -// }) -// } -// } catch (error) { -// res.status(500).json({ message: "Internal server error", error: error.message }) -// } -// } +const authenticateUser = async (req, res, next) => { + try { + const user = await User.findOne({ + accessToken: req.header('Authorization').replace("Bearer ", ""), + }) + if (user){ + req.user = user + // next function allows the protected endpoint to continue execution + next() + } else { + res.status(401).json({ + message: "Authentication missing or invalid", + loggedOut: true + }) + } + } catch (error) { + res.status(500).json({ message: "Internal server error", error: error.message }) + } +} // Seed database if (process.env.RESET_DATABASE) { @@ -277,8 +275,7 @@ app.patch("/messages/:id/like", async (req, res) => { // TODO UPDATE a message // POST-route: post a message -// TODO: authenticateUser -app.post('/messages', async (req, res) => { +app.post('/messages', authenticateUser, async (req, res) => { try { const message = new Message({ message: req.body.message, From 4f78c51faba3eebc6a708cd7933a954f79867295 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Fri, 6 Feb 2026 10:54:17 +0100 Subject: [PATCH 20/23] seedDatabase removed --- server.js | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/server.js b/server.js index 703a5ed5..33c79afc 100644 --- a/server.js +++ b/server.js @@ -76,35 +76,6 @@ const authenticateUser = async (req, res, next) => { } } -// Seed database -if (process.env.RESET_DATABASE) { - - const seedDatabase = async () => { - // Avoid content in api from being duplicated on refresh - await Message.deleteMany() - - const testMessage = new Message({ - message: 'Backend is fun!', - hearts: 5 - }) - await testMessage.save() - - const testMessageTwo = new Message({ - message: 'I get happy when it is working!', - hearts: 1 - }) - await testMessageTwo.save() - - const testMessageThree = new Message({ - message: 'Snow today, yay!!', - hearts: 0 - }) - await testMessageThree.save() - - } - seedDatabase() -} - // ROUTES // Show all available endpoints From af82da1a736a0dc7562de5443aa738fa020ad6d9 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Fri, 6 Feb 2026 14:41:59 +0100 Subject: [PATCH 21/23] route update and delete message, authenticated --- server.js | 62 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/server.js b/server.js index 33c79afc..f5b9a010 100644 --- a/server.js +++ b/server.js @@ -7,6 +7,7 @@ import crypto from "crypto" import bcrypt from "bcrypt" const mongoUrl = process.env.MONGO_URL || "mongodb://127.0.0.1/messages" +// move mongoose.connect(mongoUrl) const port = process.env.PORT || 8080 @@ -29,6 +30,11 @@ const messageSchema = new mongoose.Schema({ createdAt: { type: Date, default: Date.now + }, + userId: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: true } }) @@ -55,7 +61,6 @@ const userSchema = new mongoose.Schema({ // User model const User = mongoose.model('User', userSchema) -// Look up user based on the access token stored in the header const authenticateUser = async (req, res, next) => { try { const user = await User.findOne({ @@ -63,7 +68,6 @@ const authenticateUser = async (req, res, next) => { }) if (user){ req.user = user - // next function allows the protected endpoint to continue execution next() } else { res.status(401).json({ @@ -127,11 +131,6 @@ app.post('/users/signup', async (req, res) => { } }) -// app.get('/secrets', authenticateUser) -// app.get('/secrets', (req, res) => { -// res.json({secret: 'This is a super secret message'}) -// }) - // POST-route: log in (doesnt create the user, it finds one) app.post('/users/login', async (req, res) => { try { @@ -243,14 +242,35 @@ app.patch("/messages/:id/like", async (req, res) => { } }) -// TODO UPDATE a message +// UPDATE a message +app.patch('/messages/:id', authenticateUser, async (req, res) => { + try { + const message = await Message.findById(req.params.id) + + if (!message) { + return res.status(404).json({ error: "Message not found" }) + } + + if (message.userId.toString() !== req.user._id.toString()) { + return res.status(403).json ({ error: "You can only edit your own messages" }) + } + + message.message = req.body.message || message.message + await message.save() + + res.json(message) + } catch (error) { + res.status(400).json({ error: "Invalid message-id or request" }) + } +}) // POST-route: post a message app.post('/messages', authenticateUser, async (req, res) => { try { const message = new Message({ message: req.body.message, - hearts: req.body.hearts + hearts: req.body.hearts, + userId: req.user._id }) await message.save() res.status(200).json(message) @@ -261,14 +281,21 @@ app.post('/messages', authenticateUser, async (req, res) => { }) // DELETE-route: delete a message -app.delete("/messages/:id", async (req, res) => { +app.delete("/messages/:id", authenticateUser, async (req, res) => { try { const deletedMessage = await Message.findByIdAndDelete(req.params.id) if (!deletedMessage) { return res.status(404).json({ error: "Message not found" }) } - res.status(200).json(deletedMessage) + + if (deletedMessage.userId.toString() !== req.user._id.toString()) { + return res.status(403).json({ error: "You can only delete your own message" }) + } + + await deletedMessage.deleteOne() + + res.status(200).json({ success: true }) } catch (error) { res.status(400).json({ error: "Invalid message id" }) } @@ -279,16 +306,3 @@ app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) }) - - -// GET liked messages (query param) -// TODO Error handling -// app.get("/hearts", (req, res) => { -// let result = data - -// if (req.query.liked === "true") { -// result = result.filter(message => message.hearts > 0) -// } - -// res.json(result) -// }) \ No newline at end of file From 49485db638c47d1f00c97aa6ea2f42f211fb1cdb Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Sun, 8 Feb 2026 17:01:47 +0100 Subject: [PATCH 22/23] readme --- README.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 0f9f073d..a432d96b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,4 @@ # Project API -This project includes the packages and babel setup for an express server, and is just meant to make things a little simpler to get up and running with. - -## Getting started - -Install dependencies with `npm install`, then start the server by running `npm run dev` - -## View it live - -Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. +API for posting, editing and liking happy thoughts. Check it out live here: +https://happy-thoughts-nicolina.netlify.app/ From 473f1cf011b4bcaa59416eba16fa8b2e53d51122 Mon Sep 17 00:00:00 2001 From: nicolinabl Date: Sun, 8 Feb 2026 17:04:47 +0100 Subject: [PATCH 23/23] readme render link --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a432d96b..804cd469 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # Project API -API for posting, editing and liking happy thoughts. Check it out live here: +https://happy-thoughts-api-nicolina.onrender.com + +API for posting, editing and liking happy thoughts. Check it out connected to a frontend project here: https://happy-thoughts-nicolina.netlify.app/