7 Pro Tips to Build Good Web API – Windows ASP.NET Core Hosting 2024 | Review and Comparison

The components of a good API include logs, documentation, performance, and many others.

Given the prevalence of Web APIs, it is crucial for developers to have the skills necessary to implement effective APIs. After all, this will be a regular task for you as a web developer, especially if you use Microsoft technologies like ASP.NET Core.

1. Write Good Endpoints

Always Use Nouns

Always use nouns rather than verbs when constructing endpoints. The incorrect and proper methods are shown below.

Wrong:
/api/GetOffer/{offer}

Correct:
/api/offers/{offer}

Naming Conventions

Although there are some differences in nomenclature, it is very common to find URLs from well-known technology companies that always use lowercase. If you must use a word that is primarily a noun, try to separate the words with an underscore (_) or a dash (-). See the example below:

Wrong:
/Api/Orders/AdditionalFields

Correct:
/api/orders/additional_fields
or
/api/orders/additional-fields

Nouns in the Plural or Singular?

As was previously stated, nouns should be used in place of verbs. However, it is sometimes unclear whether to write nouns in the plural or singular.

There is no right or wrong answer; it is entirely up to you. However, I like to use the plural form because it indicates a group of qualities that can be any number of them. When you use the singular, it appears as though you are limiting the endpoint to a single item.

Whatever method you choose, the objective is always to make things simpler.

Good (singular):
/api/order/additional_field

Better (plural):
/api/orders/additional_fields

Versions

It is important to create various versions of the same API because APIs frequently change after their initial release. Many businesses opt to use the letter “v” plus the version number in the endpoints to explicitly state the API version. Thus, the first version typically has the designation “v1.”

API versioning can aid in system upkeep. As all changes are made available on a different endpoint, in this case v2, systems that use the v1 endpoint are not affected.

But it’s crucial to stress that doing so is optional. Most businesses rarely produce versions of their APIs. In these situations, fresh APIs are developed to replace the outdated ones.

Good:
Unversioned endpoint: api/offers/{offer}

Better:
Versioned endpoint: api/v1/offers/{offer}

2. Use Right HTTP Verbs

You must first understand the fundamentals of HTTP. Since this is not a difficult subject, we frequently neglect the documentation in favor of practice, which leads to the improper use of the technology’s resources. This page, created by Mozilla Firefox and titled Basics of HTTP, is a great resource for comprehending HTTP concepts.

The primary HTTP verbs and their associated functions are listed below:

HTTP MethodDescription
GETFetch a resource
POSTCreate a resource
PUTUpdates a resource
DELETEDelete a resource
PATCHPartially updates a resource

Use the Right HTTP Status Codes

HTTP status is a useful feature that is available. Depending on the outcome of the action sent in the request, which may be successful or unsuccessful, these statuses are returned in the server response. Regardless of the outcome, there are various types of status; it is the developer’s responsibility to implement the appropriate status in light of the circumstances.

For instance, a query string can be used to send the seller’s ID to an API. The API returns the information for the corresponding seller if the id is present in the database. If not, the API issues a detailed description of the error. The two scenarios are as follows:

  1. Seller found
HTTP/1.1 200 OK
Content-Type: text/html

{
    "status": "success",
    "data": 
    {
        {
            "idSeller": "100002132",
            "name": "SellerExample",
            "offerCode": "4",
            "smallSeller": false
        }
    }
}

2. Seller not found

HTTP/1.1 404 Not Found
Content-Type: text/html

{
    "status": "error",
    "messages": [
        {
            "code": "018",
            "message": "Seller not found"
        }
    ]
}

The consistent use of the return status is a further crucial point. Success, for instance, has a pattern that is frequently used for each verb.

  • GET: 200 OK
  • POST: 201 Created
  • PUT: 200 OK
  • DELETE: 204 No Content
  • PATCH: 200 OK

You can check the complete list of available statuses in the Mozilla Firefox documentation: HTTP status codes.

3. Keep business rules off of endpoints

The best option is to create a class, frequently called Service, put the business rules in it, and then simply invoke the main method of the service class on the endpoints because the endpoints of an API are used for the input and output of data. As demonstrated in the following examples:

