- Description
- Installation Instructions
- Usage
- Technologies Used
- Dependencies and Credits
- Project Structure
This is the backend for my social media website project that I built for The Odin Project. It is a RESTful API that uses JSON web tokens for authentication and authorization; it can be used per the endpoint instructions below. Please note that to use it yourself you'll need to clone this repo and update the allowList in app.js.
-
Clone or fork this repo
-
cd into the project root directory (where the README.md file is located)
-
Run the following in your terminal (I've found that separating them into smaller install blocks helps when your internet is slower)
-
npm init -y npm install
-
-
Create a .env file
-
NODE_ENV=development TEST_DATABASE_URL="your_local_test_database_url" DATABASE_URL="your_local_database_url" SECRET_KEY="your_secret_key"
-
-
npm run dev
-
After making updates to ./src/queries.ts you'll want to run this to recompile queries.js
-
npx tsc
-
-
Be sure to test the API regularly
-
npm run test
-
- API Base URL
- Auth Header Note
- Most routes require a JSON Web Token
- Correct format:
- Authorization: Bearer token <token>
- In this documentation, "authHeader" refers to this header
- Correct format:
- Most routes require a JSON Web Token
- Routes & Successful Responses
- Database Wakeup Route
- /
- GET
- Description: Wakes up the database by requesting a count of users
- Requires: nothing
- Success: 200 OK
- Response: { message: "Database is awake and ready for coffee!" }
- GET
- /
- User Routes
- /user
- POST
- Description: Create user account, this is the signup route
- Requires: { email, password, confirmPassword }
- Success: 200 OK
- Response: { id, email }
- POST
- /user/login
- POST
- Description: Create user login info, this is the login route
- Requires: { email, password }
- Success: 200 OK
- Response: { id, email, token }
- POST
- /user/:userId
- GET
- Description: Read user's email address
- Requires: authHeader (must be userId owner)
- Success: 200 OK
- Response: { email }
- PUT
- Description: Update user account
- Requires: authHeader (must be userId owner), { currentPassword, newEmail, newPassword, newPasswordConfirm }
- Success: 200 OK
- Response: { id, email, token}
- DELETE
- Description: Delete user account
- Requires: authHeader (must be userId owner), { password }
- Success: 200 OK
- Response: { message: "Account successfully deleted." }
- GET
- /user
- Profile Routes
- /profile
- POST
- Description: Create a profile for a user
- Requires: authHeader (just to verify logged in), { name, about (can be blank), website (can be blank), avatarUrl (can be blank) }
- Success: 200 OK
- Response: { id, userId, name, website, about, avatarUrl }
- GET
- Description: Read user's profile using the provided authHeader
- Requires: authHeader (used for authentication and to identify the user)
- Success: 200 OK
- Response: { id, userId, name, about, website, avatarUrl, posts: [ ... ] }
- POST
- /profile/anon
- GET
- Description: Creates and returns an anonymous profile and user object so users can browse the site without signing in
- Requires: N/A
- Success: 200 OK
- Response: { user: { id, email, token }, profile: { id, name, about, website, avatarUrl, userId } }
- GET
- /profile/list
- POST
- Description: Read list of profiles in alphabetical order by name, if the optional stringToMatch is included then only profiles whose names match this partial will be returned
- Requires: authHeader (just to verify logged in), { stringToMatch } (optional)
- Success: 200 OK
- Response: [ { id, userId, name, about, website, avatarUrl } ]
- POST
- /profile/:profileId
- GET
- Description: Read a profile, similar to visiting a profile page on Facebook
- Requires: authHeader (just to verify logged in)
- Success: 200 OK
- Response: { id, userId, name, about, website, avatarUrl, posts: [ ... ] }
- PUT
- Description: Update a profile, can change name, about, and/or website
- Requires: authHeader (must be profileId owner), { id (profileId), name, website (can be blank), avatarUrl (can be blank), about (can be blank) }
- Success: 200 OK
- Response: { id, userId, name, about, website, posts, avatarUrl }
- DELETE
- Description: Delete a profile
- Requires: authHeader (must be profileId owner)
- Success: 200 OK
- Response: { id, name, about, website, userId }
- GET
- /profile
- Post Routes
- /post/:profileId
- POST
- Description: Create a post from a profile, must be the user's own profile
- Requires: authHeader (must be profileId owner), { text }
- Success: 200 OK
- Response: { id, createdAt, text, profileId, Profile: { name, id } }
- POST
- /post/single/:postId
- GET
- Description: Read a specific post to see more detailed information
- Requires: authHeader (just to verify logged in)
- Success: 200 OK
- Response: { id, createdAt, text, profileId, Profile: { name, id }, _count: { comments, likes }, likes: [ { id } ] }
- GET
- /post/recent/:start
- GET
- Description: Read the 10 most recent posts from all profiles, starting at the specified number
- Requires: authHeader (just to verify logged in)
- Success: 200 OK
- Response: [ { id, createdAt, text, profileId, Profile: { name, id }, _count: { comments, likes }, likes: [ { id } ] } ]
- Sample
- Send a GET request to /post/recent/11 with a valid authHeader
- Response: [ { 11th most recent post }, ..., { 20th most recent post } ]
- Notes:
- Lowest start number available is 1
- /post/recent/1 will return the 10 most recent posts
- Lowest start number available is 1
- PUT
- Description: Update a post
- Requires: authHeader (must be postId owner), { text }
- Success: 200 OK
- Response: { id, createdAt, text, profileId, Profile: { name, id } }
- DELETE
- Description: Delete a post
- Requires: authHeader (must be postId owner)
- Success: 200 OK
- Response: { id, createdAt, text, profileId, Profile: { name, id } }
- GET
- /post/:profileId
- Comment Routes
- /comment/post/:postId/from/:profileId
- POST
- Description: Create a comment on a post
- Requires: authHeader (just to verify logged in), { text }
- Success: 200 OK
- Response: { id, text, profileId, postId, commentId: null, Profile: { name, id }, _count: { likes, replies } }
- POST
- /comment/post/:postId
- GET
- Description: Read comments on a post
- Requires: authHeader (just to verify logged in)
- Success: 200 OK
- Response: [ { id, text, profileId, postId, commentId: null, Profile: { name, id }, _count: { likes, replies }, likes: [ { id } ] } ]
- GET
- /comment/reply/:commentId/from/:profileId
- POST
- Description: Create a reply to another comment
- Requires: authHeader (just to verify logged in), { profileId, text }
- Success: 200 OK
- Response: { id, text, profileId, postId: null, commentId, Profile: { name, id }, _count: { likes, replies } }
- POST
- /comment/reply/:commentId
- GET
- Description: Read comment replies
- Requires: authHeader (just to verify logged in)
- Success: 200 OK
- Response: [ { id, text, profileId, postId: null, commentId, Profile: { name, id }, _count: { likes, replies }, likes: [ { id } ] } ]
- GET
- /comment/:commentId
- PUT
- Description: Update a comment
- Requires: authHeader (must be commentId owner), { text }
- Success: 200 OK
- Response: { id, text, profileId, postId, commentId, Profile: { name, id }, _count: { likes, replies } }
- DELETE
- Description: Delete a comment, currently can only be done by the comment owner
- Requires: authHeader (must be commentId owner)
- Success: 200 OK
- Response: { id, text, profileId, postId, commentId }
- PUT
- /comment/post/:postId/from/:profileId
- Follow Routes
- /follow/:followingId/from/:followerId
- POST
- Description: Create a new follow, followerId user is following followingId user
- Requires: authHeader (must be followerId owner)
- Success: 200 OK
- Response: { id, updatedAt, accepted, followerId, followingId }
- POST
- /follow/profile/followers/:profileId
- GET
- Description: Read list of profiles that are following profileId
- Requires: authHeader (just to verify logged in)
- Success: 200 OK
- Response: [ { follower: { id, name } } ]
- GET
- /follow/profile/following/:profileId
- GET
- Description: Read list of profiles that profileId is following
- Requires: authHeader (just to verify logged in)
- Success: 200 OK
- Response: [ { following: { id, name } } ]
- GET
- /follow/:followId
- PUT
- Description: Update a follow
- Note: This is currently not in use but here in case we want to allow privacy settings of accepting followers before allowing a follow.
- Requires: authHeader (must be follow's followingId owner), { accepted: true }
- Success: 200 OK
- Response: { success: true }
- Description: Update a follow
- PUT
- /follow/:deleteFollowId
- DELETE
- Description: Delete a follow
- Requires: authHeader (must be owner of either followingId or followerId)
- Success: 200 OK
- Response: { success: true }
- DELETE
- /follow/:followingId/from/:followerId
- Like Routes
- /like/comment/:likeCommentId/from/:profileId
- POST
- Description: Create a like on a comment
- Requires: authHeader (must be profileId owner)
- Success: 200 OK
- Response: { id, profileId, commentId, postId: null }
- POST
- /like/post/:likePostId/from/:profileId
- POST
- Description: Create a like on a post
- Requires: authHeader (must be profileId owner)
- Success: 200 OK
- Response: { id, profileId, postId, commentId: null }
- POST
- /like/:likeId
- DELETE
- Description: Delete a like
- Requires: authHeader (must be likeId owner)
- Success: 200 OK
- Response: { id, profileId, postId, commentId }
- DELETE
- /like/comment/:likeCommentId/from/:profileId
- Database Wakeup Route
- Errors
- Response: { errors: [ { message }, ] }
- Example: { message: "The param likeCommentId must be a number." }
- HTTP Codes
- 400: Bad Request, a provided piece of information was incorrect
- 401: Unauthorized, the auth header is missing or corrupted
- 403: Forbidden, not able to perform the selected action from this account
- 404: Not Found, route or database resource not found
- 409: Conflict, cannot create a duplicate item in the database
- 500: Internal Server Error, there was an error with the server, try again
- Response: { errors: [ { message }, ] }
- Returns JSON objects and 200 for good requests and accurate status codes with messages for bad requests
- Incorporates CORS
- Is a RESTful API
- Was built using test driven development (TDD) using Jest and supertest
- @prisma/extension-accelerate
- @prisma/client
- @types/node
- bcryptjs
- cors
- dotenv
- express-validator
- jsonwebtoken
- pg
- supertest
- tsx
- uuid
├──controllers/
├──commentController.js
├──followController.js
├──internalFunctions.js
├──likeController.js
├──postController.js
├──profileController.js
├──securityController.js
├──userController.js
└──wakeupController.js
├──db/
└──queries.js # Automatically placed here after running `npx tsc`
├──generated/
├──prisma/ # Prisma generated models
├──prisma/
├──migrations/
└──schema.prisma
├──routes/
└──router.js
├──src/
└──queries.ts # Database queries
├──test/
├──comment.test.js
├──follow.test.js
├──internalTestFunctions.js
├──like.test.js
├──post.test.js
├──profile.test.js
└──user.test.js
├──.gitignore
├──LICENSE
├──README.md
├──app.js
├──notes.txt
├──package-lock.json
├──package.json
└──tsconfig.json