Demystifying Status Codes in API Response

Demystifying Status Codes in API Response

3 min read

The Article Initially was published on https://www.linkedin.com/pulse/demystifying-status-codes-api-response-clear-guide-custom-jahid-hasan-d68hc/


Introduction

The last few months, I have been working on a client-side project with React and React Native technology. While I was integrating APIs, I encountered some confusion regarding HTTP status codes. Let me explain one scenario below.


Problem

Let's say a user has signed up for an account to our system but our system will not allow him/her to login until he/she verify his email with an OTP code. When the user tries to log in under these circumstances, we should redirect them to the OTP input page to verify their email address first. In this scenario, I found the backend was sending a status code 404 (Not Found), which conveys a completely different meaning.

When I asked about this then more confusion arose regarding which status code to use. If we send a 401, it means 'Unauthorized,' and we are using it for access token invalidation. If we send a 403, it means 'Forbidden,' and we are using it for a different scenario. So what should we can return in this case?


Custom Status Code

Hence Custom Status Code comes to save us,

We are usually send error response like this, (Let's focus on the custom status codes we can control within our API responses, rather than the default HTTP status codes)

{
    "error": {
        "code": 401,
        .........
        .........
    },
    "metadata": {
        "version": "1.0",
        "timestamp": "2024-05-22T12:34:56Z"
    }
}        

If we notice the above error.code, it's 401. which one we mostly use to send when a token is expired/invalid.

We can send our custom code as error.code: 40100 here to indicate specific issues, such as unauthorized access due to an invalid or expired token.

{
    "error": {
        "code": 40100,
        ......
        ......
    },
    "metadata": {
        "version": "1.0",
        "timestamp": "2024-05-22T12:34:56Z"
    }
}
        

And we can send our custom code as error.code: 40101 to indicate specific issues, such as unauthorized access due to an unverified email ID.

// A sample error response of Level 3 API 
{
    "error": {
        "code": 40101,
        "message": "Email verification required before login.",
        "trace_id": "abcd1234-ef56-7890-gh12-ijkl3456mnop",
        "hints": [
            "Ensure the user has received the OTP email.",
            "Use the verify email link to send or resend the OTP."
        ],
        "links": {
            "self": {
                "href": "https://api.example.com/users/12345"
            },
            "verify_email": {
                "href": "https://api.example.com/users/12345/verify-email",
                "method": "POST",
                "description": "Send verification email"
            },
            "resend_otp": {
                "href": "https://api.example.com/users/12345/resend-otp",
                "method": "POST",
                "description": "Resend OTP code"
            }
        }
    },
    "metadata": {
        "version": "1.0",
        "timestamp": "2024-05-22T12:34:56Z"
    }
}        

We can use custom codes in other scenarios too, such as providing a clear concept of 404 Not Found:

  • 40400: User not found

  • 40401: ABC product not found

  • 40402: Resource not found

  • etc.

We can use custom codes as providing a clear concept of 201: Created,

  • 20100: User created.

  • 20101: ABC product created.

  • 20102: Resource created.

  • etc.

{
    "code": 20100,
    "message": "User created successfully.",
    "info": "Please verify your email to complete the registration process.",
    "data": {
        "user_id": "12345",
        "username": "johndoe",
        "email": "johndoe@example.com",
        "status": "pending_verification"
    },
    "links": {
        "self": {
            "href": "https://api.example.com/users/12345"
        },
        "verify_email": {
            "href": "https://api.example.com/users/12345/verify-email",
            "method": "POST",
            "description": "Send verification email"
        }
    },
    "metadata": {
        "version": "1.0",
        "timestamp": "2024-05-22T12:34:56Z"
    }
}        

This approach helps us in identifying the specific issue correclty and it is making easier for the client-side developer to handle different cases more effectively.


Conclusion

Understanding and utilizing the HTTP status codes is really needed for effective API communication. HTTP status codes like 401, 403, 404, 422 etc. serve different purpose and they should be used to convey the state of a request accurately. However in a certain scenarios the custom status codes can provide more precise information. And it can enhance the clarity and usability of API responses.

Custom codes like ```40101``` for an unverified email or ```20100``` for user created successfully help the client-side developers to handle specific conditions with more effectively. These codes must be well documented and implemented to ensure they add value to the API's design.