Wrong:
app.MapPost("v1/products", (Product product, ProductDbContext dbContext) =>
{
    string errorMessage = string.Empty;

    if (string.IsNullOrEmpty(product.Name))
        errorMessage += "Name is mandatory";

    if (string.IsNullOrEmpty(product.Category))
        errorMessage += "Category is mandatory";

    if (!string.IsNullOrEmpty(product.Name))
        Results.BadRequest("Error creating the product");

    else
    {
        dbContext.Products.Add(product);
        dbContext.SaveChanges();
        return Results.Ok();
    }

}).WithName("CreateProduct");
Correct:
app.MapPost("v1/products", (ProductService service, Product product) =>
{
    var resultMessage = service.Create(product);

    if (!string.IsNullOrEmpty(resultMessage))
        Results.BadRequest($"Error creating the product, error validation: {resultMessage}");

    return Results.Ok();

}).WithName("CreateProduct");

4. Use Pagination and Filtering

Applications frequently expand over time, so it is crucial to give API users the option of only obtaining the specific number of items they require. Pagination is an idea for this.

The best way to implement paging without placing a heavy performance burden on the database is to offer a parameter (identifier) that can “cut” a group of records as well as a quantity limiter.

Below are examples of both bad and good behavior. There are neither paging options nor restrictions in the first example. These parameters are present in the endpoint route in the second, as can be seen.

Good:
GET v1/products

Better:
GET v1/products?limit=100&category=headphone

5. Provide a Health Endpoint

Making a Health route available to all users is a good idea because it allows users to check the health of an API, as its name implies. In this situation, you can check the API dependencies and return the result from each one in addition to determining whether the API is available.

For instance, you can check the availability of an external API in the Health endpoint of an API that needs to generate a token for it and return the information in the Health route.

Therefore, if a consumer’s API returns an internal server error (error 500), they can quickly identify the possible source of the issue. A Health endpoint example is shown below.

GET – v1/products/health

app.MapGet("v1/products/health", (ProductService service) =>
{
    var externalAPIResponse = service.ExternalAPIHealthVerify();
    return Results.Ok($"External API response: {externalAPIResponse.StatusCode} - {externalAPIResponse.Message}");

}).WithName("Health");

6. Use API Caching

Data that is frequently used is stored using the cache technique. It is very helpful because it aims to improve performance and lessen the load on web/database services by storing data in an accessible location, such as in-memory cache (the server’s memory), persistent in-process cache (a file or database), or distributed cache (multiple processes).

An ASP.NET Core Web API implementation of memory caching is demonstrated below.

app.MapGet ("v1/products", (ProductService service) =>
{
    const string ProductsKey = "_Products";

    if (!cache.TryGetValue(ProductsKey, out List<Product> products))
    {
        products = service.GetAll();
        var cacheEntryOptions = new MemoryCacheEntryOptions
        {
            AbsoluteExpiration = DateTime.Now.AddMinutes(3),
            SlidingExpiration = TimeSpan.FromMinutes(2),
            Size = 1024,
        };
        cache.Set(ProductsKey, products, cacheEntryOptions);
    }
    return Results.Ok(products);

}).WithName("GetProducts");

7. Write Good Documentation

When creating an API, it is crucial to write solid documentation because this is how developers will implement the API’s users.

To provide documentation about their APIs, major corporations have adopted a model that is strikingly similar to one another. Typically, a webpage that has all the information a customer needs to be created from scratch is very straightforward.

The criteria for good documentation are listed below.

  • Describe the API’s features in brief. Any business rule should always include crucial details. Example: “You must wait 24 hours after placing an order before canceling a purchase.”
  • Always keep the Request and Response separate. Give an example of the data that should be sent in the Request and received in the Response for each of them, along with the HTTP verb and the route that should be accessed.
  • Always include a process flowchart if the API is complex; it is easier to understand an image-based process description than a verbal one.

Conclusion

A good API is made up of a number of components that when combined, offer a number of benefits like simple integration, quick development, simple maintenance, etc.

This article provided advice on seven topics for producing expert-caliber Web APIs. As a result, it’s important to make sure you don’t overlook any of them when developing a new API.