API Experts - APIs that Move Money
January 4, 2023
- It’s great to have an industry standard like OpenAPI for API development, but the flexibility in the spec has made true consensus elusive.
- If you’re building an SDK, the goal is to make it as easy as possible for users to make their first request.
- When you’re building in a regulated space, it’s important to offer a sandbox to help customers build quickly and safely.
- At Stripe, maintaining the API platform required a large team. In the last couple years this API DevEx space has started to take off and democratize API product quality. It’s a welcome development for people who care about this type of stuff.
Jack Flintermann Reed is an engineer at Increase (opens in a new tab), a company that provides an API which enables developers to build a bank. Jack spends his time thinking about how to make the Increase API (opens in a new tab) enjoyable for customers to use, and scalable for the Increase team to develop. Before he joined Increase, Jack was a staff engineer at Stripe.
Increase offers a REST API to developers, how did you decide that was the right interface?
At one point we tried offering both a REST API and a GraphQL API but we found operating the GraphQL API to be challenging and ended up winding it down. There was a cognitive overhead for the user that was hard to overcome: like, welcome to our GraphQL API, here are all the libraries you're gonna have to install before you get started. And you know, GraphQL libraries across different programming languages have really varying quality. The Ruby GraphQL client is okay for example, but other languages not so much. And then, client aside, you need to learn all these new concepts before you can even do what you want. For users it’s like, “I just want to make an ACH transfer here.” And that’s the really nice thing about REST. Every single language has an HTTP client built into it. There is no stack required to get started. It is really simple. You can play with a lot of REST APIs in the browser’s URL bar if you want to. And that makes getting started with documentation and integration a lot simpler. So the barrier to entry is lowest on REST. And, that's not to say it doesn't come with plenty of issues of its own, which I'm sure we will get into. But we think it’s what is right for us right now. Ultimately, one of the reasons we had to give up on GraphQL is we realized that because of the level of DevEx we wanted to give users, we only had the bandwidth to do one public API really well, and so we were forced to pick. I suppose that is one of the main reasons Speakeasy exists, right?
Yes it is. And to explicitly state something that I think you're implying, the developer tools that are needed to support a REST API and a Graph QL API, are fairly distinct?
I think so. And again it’s partially down to the maturity of the technology. For example, when we think about the SDKs that we want to offer to our users, one of the things that we feel pretty strongly about is not having any dependencies. And that's just not possible with a GraphQL API. Like, you're not going to write your own GraphQL client, you're going to bundle something in. But that exposes you to problems where there could be a version conflict with the client you've pinned yourself to.
And with REST, it's at least possible to avoid that problem. We've recently written a Ruby SDK for our API, and we're pretty happy that it’s got no external dependencies.
Are you versioning your API, do you plan to?
We don't version the API yet. We are small enough that we just haven't had to do it. We inevitably will have to, but I'm trying to delay it for as long as possible. It's a lot of work, and there's just not a canonical way to do versioning. So I'm cheating by just making it a problem for my 2023 self. We do occasionally deprecate things, but we're close enough to our users right now that we can just reach out to them. And for us right now, we're in a phase where the API is mostly additive, we're still building out the core resources. The deprecations we’ve done have been at the API method level. It’s easy enough for us to handle. The real nightmare is when you want to take out this field from this API response. And you have no idea if anyone is relying on it or not.
That's the one that sucks. And fortunately, we haven't had to do that. And we are trying really hard to not have to do that. A good way to save yourself trouble is by being really conservative about what you put in your API to begin with.
That's our approach right now, we want users to pull features out of the API. Yes we have the data, we obviously could expose that field, but until a few people are asking us for it, we are not going to put it into the API.
Do you like OpenAPI? Does your team maintain an OpenAPI spec?
I'm glad it exists, we publish an open API spec. And it is going to be the foundation of all of the stuff that you and I are talking about right now. We’re going to generate our documentation and clients from our OpenAPI spec. That said, I think it's extremely difficult to work with. So, I'm glad that there is a standard, but I wish the standard were better.
I think OpenAPI has taken this nice big-tent approach where anyone can describe their API with OpenAPI. But there are some crazy APIs out there, right? And so there are a million features inside OpenAPI.
I’ve been working in the API space for a while and it took me some pretty serious effort to try and understand OpenAPI and how to get started. There are a lot of features you could use, but there’s no easy way to separate out the set of features that you should use.
One example that I always harp on is null. If I have a nullable parameter, there's at least four ways to represent that in OpenAPI 3.1. But not every library implements the full OpenAPI specification, so the tools and libraries that I want to have consume my spec might only support a certain way to represent null. So while it's all well and good that you can represent null 4 different ways, if you actually use two of them, none of your tooling will work. And that type of opinionated information is extremely hard to pin down.
Do you generate your OpenAPI spec from code?
Yeah, we have this cool library we use internally, I’m pretty proud of it. If I had infinite time, I think there's probably a great little framework that could be pulled out of this. Increase is written in Ruby, and we use Sorbet (opens in a new tab) from Stripe (a type checker for Ruby). We’ve built a Domain-Specific Language, you might've seen other companies do something similar, where you can write API methods using a declarative syntax. You say, this API takes a parameter called, “name”, and it's a string, and this one takes “age”, it's an integer. And this library then goes and produces a couple of outputs. On the one hand, it gives you an OpenAPI spec. Then on the other, it handles all the shared application concerns around parsing requests: error messages, type suggestions, etc. Everything you don't want to force individual developers at Increase to be thinking about. It will spit out into the application, a parsed, strongly-typed, parameters object. And so, the developer experience is pretty nice for folks at Increase. If you add a parameter, it just shows up in the docs and the SDKs without you having to do anything, which is the dream. It’s an all in one generator for artifacts.
You mentioned earlier that one of the guiding principles in your SDK generator development was limiting dependencies. What other principles do you have for SDK development?
We want to make it very easy to write your first request. And to achieve that, the majority of the library should be type definitions. It should list out the API methods and each of those should have a nice type definition that makes it easy to autocomplete when you’re working. Then there's the other piece of the SDK, sort of the core, which actually handles making the requests. That should be very tunable, and ultimately, swappable.
I worked at Stripe before coming to Increase. And at Stripe, when we were integrating with an external service, we’d rarely use the official SDK, because of all the things, like internal service proxies, that we would need to configure in order to safely get requests out of the stripe infrastructure. It would have been really nice to say, we have our own way of making HTTP requests, and I'm happy to write adapter code to conform to your interface; I'll just kind of ram it into your type definition. That would have been the sweet spot for us, and that experience has influenced our approach at Increase. We have written it to be the kind of SDK we would have wanted to integrate with.
If people are interested in this stuff, there's a really fantastic blog (opens in a new tab) by a developer I used to work with at Stripe, Brandur. He’s a prolific writer and often dives deep on the minutiae of good API design. If people haven't read it, they should.
What about DevEx for APIs? What’s most important?
There's a lot of different things that go into it. The first piece is documentation, trying to make your system legible to others. Good documentation focuses on the concepts you need to know, without overwhelming you with information.
I think at Increase, we do an okay job of this right now, but it’s one of the things I most want to improve about our own product. We’ve got the API reference, which is great - it's the index at the back of the encyclopedia, but it's not enough. It’s really important to know the typical path for building an integration with your API and then communicate: “here are the five things you're going to want to go and touch first.” I think that initial communication is more important than almost anything else to me when it comes to the experience of using an API. And again, I'm a major type system enthusiast. And that’s because when you get it right with your developer tooling, your documentation can just flow into the developer’s text editor. And to me, that's the dream experience. But it takes a lot of work to get there.
That’s all concerning understanding the API, and doing the initial integration. There’s also the ongoing operation of the integration code. And that’s about answering questions like: How do I see what I've done? Did I make a mistake? How do I debug my mistake? That's where tools that enable you to see the requests you've made are really useful.
It’s hard to say what specifically constitutes a great developer experience, but a lot goes into it, and, fortunately for developers, the bar for what great means gets higher every year. Tools are getting better.
Are there other companies that you look to as a north star when building DevEx?
So, obviously Stripe gets a lot of praise for being the first company here. They were so much better than anything else at the time they started. And I think if you look back at the things that they did, a lot of them were really small touches. Things like copy/paste for code examples, right? Small, but really nice. Another one was, if you misspell an API parameter, giving you an error message that suggests the correct spelling. It's not rocket science. But those little things add up into something really nice. I'm obviously really biased because I worked there, but I still think Stripe is the best. I learned a lot from my time there, so it’s still the company I model after most. Besides Stripe, I wouldn’t say there’s one company that is necessarily a North Star. I have a loose list of peer companies. When I'm doing research, it’s usually because I’m grappling with the fact there’s a lot of under-specified things in building REST APIs and I want to see how others have handled it before I make a decision. I’m not interested in features or clever things that they’ve done that I want to copy, it’s more about checking whether there is consensus on a topic. If there is a consensus, I want to follow the precedent so that it is not surprising to our users. However, I'm usually disappointed. There often isn’t consensus on the way to do basic features in REST APIs. Which is funny and sad.
Incidentally, that's one of the nice things about GraphQL. They tell you how to do everything. It’s very proscriptive.
How is the value of Increase’s investment in DevEx measured? Are there metrics you want to see improve?
It's not really obvious, it's much more of a qualitative metric. We open a Slack channel for every new user, and we stay pretty close to them during the integration. We're not quite looking over their shoulder, but if we could, we would. And so, we're pretty sensitive to how that kind of first experience goes. We try to get feedback from pretty much everybody who goes through it. And so, it’s just things that we see mainly. Like if everyone is running into a similar stumbling block, we prioritize removing it. It's not like there's a KPIs dashboard on a wall. It’s things we see in conversations with users every day. It scales pretty well if the whole team pitches in on working with users. Slack Connect is a pretty great tool.
You guys are a startup, but you’ve been investing in your API’s DevEx from the get go. Was that a conscious decision?
Yeah, again, It's pretty informed by our experiences at Stripe. It’s also a consequence of the space we work in. We offer a set of banking APIs, and traditionally banking API integration is pretty laborious. With a traditional bank, it'll be an extended contracting phase, then you get to a signed contract, and finally you’ll get this PDF for docs. And then the integration involves sending files back and forth between FTP servers. It’s not fun. And so as a startup in the space, our goal is to make the integration timeline as short as possible, and as dev-friendly as possible. Even in the cases where we need a signed contract before a user can go live in production, we enable their development team to build while that’s being sorted.
Ya, please expand on that a bit more. As a banking API there’s inevitably compliance. How do you guys balance integration speed with compliance?
It depends on the use case - we can get most companies live in production very quickly. And then there are some that require more due diligence. That's where tooling like an API sandbox is helpful. With a sandbox, you can build your whole integration. The dashboard experience looks and feels real, and so you can just build out what you need while the legal stuff is handled.
We’ve learned that it takes a lot of work to make a good sandbox. We have to do a lot of weird things to simulate the real world. For example, in the real world there's several windows throughout the day when the federal government processes ACH transfers and they go through. So if a developer makes an ACH transfer in the sandbox, what do we do? Should we simulate that happening immediately, or wait like the real world. There’s not always a right answer. We actually built a simulation API, where you can simulate real world events in all kinds of tunable ways. And so that has been fascinating. It made us re-architect a fair amount of code to get it working.
In the longer term, are there any big changes you think are coming to the way people interact with APIs?
Haha I think this question is above my paygrade. It's not quite the lens through which I think about things… But, I guess one thing that is interesting is how many companies are starting to pop up in this API DevEx space. It seems like there were zero people working on this stuff two, three years ago. Now there's a few.
Before I joined Increase, I was thinking I might start a company of my own in the space. One of the ideas I was kicking around was a platform for webhook delivery. I've seen a bunch of new startups doing that over the interim 2 years.
I think that’s cool. The size of the team that maintained these things at Stripe was big. It required a lot of manual work. And so it's cool to see that level of API product quality being democratized a little bit. Like I said, I think the quality bar will continue to rise, and it has risen. But, today, it's still a pain. It still takes a lot of work, you really have to care about it. I'm hoping it becomes a little bit easier to buy off the shelf as time goes on.