Speak Fluent HTTP: A Deep Dive into Methods and Status Codes

Introduction

Building a high-quality API involves more than transmitting data; it requires adhering to the "language of the web." This guide explores HTTP methods and status codes, detailing the correct actions and responses for various scenarios. Mastering these fundamentals transforms complex code into a professional system that is clear, efficient, and intuitive for integration.

HTTP Methods

The following sections outline the standard implementation of HTTP methods.

1. GET – Retrieve Data

This method is the standard for fetching data without modification. It is "safe" and "idempotent," meaning repeated calls do not alter the server state.

// Fetch the entire list of library members
app.MapGet("/api/members", async (MemberRegistry registry) =>
{
    var members = await registry.ListAllAsync();
    return Results.Ok(members);
});

// Fetch a specific member by unique ID
app.MapGet("/api/members/{id:int}", async (int id, MemberRegistry registry) =>
{
    var member = await registry.FindByIdAsync(id);
    
    return member is null 
        ? Results.NotFound() 
        : Results.Ok(member);
});

Standard Responses:

  • 200 OK: Successfully retrieved the data.

  • 404 Not Found: The requested ID does not exist in the system.

2. POST – Create a New Entry

POST is used to submit data to create a new resource. It is "non-idempotent"; multiple identical submissions typically result in multiple resource entries.

// Register a new vehicle
app.MapPost("/api/vehicles", async (RegisterVehicleRequest data, FleetManager manager) =>
{
    var vehicle = await manager.AddNewVehicleAsync(data);

    // Return 201 Created and include the 'Location' header
    return Results.Created($"/api/vehicles/{vehicle.Vin}", vehicle);
});

Key Standards for POST:

  • 201 Created: Confirms the operation succeeded and a new resource was generated.

  • Location Header: Directs the client to the specific URL of the new resource.

  • Resource Body: Provides the created object, including server-generated fields like IDs.

3. PUT – Full Resource Replacement

PUT replaces an existing resource entirely. It is "idempotent"; repeating the same request multiple times results in the same state as the initial call.

// Completely update project details
app.MapPut("/api/projects/{code}", async (string code, ProjectUpdate data, PortfolioManager manager) =>
{
    var existingProject = await manager.GetByCodeAsync(code);
    
    if (existingProject is null)
        return Results.NotFound();

    await manager.ReplaceProjectAsync(code, data);

    return Results.NoContent();
});

Key Standards for PUT:

  • Complete Overwrite: The request must contain the full representation; missing fields are typically reset or removed.

  • 204 No Content: Confirms a successful update when no response body is required.

4. PATCH – Surgical Updates

PATCH performs partial updates. Unlike PUT, only the specific fields intended for modification are transmitted.

// Update specific parts of a profile
app.MapPatch("/api/subscribers/{id:guid}", async (Guid id, JsonPatchDocument<Subscriber> updates, MembershipService service) =>
{
    var subscriber = await service.GetByIdAsync(id);
    
    if (subscriber is null)
        return Results.NotFound();

    updates.ApplyTo(subscriber);
    await service.SaveAsync(subscriber);

    return Results.NoContent();
});

Key Standards for PATCH:

  • Efficiency: Minimizes bandwidth by sending only changed data.

  • Precision: Reduces the risk of overwriting unrelated fields.

5. DELETE – Remove an Entry

DELETE permanently removes a resource. It is considered idempotent; while the first call deletes the data, subsequent identical requests should not cause system errors.

// Remove a specific record
app.MapDelete("/api/employees/{badgeId:int}", async (int badgeId, StaffManager manager) =>
{
    var staffMember = await manager.GetByBadgeIdAsync(badgeId);
    
    if (staffMember is null)
        return Results.NotFound();

    await manager.PermanentlyRemoveAsync(badgeId);

    return Results.NoContent();
});

Standard HTTP Status Codes

HTTP status codes serve as universal shorthand, ensuring system predictability and simplifying debugging.

A. Success Codes (2xx)

These indicate that a request was received and accepted.

CodeNameUsage
200OKSuccessful GET, or a PUT/PATCH returning an updated version.
201CreatedSuccessful POST resulting in a new resource.
204No ContentSuccessful DELETE or PUT/PATCH where no body is returned.

B. Client Error Codes (4xx)

These indicate a failure caused by the request itself.

CodeNameUsage
400Bad RequestGeneral validation errors or malformed data.
401UnauthorizedAuthentication is missing or invalid.
403ForbiddenAuthenticated, but lacking necessary permissions.
404Not FoundThe requested resource or endpoint does not exist.
409ConflictData collision, such as duplicate unique identifiers.
429Too Many RequestsRate limiting due to excessive requests.

C. Server Error Codes (5xx)

These indicate a failure on the server side.

CodeNameUsage
500Internal ErrorAn unhandled exception or bug within the code.
503Service UnavailableServer overload or temporary maintenance.

Common Professional Pitfalls to Avoid

  • Avoid Misleading 200 OK Responses: Never return a success status code if the operation failed.

    • Results.Ok(new { success = false })

    • Results.NotFound(new { message = "Item missing" })

  • Distinguish Between 401 and 403: Use 401 Unauthorized when identity is unknown or unverified. Use 403 Forbidden when the identity is known but lacks the required permissions for the action.

  • Protect Sensitive Data: Do not include raw stack traces or internal code errors in 500 Internal Server Error responses. Log detailed errors privately and return a generic message to the client.

  • Accurate Error Attribution: Ensure client-side mistakes (such as malformed email formats) result in 400 Bad Request responses rather than server-side 500 errors.

Conclusion

In this article, we have seen how mastering HTTP methods and status codes builds professional, predictable APIs. Correctly applying these standards ensures system scalability and simplifies integration for other developers. Adhering to these patterns provides a robust foundation for building reliable, industry-standard web services. Hope this will useful.