Skip to main content

USE Get action to return a single resource

When building a RESTful API, it is common to include endpoints that allow clients to retrieve a single resource by its ID. This approach provides a flexible and scalable way to retrieve data from the API and is widely used in web development.

Returning a single resource from a RESTful API with its ID typically involves creating an endpoint that accepts a single ID parameter and returns the resource that matches that ID. This endpoint can be implemented using the HTTP GET method, which is the standard method for retrieving data from a RESTful API.

While code block below seems very simple, there are a few constraints needs to be followed while developing a get endpoint. Let's follow what's been done in this example from a UsersController:

  • Name your method as GetUser
  • Return a single object with type matching method name as in GetUserResponse
  • Get id from route that's defined in [HttpGet("{id}")]
  • Place appropriate ProducesResponseType attributes for each return type
  • Return 404 NotFound if object is not found, 200 otherwise unless there is an error
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetUserResponse))]
public async Task<IActionResult> GetUser([FromRoute] long id)
{
GetUserResponse response = new GetUserResponse(user);
return Ok(response);
}

In general, it is not recommended to write an endpoint that returns a single resource by a field other than ID in a RESTful API. This is because the ID is typically the most reliable and consistent way to uniquely identify a resource in a database, whereas other fields may not be unique or may change over time.

For example, if an endpoint returned a single user by their email address, there could be multiple users with the same email address, or a user's email address could change over time, leading to inconsistencies and potential errors in the API.

In addition, using the ID as the primary means of identifying a resource makes it easier to maintain and update the API over time. If the structure or schema of the database changes, for example, the API can be updated to reflect those changes without affecting the endpoints that rely on the ID.

For example, if you need to retrieve a user via its email address, consider writing a query endpoint and returning an array of users with a query field email in the request.

// DON'T DO THIS
// DON'T DO THIS
// DON'T DO THIS

[HttpGet("{email}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetUserResponse))]
public async Task<IActionResult> GetUserByEmail([FromRoute] string email)
{
GetUserResponse response = new GetUserResponse();
return Ok(response);
}

// DON'T DO THIS
// DON'T DO THIS
// DON'T DO THIS

Never implement custom methods other than described 6 actions (Query, Get, Create, Update, Patch, Delete).