This is a social media REST API written in Java and powered by Spring Boot. It provides endpoints such as creating a new post, liking a post, following a user, etc. This API acts as a bridge between the Tomateto React web app and the PostgreSQL database, where all user, post, and comment data are being stored. Hosted with Azure App Service within a Docker container.
This is the back-end side of Tomateto. To learn more about the front-end side, click here.
Here is the working live demo : https://tomateto.com
API Request (example code)
This API supports methods to list, insert, edit, delete, and many more that are specific to a particular resource. The following file identifies methods for Post
resources: Example code
Custom Response Object (example code)
This object is used to handle bad requests made by users that could happen when the user modified the front end web app code through the browser developer tools to try to bypass a request validator (like trying to edit a post created by another user). The following JSON structure shows the format of a response:
{
"message": "Success!",
"code": 0,
"items": {
"id": 1,
"content": "First!",
"photo": null,
"date": "2022-07-26T17:52:22Z",
"likesCount": 2,
"commentsCount": 1,
"user": {
"displayName": "Adam Darmawan",
"id": "U2k7x5pBMXMleCHRqfRTYZkQlmD3",
"avatar": {
"small": "https://someurl",
"extraSmall": "https://someurl",
"default": "https://someurl",
"medium": "https://someurl"
},
"username": "adamscript"
},
"isEdited": false,
"isLiked": true,
"isMine": true
}
}
The following table identifies response codes and messages that the API returns.
Code | Message |
---|---|
General | |
0 | Success! |
User | |
100 | User not found |
101 | Username already exists |
102 | User does not exist (Invalid User ID) |
103 | Username can't be empty |
104 | Name can't be empty |
105 | You can't follow yourself |
106 | You can't follow non existing user |
107 | You can't follow if you do not exist |
108 | User already followed |
109 | User not followed |
Post | |
200 | Post not found |
201 | Post does not exist (Invalid Post ID) |
202 | Post's user can't be empty |
203 | Post's content can't be empty |
204 | Post already liked |
205 | Post not liked |
Comment | |
300 | Comment not found |
301 | Comment does not exist (Invalid Comment ID) |
302 | Comment's user can't be empty |
303 | Comment's post can't be empty |
304 | Comment's content can't be empty |
305 | Comment already likedd |
306 | Comment not liked |
Error | |
400 | An unknown error occured |
401 | You are not authorized for this action |
Data Transfer Object (example code)
This is mainly used to solve the infinite recursion problem that happens when the requested data (in example, all top posts) contains a relation with another entity (in example, the user who created the posts). It also helps reduce the number of calls needed so the server can respond with all of the required data at once (in example, content of the post, name of the user who created the post, and like status of the post) without having to make separate calls for each data.
Instant Search (example code)
The app will index every data that is stored in the database to find data based on search queries faster so users will be able to get responses instantly. This feature is powered by Hibernate Search and Apache Lucene.
Test cases were written to make sure the app runs as exactly as expected outside of the development environment. These tests include unit testing, integration testing, controller testing, and repository testing. The test cases were written using JUnit and Mockito for mocking.
Continuous integration is triggered when a pull request was made. It will automatically run the tests to make sure the app will run as expected after being integrated to the main branch.
Continuous deployment is triggered when a new tag is pushed to the repository. It will add some configurations to the app, then it will build and push a new container to GItHub Container Registry, and finally it will deploy the container to Azure App Service which will trigger the resource to restart.
The CI/CD workflow is being run by GitHub Actions.
This app is running within a Docker container with Eclipse Temurin JRE 17 as the base image and hosted on Azure App Service and GitHub Container Registry.
This app is currently running utilizing two Azure resources:
- Azure App Service This resource hosts the REST API and provides access to the API endpoints.
- Azure Database for PostgreSQL This resource stores the data that can be requested through the API.
Through this project, my main goal was to learn how to write my own REST API and the React app to interact it with. I also wanted to use this opportunity to learn about cloud, containers, testing, and CI/CD. Initially I wanted to build it as microservices but I figured it was a bit too ambitious for what I was trying to build with the amount of time that I had, so I built it as a monolithic app instead.
If I had more time, I would add these :
- More comprehensive testing (it already covers many edge cases, but there are still a few that I wish I could add if I had more time)
- Pagination, which could be useful if the server needs to handle many GET requests at once. Will add this when absolutely needed.
- Error handling, right now it can only handle bad requests made by users, not errors that is caused by the app itself.
If you are having issues or found a bug, feel free to open an issue. Also if you have questions about the project, feel free to reach out at: adam@adamscript.com.
These articles helped me while building this project. Check them out!
- Jackson – Bidirectional Relationships
- Best Practices for REST API Error Handling
- Spring Data JPA: Query Projections
- Testing MVC Web Controllers with Spring Boot and @WebMvcTest
- Full-Text Search with Hibernate Search and Spring Boot
- 9 Tips for Containerizing Your Spring Boot Code
- 10 best practices to build a Java container with Docker