API Advice
APIs vs SDKs: Why you should always have both
Simon Yu
April 13, 2023
What’s an API?
An API, or Application Programming Interface, allows different software applications to communicate with each other. For example, a developer in an e-commerce company might create an “orders” API that enables other services to easily retrieve orders made by a certain user. Consumers of the API may be external developers or even other developers within the same company.
There are several different API technologies. Let’s look into the most popular in 2023: REST, GraphQL and gRPC:
- REST (Representational State Transfer): REST is the most widely used approach for creating APIs, primarily due to its simplicity and compatibility with HTTP. It dictates structured access to resources via well-known CRUD (Create/Read/Update/Delete) patterns. A common pattern in modern web development is to create a front-end written in React or a similar framework, which fetches data from and communicates with a back-end server via a REST API.
- GraphQL: GraphQL is a newer API technology that enables API consumers to request only the data they need. This reduces bandwidth required and improves performance, and is particularly suitable in situations where a REST API returns large amounts of unnecessary data. However, GraphQL is more complex to implement and maintain, and users need to have a deeper understanding of the underlying data models and relationships in order to construct the right queries.
- gRPC (Google Remote Procedure Call): gRPC is a high-performance, open-source framework designed for low-latency and highly-scalable communication between microservices. gRPC is strongly-typed, which helps catch errors earlier in the development process and improves reliability. However, gRPC ideally requires support for HTTP/2 and protocol buffers, which many web and mobile clients may not support natively. Also note that far fewer developers are familiar with gRPC than REST, which can limit adoption. For these reasons, gRPC is mainly used for internal microservice communications.
In summary, REST remains the most popular API technology due to its simplicity and widespread adoption. GraphQL and gRPC are popular for specific use cases.
Why are APIs important?
There are several use cases for APIs:
- Leverage the Best: Third party APIs provide developers easy access to services that would take years to build. With just a few lines of code, developers can add payment capabilities (e.g. Stripe (opens in a new tab)), mapping data (e.g. Google Places API (opens in a new tab)), or transactional email (e.g. Resend (opens in a new tab)) into their application, all powered by 3rd parties. This allows developers to stay focused on the value add of their app, and outsource the rest.
- Scale Applications: By providing a well-defined programmatic interface, APIs allow developers to build their applications more efficiently, as they can update or replace individual components without affecting the entire system.
- Collaborate Efficiently: APIs can be used internally to facilitate collaboration between teams by standardizing communication and providing a clear contract for developers to work against. Common functionalities are developed into services and APIs so that they can be leveraged by every team – accelerating the development of new applications and reducing duplicative work.
What is an SDK?
An SDK, or Software Development Kit, contains libraries, documentation, and other tools that aim to make it easy to integrate with an API in a specific language. It simplifies integrating with an API – without the developer needing to dig through docs to patch together details like how the API handles auth, query parameters, or returns response objects.
The idea is that providing an intuitive and streamlined way to integrate with an API enables developers to quickly and easily access the API's functionality. Which is, after all, the goal of an API developer right?
If this sounds a little academic, hang on for the code examples shortly.
A typical SDK contains:
- API client: A pre-built client that handles communication with the API, taking care of low-level details like HTTP requests, authentication, and error handling.
- Data models: Classes or structures that represent the API's data objects, providing a strongly-typed and native representation of the data returned by an API.
- Helper functions and utilities: These assist developers in performing common tasks related to the API, such as data serialization, pagination, or error handling.
- Documentation and code samples: These should be written specifically in the SDK’s language.
Why use an SDK? Why are they important?
It’s worth diving a bit deeper on why SDKs for an API are so important.
Without an SDK, developers have to manually handle the API integration process. This is time-consuming and error-prone. For example, developers need to:
- Read the API documentation, and especially the expected request and response data formats.
- Write code to form and send HTTP requests to the relevant API endpoints, parse the responses into the right data structures, and handle any errors that might occur.
- Manage the low-level details of authentication, retries, and rate limiting. The latter often are left out in the initial stages of integrating with an API, but are incredibly important if the API is being used in critical workflows.
Overall, this approach tends to resemble “trial and error”, which creates a high risk of users introducing bugs into the integration. API users end up frustrated and less motivated to use the API.
However, with a language-idiomatic SDK, developers can avoid these common pitfalls. This results in a faster integration process, and greater API usage as API consumers are provided with a reliable, well-supported – even enjoyable! – experience.
SDKs offer several advantages over the APIs alone:
- Faster development: SDKs provide pre-built functions that help developers accomplish tasks quickly. For example, an SDK for an e-commerce API might include a pre-built function and parameters for placing an order.
- Standardized / streamlined data and type definitions: SDKs can ensure that data returned by an API is handled in a standard and recommended manner.
- Consistency: By offering standardized components and best practices, SDKs promote consistency, making maintenance and management much easier. This might be particularly important for internal APIs, where you don’t want every API user to create an idiosyncratic implementation.
- Breaking change mitigation: When an API introduces breaking changes, the SDK can in some cases be updated to accommodate those changes “under-the-hood” – while maintaining a consistent interface for the developers.
- Streamlined documentation: SDK docs focus on achieving specific outcomes and abstract away many low-level details, making them more usable, easier to understand, and ultimately more effective for developers.
Example of integrating to an API with and without an SDK
To highlight these differences, let’s look at an example of what integrating with an e-commerce API might look like, first without an SDK and then with one.
The use case will be enabling a new customer to place an order. This requires fetching information about the product being ordered, creating a new customer, and creating the order itself.
First, here’s what integrating might look like without an SDK:
const fetch = require('node-fetch');const apiKey = 'your_api_key';const baseUrl = 'https://api.ecommerce.com/v1';const headers = { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json'};const productName = 'Awesome Widget';const customer = { firstName: 'John', lastName: 'Doe', email: 'john.doe@example.com'};const quantity = 2;async function placeOrder(productName, customer, quantity) { try { // Step 1: Get product information const productResponse = await fetch(`${baseUrl}/products`, { headers }); if (productResponse.status !== 200) { throw new Error(`Could not fetch products. Status code: ${productResponse.status}`); } const productData = await productResponse.json(); const product = productData.products.find(p => p.name === productName); if (!product) { throw new Error(`Product '${productName}' not found.`); } // Step 2: Create a new customer const customerResponse = await fetch(`${baseUrl}/customers`, { method: 'POST', headers, body: JSON.stringify({ customer }) }); if (customerResponse.status !== 201) { throw new Error(`Could not create customer. Status code: ${customerResponse.status}`); } const customerData = await customerResponse.json(); const customerId = customerData.customer.id; // Step 3: Place the order const orderResponse = await fetch(`${baseUrl}/orders`, { method: 'POST', headers, body: JSON.stringify({ order: { customerId, items: [ { productId: product.id, quantity } ] } }) }); if (orderResponse.status !== 201) { throw new Error(`Could not place order. Status code: ${orderResponse.status}`); } console.log('Order placed successfully!'); } catch (error) { console.error(`Error: ${error.message}`); }}placeOrder(productName, customer, quantity);
Note that the API consumer would need to construct all this code themself. They would need to refer to the API documentation to figure out which APIs should be called, what the response data structures look like, which data needs to be extracted, how to handle auth, what error cases might arise and how to handle them… oof!
Now here’s the SDK version of this code:
const { EcommerceClient } = require('ecommerce-sdk');const apiKey = 'your_api_key';const client = new EcommerceClient(apiKey);const productName = 'Awesome Widget';const customer = { firstName: 'John', lastName: 'Doe', email: 'john.doe@example.com'};const quantity = 2;async function placeOrder(productName, customer, quantity) { try { await client.placeOrder(productName, customer, quantity); console.log('Order placed successfully!'); } catch (error) { console.error(`Error: ${error.message}`); }}placeOrder(productName, customer, quantity);
Notice how much simpler and concise it is. Authentication is handled automatically with the developer just needing to copy in their key. Pre-built functions mean the developer doesn’t need to parse through pages of API docs to stitch together the required calls and associated data extraction themselves. Error handling and retries are built-in.
Overall, a far easier and superior experience.
What’s the difference between SDKs and APIs?
In summary, APIs & SDKs are symbiotic. Let’s talk about coffee to draw the analogy better.
You can think of APIs as the fundamental, bare metal interfaces that enable applications or services to communicate. In our analogous example, APIs are like going to a coffee shop and getting a bag of beans, a grinder, a scale, filter paper, a coffemaker/brewer, kettle, and an instruction guide. Good luck making a delicious brew!
SDKs on the other hand are critical to enabling APIs to reach their full potential, by providing a rapid, ergonomic way to access the API’s underlying functionality. In our coffee example, SDKs are more akin to telling a skilled barista “I’d like a latte please”. The barista does all of the work of assembling the ingredients, and you get to focus on the end result.
API and SDK best practices
Now we know what APIs and SDKs do, what should you keep in mind as you’re building them, to ensure they fulfill the promises we’ve outlined above?
Here are some “gotchas!” to watch out for when building awesome APIs:
- Design carefully: It can be extremely difficult to get users to change how they use an API once it’s in production. Avoiding unnecessary breaking changes, where possible, will save you many headaches and irate users later.
- Documentation: In addition to an “API reference” that details every endpoint and response, consider creating a “usage guide” that walks users through how to use APIs in sequence to accomplish certain tasks.
- Authentication: Creating and sending users API keys manually works fine for an MVP, but has obvious security and scalability challenges. An ideal solution is to offer a self-service experience where end-users can generate and revoke keys themselves. For more on API auth, check out our guide.
- Troubleshooting and support: Users will inevitably run into issues. It’s easy for members of the team to quickly get inundated with support requests. Try to provide self-service tools for troubleshooting API issues, such as logging and monitoring, and community support channels.
Building great SDKs presents a different set of considerations. Keep these in mind if you want to offer a great SDK to your users:
- How stable is the underlying API? If the API is undergoing frequent changes, it might be particularly challenging to manually keep the SDKs up-to-date and in sync with the API.
- Creation and maintenance cost: Creating native language SDKs for all your customers’ preferred languages can be a huge hiring and skills challenge. Each language SDK also has to be updated every time the API changes – ideally in lockstep to avoid the SDK and API being out of sync. This is time-consuming and costly. Many companies have deprecated or scaled back their SDKs after misjudging the work required.
- Testing and validation: Plan for thorough testing of the SDKs across different platforms and languages, including unit tests, integration tests, and end-to-end tests, to ensure the SDKs are reliable and compatible with the API.
- Documentation: Provide clear examples and code snippets in each language to make the SDKs easy to use and understand.
APIs, SDKs and Speakeasy
As discussed above, APIs and SDKs are both incredibly important tools.
Unfortunately however, creating SDKs for every API has been out of reach for most teams, given their cost, the skills required, and distraction from the core product roadmap.
Until now.
At Speakeasy, we believe that every API deserves an amazing SDK – one that is idiomatic, reliable, low-cost, always-in-sync, and easy to manage.
And that’s exactly what you get with Speakeasy:
- Idiomatic: we know how important it is that the SDK feels ergonomic. That’s why we built a generator from the ground up with a focus on creating idiomatic SDKs in a range of languages.
- Reliable: our SDKs have been battle-tested in real-world scenarios through our customers. And we handle all support and troubleshooting – so you don’t have to.
- Low-cost: until now, only the largest companies have been able to afford an engineering team to focus on SDKs. Speakeasy provides access to best-in-class SDKs for a fraction of the price of a full engineering team.
- Always-in-sync: our SDKs rebuild after every API spec change. Easy to manage: we offer a fully-featured web application so you can always understand the current status of your SDK generation.
If you have an API spec, why not try it for yourself now? Just click the button below to generate your first SDKs for free.