While APIs form an important part of modern software development, it’s crucial to ensure that the utility offered by an API does not come at the cost of hindered productivity. Often it takes developers multiple hours to get familiar with an API before they can start building and integrating with it, however, a great developer experience can ensure developers get started with the least of steps and minimal time. In this blog, we will discuss how code samples help contribute to an outstanding developer experience. We will discuss in detail what makes good samples, the different styles of samples, and how samples gel with documentation and other elements to form a formidable developer experience.
Part I: Code Samples — Why Should We Care?
Learning new technologies is a complex task, even for the savviest of developers. Often it requires them to go through in-depth documentation, guides, and tutorials, something which they are very keen to skip. What code samples do instead, is provide them with a task-based learning activity, which requires concrete action.
Developers love learning by experience.
Developers are hands-on learners and code is another language they speak. When they see code, they want to try it, break it apart, and put it into action. It’s their favorite call-to-action, often when figuring out if an API is a right fit for them, developers would have already tested out the code samples on developer portals to make their choice.
This was proved by a user study conducted by Twilio, where they found that pages with lesser words before code, did better than pages with more sentences before code.
Hence it comes as no surprise why code samples make an important part of the developer experience checklist list for several APIs programs, including the likes of Amazon, Facebook, Twilio, and Stripe. All of them have code samples included one way or the other and have found massive success. And for a very good reason.
API Calls are Complex Structures
Before we further talk about code samples, it’s important to understand the need for them in the first place. Why can’t developers do without them?
And it all starts with putting an API call together. A lot goes into an API call, all these protocols, and conventions, and developers get all caught up in it, instead of focusing on their actual projects. It can take developers multiple hours to figure out what to put into a call, taking a toll on their productivity and creativity and all adding up to integration time.
What code samples do is put their calls together for them, in languages of their choice, so they don’t have to do it. Nicely done samples can get developers to the first Hello World with an API without writing a single line of code. Samples that go beyond that can be put straight into production. This now leads to our next question.
How many code samples can you write?
Not enough! Especially if you are looking for coverage of every endpoint. APIs tend to change and evolve and to update the samples manually with every iteration, even if you somehow managed to produce them is not feasible.
A viable approach here is to auto-generate these samples using an out-of-the-box documentation solution. Different tools have different ideas on how to package and deliver these samples. While some do the bare minimum, others go the extra mile to see developers have to put in as little work to get them running. It’s important for API owners to select the right tool to provide the best samples to their consumers, it should be a top priority to choose a documentation solution.
Part II: Code Samples — Several Different Styles
To help API owners make well-informed choices, we ran a study to compare these different styles of samples, which we analyzed keeping in mind the following qualities:
- Learning Objective — They demonstrate actual (non-theoretical) use of API
- Runnable — Are runnable out of the box on a console and IDEs
- Interactive — Come with a playground to tweak them around
- Language Idiomatic — Proper language Structure to gel in with production-ready applications
We categorized our learning into 5 different styles, the summary of which is categorized in the table below:
Style 1: Static, Non-Runnable HTTP Snippets
The first style is made of static samples, which are not runnable out of the box and required some tweaking done on them. The samples while easily navigable alongside the reference docs, come with no code playground and cannot be tried or tested on the portal.
We call the samples, HTTP snippets, because they essentially look like an HTTP call, without any proper language structure around them. Samples for some languages were copy-paste ready, while others took a bit of tweaking to run. In the case of Java, we had to configure maven dependencies for the build, and the generator could not pick some values such as the example body and the auth header, which have to be manually added.
These samples were built upon the Kong httpsnippet
library, which has been made open source by Kong to be included within your documentation products. This specific sample was generated on the Postman platform. While there was no on-portal console, on the Postman app you can run a call using Postman collections.
Style 2: Dynamic, Non-Runnable HTTP Snippets
The second style of samples is made of dynamic HTTP snippets. While the sample came along with a console, they were incomplete and had to be tweaked to be made runnable on the console and IDEs.
After a few simple fixes, including the missing headers and entering a body, we got the samples running.
The console, while getting the job done, made it a difficult task to add in these fields, offering no help on what goes inside the call. For somebody completely unaware of the API and starting new, making use of the console could prove to be a challenge.
These samples, too, were built on Kong’s HTTP Snippet library and resembled barebone curl command lacking language structure.
Samples in this style are available in Shell, Javascript, Node, C, Java, PHP, Objective-C, Swift, Python, Ruby, C#, GO and OCaml, covering pretty much all major platforms. We found this style on Stoplight.io.
Style 3: Dynamic, Runnable HTTP Snippets
The third style of samples is made of dynamic snippets that were runnable out of the box. We had to add nothing to the samples to make them work, they came with all the required constructs.
The samples come with an intuitive playground that lets you know what kind of field goes where with what data types. This makes it very easy to construct a sample.
Although the samples did a good job explaining what goes in and out of an API call, they were still not idiomatic and required work to be done on them. For instance, there is no body serialization going on, all these different fields that have to go as arguments, go as one single string and there is no mechanism to put those values together in the form of one single string. These samples were found on Readme.io.
What we also found missing in all three of these styles was a lack of getting started guides, for instance, the HTTP client requires to be included as a dependency and then included as imports within the sample, something which has been left to the discretion of the user to figure out. For novice developers, setting up development environments may also prove to be a challenge, something which the samples or the documentation does not help with at all.
Style 4: Dynamic, Runnable HTTP snippets, with Proper Guides
The fourth style of samples, while also dynamic and runnable, came with an extra advantage. We found configuration instructions for them, which made it easier to work with them.
The sample can be tried and tested on the in-product interactive console. Although the console was not as intuitive as the one found in Style 3, particularly making it tough to add arguments, you have to make sure to not mess up a single space of bracket when making up the JSON string, or the request won’t go.
Style 5: Dynamic, Runnable & Language Idiomatic snippets
These samples are different than the ones we saw above, you see no specifics of making an API call here, no URLs passed or methods declared or headers going in. Instead, you see some object-oriented code here, using proper crud mechanisms.
This is because these samples were generated alongside an SDK, an SDK abstracts out all the details about making an API call and generates additional language structure around these samples, so developers have to write as little communication code as possible. This includes body serialization and response deserializations, which makes it very easy to work with data points.
The samples can be tried and tested out and tweaked using an interactive explorer, which comes with intuitive, form-based ways to input. The console validates every field, so no incorrect data goes in and helps you construct samples without touching code at all. With the console, you can construct API calls with your sample arguments and authentication keys, and copy-paste the resulting samples into your production-ready applications.
And all of that comes with proper documentation, the platform gives API providers the facility to document every parameter in each of the endpoints and data models. Providers can also auto-generate "getting started guides" for different IDEs.
Once set, the developers navigate to their desired use case, copy-paste the code, and start working on the business logic — letting the SDK and the sample take care of logistics.
Part III: Making Code Samples Work in Production
Looking at the different styles of samples, the question that now arises is how practical are these samples to use? Do they completely replace the need to code, or are they just a push towards the right direction? Do they fully demonstrate the use case for the endpoint? Or do they just explain the logistics of making an API call?
Language Coded HTTP Snippets or More?
If you closely look at many of the auto-generated samples, especially the styles 1 to 4, what they essentially do is eliminate the redundant work of configuring environments, and help consumers figure out what kind of syntax to use. However, when making real-world use of API, you need a lot more. Do these samples, which essentially lack language structure and look like language-translated HTTP requests, cut it? The answer is NO and for the following reasons:
- No Data Types: The samples take input and output in the form of a string, leaving it to the consuming developers to write an efficient i/o mechanism to complete these requests. Often the fields inside the body are not documented.
- No Data Models: Modelling the JSON/XML as classes make it easier to deal with the data, both input, and output. These “models” add a whole different layer on top of the API, with your application having to interact with the model, instead of queried response in JSON or XML.
- No Validation and Error Handling: Since there is no proper I/O mechanism, and both inputs are taken and output returns in form of JSON strings, it’s impossible to validate the sent data and handle error cases to determine what went wrong with the request.
To further demonstrate our point, we will write a Sample App to make a new pet entry to a store. The app will utilize Code Samples generated by Postman for the endpoint Add Pet.
Copy-pasting the code straight away did not work. To configure the HTTP client, we had to include the maven dependency in the build. Following this we found the authentication header missing. We passed in the credentials:
.addHeader("api_key", "special-key")
And then had to build a JSON String to pass in the input, since the argument body is passed as a String. Constructing an argument body of the two required fields, this is how the sample looked like:
package TestApp.Testapp123;
import java.io.*;
import okhttp3.*;
class main {
public static void main(String []args) throws IOException{
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\"name\":\"doggie\",\"photoUrls\":[\"photoUrls1\"]}");
Request request = new Request.Builder()
.url("https://petstore.swagger.io/v2/pet")
.method("POST", body)
.addHeader("Accept", "application/json, application/xml")
.addHeader("Content-Type", "application/json")
.addHeader("api_key", "special-key")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
}
}
We ran the code after this tweaking, and it worked like a charm. So how do this sample further translates to real-world usage? If we were to take inputs for the Pet entry from a user, how do we send that as arguments? And before that how do we ensure the data taken from the user is of the correct type? To tackle that we wrote a model class for the Pet Object, with all the underlying attributes including getters and setters.
package TestApp.SimpleConsoleAppFix;
import java.util.List;
import io.swagger.petstore.models.Category;
import io.swagger.petstore.models.StatusEnum;
import io.swagger.petstore.models.Tag;
public class PetModel {
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getPhotoUrls() {
return photoUrls;
}
public void setPhotoUrls(List<String> photoUrls) {
this.photoUrls = photoUrls;
}
public List<Tag> getTags() {
return tags;
}
public void setTags(List<Tag> tags) {
this.tags = tags;
}
public StatusEnum getStatus() {
return status;
}
public void setStatus(StatusEnum status) {
this.status = status;
}
Long id;
Category category;
String name;
List<String> photoUrls;
List<Tag> tags;
StatusEnum status;
}
Following this, we wrote the code to take in input values for these attributes. Now that we ensured we took in these values, with their correct data types, how do we pass these in the request, since the request passes the arguments in the form of a string? Manually doing this was, of course, unfeasible and out of the question, so we had to write in an object to string mapper to do the job for us. This took in these various attribute fields and put them together in the form of a JSON string.
It was at this point that we were able to achieve a business use case out of the sample. We could pass in the input parameters, with their correct types, concatenated as a JSON string, and passed along with the argument. The model allowed us to keep local records of the sent values as well.
https://blog.devapi.dream.press/media/a6a1ace16d322eaaf541f83acf4905f9
Working with multiple endpoints and multiple models would have taken us even more time, depending on the use case and business logic. For instance, for the GET endpoints, we would have to write a string to the object mapper to parse values from the response string back to our model. While the sample does a great job pushing developers in the right direction, it is clear that it is not a plug-and-play situation. Developers have to put in a lot of code to get the calls running, and have to figure out on their own what goes before or comes after the API call.
Now imagine if there were samples that could take care of all these logistics, you had to write no communication code at all, and could just plug and play a sample into action. The good news is, you no longer have to imagine. The language idiomatic samples generated alongside an SDK already do that for you.
Language Idiomatic Code Samples — The Way To Go
SDKs have often been labeled as the cornerstone of the API developer experience. What SDKs essentially do is that they abstract out all underlying details of making an API call, making your API look like a library. They provide developers a complete framework to model their applications, including all the necessary dependencies, referenced libraries, system libraries, i/o mechanisms, and class models.
Furthermore SDKs automatically format API responses to match the data types used in the programming language. They add an interface on top of the API, so your app interacts with the modeled data from SDK, instead of raw API arguments and responses. By providing SDKs, you can help developers focus on the business logic while taking care of API communication code.
Code samples generated with SDKs have a lot more work done on them. Since the SDK abstracts out request construction, none of the construction bits make part of the sample, making the sample look very lean. Such samples can easily fit in with your applications in a very scalable manner, you only have to add minimal communication code, since there exist mechanisms to access, manipulate and work around all the data fields, that go in and come out of an API call.
. . .
Concluding, we strongly recommend that developers make use of code samples to consume APIs. No matter what style, design, or approach. Code samples will help you get started easily and save you tons of time. While for most people, the simple HTTP snippets may do the job, it is sampled with more language structure that helps with real-world use and can fit in straight with your applications.
Again we emphasize the fact that the developer experience is a key driver for API adoption. APIs are meant to execute integrations, and the easier to integrate, the better the API. Luckily for you, we at APIMatic hold all sorts of expertise to help improve the experience you deliver to developers. Reach out to us today at Contact Us and let’s discuss what can be done to enhance your offerings today.