How Smart API Design Promotes Sustainable App Development

With the tech industry evolving rapidly, reducing development time has become absolutely crucial. For established software companies and independent developers alike, success requires fleet-of-foot decision making. Luckily, API design best practices have come to the rescue. Putting these practices to work ensures greater security, efficiency, and scalability for your apps.

Amjad Afanah, Co-Founder of FX Labs, is meeting these challenges head-on. Afanah is rewriting the API playbook to emphasize new-and-improved standards. Rethinking flawed practices can boost cost-effectiveness while making apps robust enough to support exponential growth.

Watch Amjad Afanah present at the Platform Summit:

Slides

We’ll share and expand upon some of Amjad’s talking points below:

REST Resource Handling by Type

When designing sound APIs, taking stock of your various resources is paramount. These resources represent the data a given API can access either client side or server side. API developers assign Uniform Resource Identifiers (URIs) to these resources, which dictate how items are referenced.

Semantics play an important role when making successful API calls. Afanah argues that developers should avoid using nouns in lieu of verbs, unless explicitly referring to actions. It’s crucial that we use proper naming conventions for every resource. But why is this the case?

There are four categories of REST resources:

  • Documents
  • Collections
  • Stores
  • Controllers

Let’s briefly tackle controllers first, since they’re the exceptions:

When designing REST APIs, verbs are required to access controller resources. Controllers involve procedural operations, according to the REST API Design Rulebook, making this requirement both logical and natural. For example, apps may utilize specific APIs for authentication or make computations based on inputs.

POST /alerts/111234/resend

These resources and their siblings are unique since they don’t connect with standard methods – create, retrieve, update, and delete (CRUD).

Next, we have stores, which developers should always denote using plural nouns. Since stores are repositories for resources of a given type, they’re often referenced by category. For example:

https://api.example.com/library-management/users/{id}/songs

Items within stores are initially assigned URIs by the client, and therefore don’t generate additional URIs.

Similar to stores are collections, which are also denoted by plural nouns. While clients manage stores, collections are managed by servers. Collections pick and choose which resources to accept, and can thus generate URIs for each. Sticking with plural naming conventions throughout your API code ensures your mapping remains consistent for the user. For example, specifying both /resource and /resources causes confusion with routing. The same thing applies to stores, in essence.

Finally, documents are denoted by singular naming conventions. A document is a singular record and refers to an instance. The document type stands out by acting as something of a base for other resource types, due to its structure. It can have children and thus acts as the API’s root resource:

https://api.soccer.restapi.org/leagues/seattle 
https://api.soccer.restapi.org/leagues/seattle/teams/trebuchet
https://api.soccer.restapi.org/leagues/seattle/teams/trebuchet/players/mike

Finally, avoid designing resources that are hybrids of two REST types. This ensures consistent API design and keeps your link structure predictable.

Error Handling is Important

While designing a quality API, you must create logical error states for end users. When an invalid call is made but no feedback is given, it can cause frustration and confusion. Your API errors should be based around contextual, logical status codes organized by issue type. Assigning these descriptive messages ensures users won’t be in the dark.

Some obfuscation may also be required for security purposes. You don’t want to accidentally give attackers insight into your API’s core structure:

“Error handling is extremely important, and it’s also important from a security perspective — specifically for the 500 status code. You have to be very, very careful not to sort of dump your entire stack trace when an internal server error happens. Otherwise you’re giving hackers the opportunity to reverse engineer and figure out how your application is actually working…”

Afanah also points out the delicate balance between security and clarity. Ultimately, one must provide end users with ample reasoning as to why an error is occurring without revealing too much. This error payload must be informative or it serves no redeeming purpose.

Let’s jump quickly into Amjad’s example, centered on the 403 Forbidden error code. While authentication is successful, that request may also be forbidden. In these instances, Afanah suggests providing feedback in the payload, such as “you don’t have enough credit to complete this transaction.” This gives users a better idea as to why the API function was not executed.

Monoliths vs. Microservices

Generally, monolithic code bases are easier to begin developing with. Monolithic setups typically include a centralized source-code repository, which engineers can readily access. Contained within are shared tools and dependencies. Many large companies — notably Facebook, Microsoft, and Google — have adopted this model.

However, Afanah is quick to emphasize some drawbacks to this method. When the codebase rapidly grows, it becomes difficult to release feature updates. It’s challenging to sort through many dependencies. Additionally, end-to-end testing must be completed when only one feature is being altered. This makes development cumbersome and expensive.

