LinkUp is a backend API for a social media platform built by Chinwendu Enyinna using a couple JavaScript-based server side technologies. This API follows the REST architectural design pattern.
The following are the requirements I implemented in this project π:
-
Users should be able to sign up(register) and sign in into their account
-
Users should be able to follow and unfollow other users on the platform
-
Users should be able to get all followers and followings
-
Users should be able to delete their account
-
For the Post functionality, users should be able to:
- Share a post
- Like and unlike a post
- Upload image to a post
- Comment on a post
- Like a comment to a post
- Repost a shared post
- Edit and update a post
- Get timeline posts
- Delete a post
-
A post is initally in a draft state when created. To share a post, user should update the state to 'shared'
git clone https://github.com/wendeee/socialmediaAPI.git
npm install
Update .env with example.env
- Sign up on Cloudinary to get API_KEY for free and other details needed in your .env file
- To implement forgot password and reset password functionality, I used Nodemailer and mail trap to send reset token to user's email.
Sign up on mailtrap for free to get the following detailsπ:- EMAIL_USERNAME
- EMAIL_PASSWORD
- EMAIL_HOST
- EMAIL_PORT
npm run start:dev
field | data_type | constraints |
---|---|---|
firstname | string | required |
lastname | string | required |
username | string | required |
string | required | |
password | string | required |
passwordConfirm | string | required |
followers | objectId | referenced |
followings | objectId | referenced |
posts | objectId | referenced |
joinedOn | Date | added dynamically |
field | data_type | constraints |
---|---|---|
post | string | required |
author | objectId | referenced |
state | string | required, enum: ['draft', 'shared'] |
image | string | optional |
likes | Number | added dynamically |
numOfRepost | Number | added dynamically |
comments | objectId | referenced |
timestamps | Date | required |
field | data_type | constraints |
---|---|---|
_user | objectId | referenced |
_post | objectId | referenced |
timestamps | Date | required |
field | data_type | constraints |
---|---|---|
_user | objectId | referenced |
_post | objectId | referenced |
timestamps | Date | required |
field | data_type | constraints |
---|---|---|
_user | objectId | referenced |
_post | objectId | referenced |
comment | string | required |
likes | Number | dynamically added |
timestamps | Date | required |
field | data_type | constraints |
---|---|---|
_user | objectId | referenced |
_comment | objectId | referenced |
timestamps | Date | required |
-
Route: /api/auth/signup
-
method: POST
-
π: Body
{
"firstname":"Jackson",
"lastname":"Ben",
"username":"jacksonben",
"email": "[email protected]",
"password": "jackson12345",
"passwordConfirm": "jackson12345"
}
π: Response
{
"status": "success",
"token": {token},
"data": {
"user": {
"firstname": "Jackson",
"lastname": "Ben",
"username": "jacksonben",
"email": "[email protected]",
"followers": [],
"followings": [],
"joinedOn": "2022-12-09T22:05:06.564Z",
"posts": [],
"_id": "6393b13a97e46808bb9c9a3e",
"createdAt": "2022-12-09T22:05:46.826Z",
"updatedAt": "2022-12-09T22:05:46.826Z",
"__v": 0
}
}
}
Route: /api/auth/login method: POST
π: Body
{
"email": "[email protected]",
"password": "jackson12345"
}
π: Response
{
"status": "success",
"token": {token}
}
- Route: /api/auth/forgotPassword
- Method: POST
π: Body
{
"email": "[email protected]"
}
π: Response
{
"status": "success",
"message": "A reset token has been sent to your email"
}
- Route: /api/auth/resetPassword/:token
- Method: PATCH
π: Body
{
"password": "jacksonnewpassword",
"passwordConfirm": "jacksonnewpassword"
}
π: Response
{
"status": "success",
"token": {token}
}
- Route: /api/v1/users/:toFollowId/follow
- Method: PATCH
- Header
- Authorization: Bearer {token}
π :Response
{
"status": "success",
"response": "following johndoe!"
}
- Route: /api/v1/users/:toUnfollowId/unfollow
- Method: PATCH
- Header
- Authorization: Bearer {token}
π :Response
{
"status": "success",
"message": "johndoe unfollowed successfully!"
}
- Route: /api/v1/users/followings
- Method: GET
- Header
- Authorization: Bearer {token}
π :Response
{
"numOfFollowings": 1,
"followings": [
{
"firstname": "John",
"lastname": "Doe"
}
]
}
- Route: /api/v1/posts
- Method: POST
- Header
- Authorization: Bearer {token}
π: Body
{
"post": "lorem iiiggg hhhaaa hhdddsn jkljskvhl vzbvzklvjhzv vn zhbvlVz n"
}
π: Response
{
"success": true,
"data": {
"author": "6393b13a97e46808bb9c9a3e",
"post": "lorem iiiggg hhhaaa hhdddsn jkljskvhl vzbvzklvjhzv vn zhbvlVz n",
"state": "draft",
"image": "",
"likes": 0,
"numOfReposts": 0,
"comments": [],
"_id": "6393b41597e46808bb9c9a42",
"createdAt": "2022-12-09T22:17:57.764Z",
"updatedAt": "2022-12-09T22:17:57.764Z",
"__v": 0
}
}
//A post with an uploaded image
{
"success": true,
"data": {
"author": "63910022e9cd10c8589fdda9",
"post": "A post with an image",
"state": "draft",
"image": "https://res.cloudinary.com/dwsbmjhzd/image/upload/v1670604617/wgqddvyzvbd73nnuovvc.jpg",
"likes": 0,
"numOfReposts": 0,
"comments": [],
"_id": "6393e519d3208257faba9a44",
"createdAt": "2022-12-10T01:47:06.016Z",
"updatedAt": "2022-12-10T01:47:06.016Z",
"__v": 0
}
}
- Route: /api/v1/posts/:postId
- Method: PUT
- Header
- Authorization: Bearer {token}
π: Body
{
"state": "shared"
}
π: Response
{
"status": "success",
"data": {
"_id": "6393b41597e46808bb9c9a42",
"author": "6393b13a97e46808bb9c9a3e",
"post": "lorem iiiggg hhhaaa hhdddsn jkljskvhl vzbvzklvjhzv vn zhbvlVz n",
"state": "shared",
"image": "",
"likes": 0,
"numOfReposts": 0,
"comments": [],
"createdAt": "2022-12-09T22:17:57.764Z",
"updatedAt": "2022-12-09T22:30:17.243Z",
"__v": 0
}
}
- Route: /api/v1/posts/:postId
- Method: PATCH
- Header
- Authorization: Bearer {token}
π: Body
{
"post": "Lorem ipsum updated"
}
π: Response
{
"status": "success",
"data": {
"_id": "6393c921fe99aa758d819ac1",
"author": "6393c1bcfe99aa758d819aa4",
"post": "Lorem ipsum updated",
"state": "shared",
"image": "",
"likes": 0,
"numOfReposts": 0,
"comments": [],
"createdAt": "2022-12-09T23:47:45.581Z",
"updatedAt": "2022-12-09T23:50:08.612Z",
"__v": 0
}
}
- Route: /api/v1/posts/:postId/like
- Method: PATCH
- Header
- Authorization: Bearer {token}
π: Response
{
"status": "success",
"message": "You liked this post",
"post": {
"_id": "6393b41597e46808bb9c9a42",
"author": "6393b13a97e46808bb9c9a3e",
"post": "lorem iiiggg hhhaaa hhdddsn jkljskvhl vzbvzklvjhzv vn zhbvlVz n",
"state": "shared",
"image": "",
"likes": 1,
"numOfReposts": 0,
"comments": [],
"createdAt": "2022-12-09T22:17:57.764Z",
"updatedAt": "2022-12-09T22:30:17.243Z",
"__v": 0
}
}
- Route: /api/v1/posts/:postId/like
- Method: PATCH
- Header
- Authorization: Bearer {token}
π: Response
{
"message": "You unliked this post",
"postToLike": {
"_id": "6393b41597e46808bb9c9a42",
"author": "6393b13a97e46808bb9c9a3e",
"post": "lorem iiiggg hhhaaa hhdddsn jkljskvhl vzbvzklvjhzv vn zhbvlVz n",
"state": "shared",
"image": "",
"likes": 0,
"numOfReposts": 1,
"comments": [],
"createdAt": "2022-12-09T22:17:57.764Z",
"updatedAt": "2022-12-09T22:39:16.038Z",
"__v": 0
}
}
- Route: /api/v1/posts/:postId/repost
- Method: POST
- Header
- Authorization: Bearer {token}
π: Response
{
"status": "success",
"message": "You reposted this post",
"post": {
"_id": "6393b41597e46808bb9c9a42",
"author": "6393b13a97e46808bb9c9a3e",
"post": "lorem iiiggg hhhaaa hhdddsn jkljskvhl vzbvzklvjhzv vn zhbvlVz n",
"state": "shared",
"image": "",
"likes": 0,
"numOfReposts": 1,
"comments": [],
"createdAt": "2022-12-09T22:17:57.764Z",
"updatedAt": "2022-12-09T22:39:16.038Z",
"__v": 0
}
}
- Route: /api/v1/posts/:postId/comment
- Method: POST
- Header
- Authorization: Bearer {token}
π: Body
{
"comment": "Great write up!"
}
π: Response
{
"status": "success",
"message": "You commented on this post",
"data": {
"comment": {
"_user": "6393b13a97e46808bb9c9a3e",
"comment": "Great write up!",
"_post": "6393b41597e46808bb9c9a42",
"likes": 0,
"_id": "6393ba5197e46808bb9c9a61",
"createdAt": "2022-12-09T22:44:33.937Z",
"updatedAt": "2022-12-09T22:44:33.937Z",
"__v": 0
}
}
}
- Route: /api/v1/posts/:postId/:commentId/like
- Method: PATCH
- Header
- Authorization: Bearer {token}
π: Response
{
"status": "success",
"message": "You liked this comment",
"data": {
"comment": {
"_id": "6393ba5197e46808bb9c9a61",
"_user": "6393b13a97e46808bb9c9a3e",
"comment": "Great write up!",
"_post": "6393b41597e46808bb9c9a42",
"likes": 1,
"createdAt": "2022-12-09T22:44:33.937Z",
"updatedAt": "2022-12-09T22:44:33.937Z",
"__v": 0
}
}
}
- Route: /api/v1/posts/:postId/
- Method: DELETE
- Header
- Authorization: Bearer {token}
π: Response
{
"status": "success",
"message": "post deleted sucessfully"
}
- How to model data
- Mongoose Database Schema Design
- User authentication authorization with JWT
- Database Query
- User Authentication
- How to craft a presentable README.md
- How to upload image using multer and cloudinary
- How to implement forgot password and reset password using Nodemailer
-
Twitter - @_ChinwenduE
-
Email - [email protected]
Project Link: https://github.com/wendeee/socialmediaAPI