Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project Happy Thoughts API #507

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
cd2762c
Initial commit
joheri1 Dec 17, 2024
3296195
Add a console log message for when starting the server. Add a test ro…
joheri1 Dec 18, 2024
fa87bdc
Add some starter code snippets, not tested yet
joheri1 Dec 18, 2024
036b5f1
Add starter code for /thoughts/:thoughtId/like
joheri1 Dec 18, 2024
caa6b36
Add a comment to /thoughts/:thoughtId/like
joheri1 Dec 18, 2024
1dfb6b1
Add a new component for the MongooseModel. Defines the paths, and set…
joheri1 Dec 18, 2024
25b33a4
Add a validation message to the 'message' in the mongoose schema
joheri1 Dec 18, 2024
cfc0a09
Import the Thought model to server.js
joheri1 Dec 18, 2024
6f2deba
Fix: Correct typo in name of the Schema
joheri1 Dec 18, 2024
fb3a85f
Move MongooseModel.js to folder models
joheri1 Dec 18, 2024
4faed4f
Import mongoose to the MonGooseModel. Add comments at the top of the …
joheri1 Dec 18, 2024
3d62517
Fix: get the naming right for the import of the mongoose model to the…
joheri1 Dec 18, 2024
9514d3a
Changed name on component to camelCase
joheri1 Dec 18, 2024
36277d1
Move the endpoints for happy thoughts to file routes
joheri1 Dec 18, 2024
519bd70
Move the HappyThought routes to routes, import the routes to server.j…
joheri1 Dec 18, 2024
f66765d
Update server.js with shorter comments
joheri1 Dec 18, 2024
e059d29
Add try catch error handling to the endpoint for POST a like
joheri1 Dec 18, 2024
af75f8f
SAve any unsaved changes
joheri1 Dec 18, 2024
50dde9a
Fix routing setup for HappyThoughts endpoints
joheri1 Dec 18, 2024
d4b3027
Initial commit for deployment
joheri1 Dec 19, 2024
225483f
Add documentation endpoint
joheri1 Dec 19, 2024
bc9620a
Remove useUnifiedTopology and useNewUrlParser to make Render complain…
joheri1 Dec 19, 2024
aad0aaa
Fix: Change response status 201 to newThought
joheri1 Dec 20, 2024
59a8c0a
Update README with information about the project
joheri1 Dec 20, 2024
5056057
Save any unsaved changes in the README file
joheri1 Dec 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
# Project Happy Thoughts API

Replace this readme with your own information about your project.
This is the backend API for the Happy Thoughts project, used to store and manage "happy thoughts" submitted by users. It is built with Node.js, Express, and MongoDB, hosted on Render.

Start by briefly describing the assignment in a sentence or two. Keep it short and to the point.
### Features
- **GET /thoughts**: Fetches the 20 most recent happy thoughts, sorted by creation date.
- **POST /thoughts**: Allows users to submit a new happy thought.
- **POST /thoughts/:thoughtId/like**: Adds a like (heart) to a specific thought by ID.

### Deployed Backend
- **Base URL**: [https://project-happy-thoughts-api-gns9.onrender.com](https://project-happy-thoughts-api-gns9.onrender.com)

### Frontend Integration
This backend is connected to the [Happy Thoughts Frontend](https://github.com/joheri1/project-happy-thoughts-vite), a React application for displaying and interacting with the happy thoughts.

- **Backend Repository**: [Happy Thoughts API](https://github.com/joheri1/project-happy-thoughts-api)
- **Backend URL**: [https://project-happy-thoughts-api-gns9.onrender.com](https://project-happy-thoughts-api-gns9.onrender.com)

## The problem
### Connecting the Frontend, Backend, and Database
When I started integrating my React frontend, Node.js backend, and MongoDB Atlas database, I faced several issues. Here's a few of them:
- My MongoDB Atlas user seemed to have the correct password, but for some non-obvious reason, the connection still failed. I resolved this by generating a new password for the user and updating the `MONGO_URL` in Render’s environment variables.
- During development, I got an error saying that `savedThought` was not defined in the `POST /thoughts` endpoint. This was caused by a typo, and I fixed it by correctly referencing the newly created thought object as `newThought`.
- The error 'Operation 'happythoughts.find()' buffering timed out' because the database wasn’t properly configured in MongoDB Atlas. This was resolved by adding 0.0.0.0/0 in Network Access in MongoDB Atlas to allow connections from any IP address (necessary for Render).

I used Postman a lot to test my API endpoints and MongoDB Compass to confirm that data was being stored in the database. I uploaded a json with a few "happy thoughts" to make the testing easier, while debugging issues with my initial POST request.

Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next?
I also sketched a simple flow on paper to map out how each part of the application interacts, such as how MONGO_URL is used in the backend to connect to MongoDB Atlas, and that BASE_URL links the frontend to the backend. This really helped when debugging.

## 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.
- **Frontend URL**: [Project Happy Thoughts](https://project-happy-thoughts-x.netlify.app/)
- **Backend URL**: [https://project-happy-thoughts-api-gns9.onrender.com](https://project-happy-thoughts-api-gns9.onrender.com)
26 changes: 26 additions & 0 deletions models/MongooseModel
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unused code

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Purpose: Define the Mongoose model for the HappyThoughts collection in the MongoDB database
// Dependencies: mongoose

import mongoose from 'mongoose';

const happyThoughtSchema = new mongoose.Schema({
message: {
type: String,
required: [true,'A message is required'],
minlength: [5, 'Message must be at least 5 characters'],
maxlength: [140, 'Message must be at most 140 characters']
},
hearts: {
type: Number,
default: 0
},
createdAt: {
type: Date,
default: () => new Date(),
immutable: true
}
});

const HappyThought = mongoose.model('HappyThought', happyThoughtSchema);

export default HappyThought;
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
"@babel/preset-env": "^7.16.11",
"cors": "^2.8.5",
"express": "^4.17.3",
"express-list-endpoints": "^7.1.1",
"mongodb": "^6.12.0",
"mongoose": "^8.0.0",
"nodemon": "^3.0.1"
"nodemon": "^3.0.1",
"dotenv": "^16.0.0"
}
}
}
72 changes: 72 additions & 0 deletions routes/happyThought.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/** This file contains all the routes */

import HappyThought from "../models/MongooseModel";
import express from "express";
import expressListEndpoints from "express-list-endpoints";

const app = express.Router();

/**
* Documentation for the API.
*/
app.get("/", (request, response) => {
const endpoints = expressListEndpoints(app); // Get all endpoints
response.json({
message: "Welcome to the Happy Thoughts API 🌟",
endpoints: endpoints,
});
});

/**
* Endpoint to GET 20 thoughts.
*/
app.get("/thoughts", async (request, response) => {
try {
const thoughts = await HappyThought.find()
.sort({ createdAt: "desc" })
.limit(20);
response.status(200).json(thoughts);
} catch (error) {
response.status(400).json({ message: "Could not get thoughts", error: error.message });
}
});

/**
* Endpoint to POST a thought.
*/
app.post("/thoughts", async (request, response) => {
const { message } = request.body;

try {
const newThought = await HappyThought.create({ message });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

response.status(201).json(newThought);
} catch (error) {
response.status(400).json({ message: "Could not save thought to the Database", error: error.message });
}
});

/**
* Endpoint to POST a like.
*/

app.post("/thoughts/:thoughtId/like", async (request, response) => {
const { thoughtId } = request.params;

try {
const updatedThought = await HappyThought.findByIdAndUpdate(thoughtId,
{ $inc: { hearts: 1 } }, // Add 1 heart/like to the thought
{ new: true } // Return the updated thought
Comment on lines +56 to +58
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

);

if (!updatedThought) {
return response.status(404).json({ message: "Thought not found" });
}

response.status(200).json(updatedThought);

} catch (error) {
response.status(400).json({ message: "Could not like thought", error: error.message });
}
});

export default app;
37 changes: 27 additions & 10 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
import cors from "cors";
import express from "express";
import mongoose from "mongoose";
import routes from "./routes/happyThought";

import dotenv from "dotenv";
dotenv.config();

// Connects to the Mongo database
const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-happy-thoughts-api";

console.log("MongoDB URL:", mongoUrl);

mongoose.connect(mongoUrl)
.then(() => console.log("Connected to the database 🚀"))
.catch((error) => console.error("Could not connect to the database", error));

const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo";
mongoose.connect(mongoUrl);
mongoose.Promise = Promise;

// 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
// Defines the port the app will run on.
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());

// Start defining your routes here
app.get("/", (req, res) => {
res.send("Hello Technigo!");
//Use routes fot HappyThoughts
app.use("/", routes);

/**
* Endpoint for testing the server.
*/
app.get("/test", (request, response) => {
response.send("The server is up, so come share your happy thoughts with us! 🌟");
console.log("The server is up, so come share your happy thoughts with us! 🌟");
});

// Start the server
/**
* Start the server.
*/
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
console.log(`Server is spreading joy on http://localhost:${port} 🎉`);
});