Conversely, microservices are well-suited to agile development. Since features are essentially siloed, less testing is required. This means businesses and API developers can work swiftly. This also boosts scalability. However, linking microservices can be tricky when dealing with multiple dependencies.

API Security Best Practices

You could build the most functional, robust API in existence. However, proper security measures are essential in keeping your API viable. Users will be much more apt to utilize your API if it’s less susceptible to vulnerabilities. This is especially true for enterprise clients.

One common method attackers use to disrupt services is a Distributed Denial-of-Service attack (DDoS). Since most APIs are hosted on web servers, attackers can flood these servers with requests. When this reaches a critical volume, your services will no longer be accessible. When you have a lot of users, downtime is a huge issue.

Afanah advocates for simple pagination limits, which can mitigate unnecessary network traffic. Otherwise, searches could theoretically return millions or billions of results at once. This can easily overwhelm your servers. Using LIMIT and OFFSET restricts how many resources users can call at a given time, preserving bandwidth.

Role-Based Access Control (RBAC), while useful, is not a magic bullet. When building access control into authentication systems, API architects will include multiple, finely-tuned permissions. As this list grows, it becomes harder to maintain and requires more resources. If companies don’t invest in continual upkeep, vulnerabilities can develop. API users can obtain elevated access to resources when checks are missed. As Amjad states, this is unintended and can be very harmful. These users can accumulate unnecessary roles, facilitating this outcome.

Lastly, hackers can employ SQL injections and data attacks to access sensitive information and extract data. Attackers can also erase or otherwise alter important data. Thankfully, there are many tools that assist with catching these coding errors before they go live.

API Testing Best Practices

Afanah lays out five key practices for API testing, focusing on ease of use:

  • Standardized tests
  • Data-driven testing
  • Distributed test execution
  • Automated bug management
  • API security testing

Each has distinct advantages over other methods. Let’s break them down one by one:

Standardized testing and writing are important for a team-based approach. Using one markup language lets developers focus their attention on one tool. This is useful since development is a process where teammates pass code along.

Data-driven testing really focuses on taking one core data set and applying it elsewhere. Instead of creating new tests each time, developers can reuse previous tests. When tests multiply extensively it becomes inefficient to run them.

Distributed test execution is implemented with scaling in mind. When tests run intelligently in parallel, it slashes lead times and allows more resource allocation.

Automated bug management, Amjad argues, must be somewhat automated. Otherwise, issue tracking can quickly become overwhelming.

Lastly, API security testing must be applied ASAP in the development process. It’s much simpler to evaluate code vulnerabilities progressively, instead of auditing a massive codebase.

Traditional vs. Shift-Left Testing

Afanah is a huge proponent of testing early in the design phase. In the traditional testing life cycle, bugs become progressively more expensive to resolve:

When we catch these bugs sooner, they cost less for two main reasons: less time is required to resolve them, and they are relatively-less impactful on the API.

When we shift testing leftward, catching bugs becomes simpler. Fewer associated costs means less financial impact. Given that startups and small businesses are especially sensitive to financial woes, early testing is crucial. According to the Ponemon Institute’s International Data Breach Statistics, 60% of startups go out of business within six months of an attack. This makes proactive testing essential.

According to those same statistics, 89% of breaches and data loss could have been prevented by proper testing. Take the time to galvanize your API against external threats. After all, recently-written code will be fresher in your mind than code written weeks prior.

The Cautionary Tale of GitLab

Afanah references previous security issues with GitLab’s Events API to highlight this. One vulnerability lead to the exposure of innumerable confidential project issues. This security problem wasn’t spotted until one year later. Given that the Events API had been widely adopted, GitLab had to notify scores of developers. As a result, GitLab invested a large amount of money into solving these problems.

Amjad also argues against relying on bug-bounty programs. By the time users discover and report these issues, the cost to fix has grown immensely. If too expensive, companies may have to withhold fixes until funding is available.

Closing Notes

Amjad closes his discussion by turning things back to FX Labs, explaining the API design best practices they employ on a daily basis. It’s important to briefly reiterate the benefits of security and parallel testing.

API development is growing increasingly complex as tools become more powerful. Keeping these guidelines in mind will give your future projects the best chance of success. These API design best practices should be your blueprint moving forward.

Resources: