Crafting a Robust API Structure: A Deep Dive into Our Instagram-like Application

Welcome back! In our ongoing journey to build a stellar application reminiscent of Instagram, it’s time to lay down the tracks for our API endpoints. In our previous discussion, we explored the system design of our application, drawing parallels with the functionality of Instagram. If you missed that or need a refresher, you can catch up on the system design here.

Designing a REST API demands adherence to best practices to ensure it ticks all the boxes of efficiency, scalability, and user-friendliness. Here’s a breakdown of key guidelines:

  1. Descriptive URLs: URLs should be intuitive and indicative of the resource they represent. Avoid verb-heavy URLs and let HTTP methods do the heavy lifting.
  2. HTTP Methods: Use HTTP methods (GET, POST, PUT, DELETE, PATCH) correctly and consistently, assigning each action its rightful place.
  3. Resource Naming: Keep resource names as nouns and in the plural form for clarity and consistency.
  4. HTTP Status Codes: Each response should carry an appropriate HTTP status code to convey the outcome of the request effectively.
  5. Versioning: Incorporate versioning into your API to ensure backward compatibility as it evolves.
  6. Authentication and Authorization: Implement secure authentication mechanisms like OAuth or JWT and ensure data transmission encryption via HTTPS.
  7. Response Format: Responses should follow a consistent format, accompanied by clear documentation outlining response structures and error messages.
  8. Pagination: Implement pagination for endpoints dealing with large datasets to enhance performance and user experience.
  9. Input Validation: Validate input data to mitigate security vulnerabilities such as SQL injection or XSS.
  10. Error Handling: Provide informative error messages with details on error causes and resolutions, following standard error formats and HTTP status codes.
  11. Caching: Utilize caching mechanisms to reduce server load and optimize performance for frequently accessed resources.
  12. Rate Limiting: Implement rate limiting to prevent abuse and ensure fair API usage.
  13. Documentation: Offer comprehensive documentation to guide users on API usage, endpoint descriptions, request/response formats, and authentication requirements.
  14. Testing: Thoroughly test the API with various use cases and edge scenarios to ensure reliability and consistency.
  15. Monitoring: Monitor API usage, performance, and errors to identify issues and optimize performance.

Now, armed with a solid understanding of what makes a great REST API, let’s dive deeper into our application’s services and the endpoints they’ll expose.

Authentication Service: As the name suggests, this service is going to be responsible for authentication. We can add authorization as well, but we don’t support roles yet. Perhaps that can come later when we build an admin panel for admins and introduce roles there. While services like Azure Active Directory or AWS Identity and Access Management can handle authentication and authorization, we’ll keep it simple and focus on what each service has to offer. For our authentication service, we’ll expose the following endpoints:

  • POST: /login
    body:
    {
    "userName": string,
    "password": string
    }

    this endpoint will return 400 in case of invalid body parameters, 200 in case of successful authentication
  • POST: /signup
    body:
    {
    "userName": string,
    "password": string,
    "firstName": string,
    "lastName": string,
    "dateOfBirth": string
    }

    this endpoint will return 400 in case of invalid body parameters, 200 in case of success
  • POST: /logout
    for logout, the body will be empty, the server will read the user info from token and fulfill the logout request, in case of success it will return 200, incase the logout is called without having a session the server will respond with 422.

User Service: We’ll have a user service responsible for managing user-related functionalities. This service will expose endpoints for fetching current user information, updating user information, searching for users, and managing user relationships (follow/unfollow). Here are the endpoints:

  • GET: /users/:id
    response:
    {
    "firstName": string,
    "lastName": string,
    "dateOfBirth": string
    }

    This endpoint will retrieve user information based on the provided user ID. It will return a 200 status code along with the user’s information if the request is successful. If the user ID is not found, it will return a 404 status code and 401 if the user is unauthorized.
  • POST: /users/:id
    body:
    {
    "firstName": string,
    "lastName": string,
    "dateOfBirth": string
    }

    This endpoint will update user information for the user specified by the provided ID. The request body should contain the updated user information. It will return a 200 status code upon successful update. If the user ID is not found, it will return a 400 status code in case of invalid parameters and 401 if the user is unauthorized.
  • GET: /users?username='{username}’
    response:
    [{
    "firstName": string,
    "lastName": string,
    "dateOfBirth": string
    }]

    This endpoint will search for users based on the provided username. It will return a list of users matching the provided username along with a 200 status code if successful. If no users are found, it will return an empty list and 401 if the user is unauthorized.
  • POST: /follow/:userId
    This endpoint will allow the currently authenticated user to follow the user specified by userId. It will return a 200 status code upon successful follow. If the user to follow is not found, it will return a 404 status code and 401 if the user is unauthorized.
  • POST: /unfollow/:userId
    This endpoint will allow the currently authenticated user to unfollow the user specified by userId. It will return a 200 status code upon successful unfollow. If the user to unfollow is not found, it will return a 404 status code and 401 if the user is unauthorized.

Upload Service: Our application will feature functionality to upload pictures. Therefore, the upload service will offer a single endpoint for this purpose:

  • POST: /upload
    the upload request will be a multi-part form data request, the following information will be sent.
    {
    "fileName": string,
    "fileSize": number,
    "caption": string
    }

    The server can return 200 in case of success, 401 in case of unauthorized, 400 when request is invalid

Feed Generation Service: The feed generation service will be responsible for generating and managing user feeds based on specific algorithms. It will read data from a message queue and modify feeds accordingly. For simplicity, we’ll implement a pull mechanism. The endpoint exposed by this service will be:

  • GET: /feed
    response:
    [{
    "userName": string,
    "userProfilePicUrl": string
    "imgUrl": string,
    "caption": string,
    "hashtags": string[]
    }]

    The response will be an array of posts from from followed users, 200 status code is returned in case success, if the feed is empty the list will be empty with 200 status code and 401 in case of unauthorized access

By defining clear endpoints for each service, we pave the way for seamless functionality and user satisfaction.

So, with our roadmap set and our endpoints defined, let’s embark on the next phase of building our Instagram-like application, one step closer to making our vision a reality.