Crafting Readable API Responses

ยท

2 min read

Hey there, tech enthusiasts and creators! Lately, in my backend web development adventures, I've encountered a challenge: inconsistent response structures. As a big fan of simplicity, I'm on a mission to iron out the irregularities in how I structure my API responses.

What's the remedy?

To ensure easy and consistent structures, I took a cue from consuming other APIs. Just like recognizing a Fibonacci series or an Arithmetic Progression, your API structures should have discernible patterns.

In your response, provide a clear, concise explanation of the status code. Include the actual data, a boolean property describing the response state, and the status code:

async function getComments(req: express.Request, res: express.Response) {
  const postId = req.params.postId;
  type QueryProps = { from: string; to: string; limit: string };
  const { from, to, limit }: QueryProps = req.query;

  const comments : Comment[] = await db.comment.find({
    postId,
    from: from || new Date(0).toISOString().slice(0, 10),
    to: to || new Date().toISOString().slice(0, 10),
    limit: parseInt(limit) || 20,
  });

  res.status(200).json({
    data: comments,
    count: comments.length,
    message: "whatever you have to say",
    success: true,
  })
}

Adding a count property to responses containing an array, like comments, assists consumers by reducing the workload on their end.

In cases like fetching a single user, the absence of count indicates the response data type is not an array:

const user = await db.user.findOne(query);

res.status(200).json({
    data: user,
    success: true,
    message: "say something..."  
})

In error scenarios, a well-structured response is key:

if (!user) {
    return res.status(404).json({
        success: false, message: "your statement about the error",
    })
}

The success property is finally doing something. It informs the consumer that the response is of a request that went wrong (the status code provides more information about this to the consumer).

For more complex errors, customize responses based on error types:

try {
 //...
} catch (err) {
 let code = 500;
 const response = {
  success: false, message: err.message,
 }
 if (err instanceof ValidationError) {
  response["error"] = err.error; // IDK
  code = 400;
 }

 res.status(code).json(response);
}

Whenever there's an error, I will have the error property instead of the data property. This makes the responses not only readable but also understandable.

Concluding Thought

As APIs grow in complexity, maintaining concise, simple, and consistent response structures remains crucial. Share your thoughts on improving API responses in the comments. Don't forget to upvote and follow!

Danke! (German for "Thank You" โ€” it's funny how it sounds the same if you pronounce it rapidly!)

ย