API Advice
API Experts - APIs to Support your Customers
Nolan Sullivan
January 31, 2023
TL; DR
- Building your API to be public (without private endpoints) pays huge dividends in the form of extensibility for your customers.
- GraphQL requires some extra legwork to cover the basics, but comes in handy for supporting more advanced UIs and apps.
- The Plain team is not only working on their APIs’ DevEx, but is trying to make it easy for customers to build their own API endpoints.
- For smaller companies, the qualitative feedback on your developer experience is more useful than tracking metrics.
Introduction to Plain
To warm up, could you give a brief overview of Plain (opens in a new tab) and what y’all are building?
Plain is the customer support tool for developer tools.
My co-founder Simon and I both found that existing customer service platforms were really hard to integrate with and fundamentally not built for engineering led products. Their APIs were afterthoughts tacked on and dumbed down to be made public. Their data models and workflows assumed that they were the primary store of customer data vs your own databases. These assumptions just didn’t make sense, especially in the developer tools vertical.
We wanted to build a customer service platform that is incredibly easy for developers to build with. The inspiration came from our experiences at Deliveroo (food delivery) and Echo, an online pharmacy. All of Plain is built API-first, meaning the API we make available to users is identical to the API we use internally. This means that there are no restrictions with what you can do programmatically. Anything you can do in Plain, you can do via the API. By dog-fooding our API this way, we end up constantly working on making it easier to build with and integrate Plain into your own systems.
Architecture of the Plain API
How does being API-first impact product development? Move fast and break things doesn’t work so well for APIs right?
Yeah, we have virtually no private surface area, which is a challenge since it means that everything we build is exposed. Things that are traditionally quite easy are harder, for example deprecating an endpoint, but the rewards are massive.
You have to move a bit slower at the beginning, especially when you're conceiving a new feature. It forces you to think quite carefully as to where you put logic and where you ‘encode’ your opinions if that makes any sense. For example, our data model (opens in a new tab) is something that is integral and is set in the API. A less clear cut case is certain opinions around how you should work as someone providing support to users. We do our best to make sure that opinions are more in our UI and the Plain app, and the API remains more generic.
As a result of this, we definitely have more in depth conversation around API design than you would normally see at an early stage startup. The payoff though is huge. When we onboard customers, and our platform is missing certain features, they are able to extend and just build the features themselves.
As an example, we had one customer using Discord to manage their community. We didn't offer a Discord integration. So they built it. It’s super cool, now they’re able to talk to users in Discord and sync it to Plain. That's where you reap the benefits of an API first approach.
One of the first decisions an API company needs to make is REST or GraphQL, Plain is GraphQL-based. What persuaded you that GraphQL was best?
We realised early on that most companies want to use customer support APIs to automate only small parts of their workflow. For example when they have an issue in their back-end they might want to proactively reach out to that customer and so they might open a ticket. In these early stages of companies, the requirements for customer support tooling are quite simple so we were very tempted to use REST. For simple API calls REST is typically way easier.
However at the same time we learnt that many people were looking for a productivity focused, power user friendly, support app. This is especially true for engineers as a demographic. Given this, GraphQL seemed like a much better fit. For building complex applications the schema stitching required by REST can be very painful and it was something we were keen to avoid.
Ultimately weighing both of these conflicting requirements we went for GraphQL. We felt like if we start with a GraphQL API, we could always add a REST layer on top later. The reverse would be more difficult to do in a performant way.
I’ve spoken to some other founders who started with GraphQL, before switching to REST. One of their criticisms was that the ecosystem of GraphQL tooling left a lot to be desired. Yes, What has your experience been?
There are some things that are great. And then there are some things that you expect to be good, but are terrible. For basic apps, where you just want to make some queries and run some mutations, you're going to have a great time. You make some GraphQL files, generate all of your types. It can even generate clients for you. There's lots of libraries that take care of things like caching and normalisation, definitely in the React ecosystem, but also in others. So that's all fine.
I think, where you start running into GraphQL weirdness and where the ecosystem leaves a lot to be desired is in terms of some more basic elements like error handling and complex input types. With REST APIs a 401 is an unauthorized request, you don’t need to explain that to anyone. And because you are not restricted to a type system you can do things that are just plain awkward in GraphQL (e.g. union input types).
How do you handle errors in GraphQL then?
Unlike REST, GraphQL is multileveled so certain problems become harder. Suddenly, you might be in a situation where the user has top level permissions to get something, but then doesn’t have permission for one of the nested elements. The way that you handle that error is DIY. There’s no (good) convention to follow.
We made some good and bad decisions in our early days. What helped was that very early on, we decided to write our own linting rules. GraphQL has an inbuilt tool that essentially parses the GraphQL schema when a request comes in, and with this, you can write rules to lint your schema. We write our schema first, so the linters enforce convention before any API code is actually written. And it’s not just syntactical errors, our linters enforce things like, every mutation must return an error, an error must be of this type, etc. It’s served us really well, because it means that we have very few debates on PRs around repeated API design topics.
What’s been the client reaction to the GraphQL API?
It's interesting. I think the more complex the use case, the happier users are with GraphQL. There's obviously still a bit of a gap between GraphQL and REST when it comes to awareness, and we do encounter companies who want to use Plain where the engineers have never worked with GraphQL, beyond reading blog posts. It's definitely a barrier, but not insurmountable; it just requires a little bit more hand holding. We help customers through this by giving them code examples and instructions on how to make GraphQL requests, how our errors work, that kind of thing.
Overall, we’ve found that as long as you’ve put work into developer experience and consistent API design, developers will pick things up quickly. And we are militant about the consistency and experience of our API. As an example, we provide incredibly thorough error messages, which is something that developers love. Once they start building they quickly realise: “Okay, this is solid.”
Plain’s API DevEx
That's a good segue. What additional tooling do you give to users to support API integration? What tooling improvements are you looking to make?
Before we dive in, it's worth knowing that there are two ways you build with Plain. There is the GraphQL API, which we've been talking about, but there’s also something we call Customer Cards (opens in a new tab). They are really interesting, because they’re the inverse of the traditional way that other support tools work. Instead of our customers calling us and syncing data (when the support tool is the primary source of truth), our users provide a URL, which we call to fetch your customer data which is then loaded up within the Plain UI.
This means that when your support team is helping someone they instantly have access to context from your own systems about the customer they are trying to help. What account tier they are, what their recent activity has been, how much they're paying you every month, etc.
We want that data to continue to live in our customers systems, so for the product to work, we need to help our customers construct an API endpoint which we can call. We’ve put in quite a bit of work into the DX of Customer Cards but I think our developer experience is a work in progress. It’s a fairly novel workflow, so it’s harder to do well than when trying to document an API.
How have you been trying to solve it so far?
I think we've made some good steps. We’ve built a playground that can assist users while they’re building which is quite nice, but there's definitely more to do. This data transfer is async. It's happening all the time. And so error handling and the developer experience here is actually a lot more challenging than a traditional API. We have to provide a lot more visibility on errors and monitoring. We need to know if you responded with something wrong, and why it was wrong. We then need to notify you that it was wrong and persist it so that you can fix it. The same goes for timeouts and anything else that’s unexpected. It’s complicated and we’ve not totally solved this experience.
Do you offer SDKs for the Plain API?
We haven't yet, but we plan on it. We’ve been relying on every ecosystem having its own stack, for generating GraphQL tooling. But we plan on offering SDKs to make integration easier, and to make errors easier to understand and parse. We really want to get to a place where, for a simple use case, you don’t have to deal with GraphQL at all. If you look at how Slack does it, it’s very good. No one is actually making raw Slack API calls, right? They're all using the client and the playground provided to visually work out how to construct messages and do things with bots and so on.
Any other DevEx challenges that you’re tackling?
I think on the API side, we’ve covered it, we really just want to make it easier and easier to integrate and use Plain. It's our raison d’être, I don’t think we’ll ever ‘finish’ working on DevEx
Outside of our API, we also have a chat solution (opens in a new tab), and we’ve spent a lot of time thinking about the DevEx there. If you’re using a React app and you want to embed chat into your product, it’s a UI-level integration, and that has its own challenges. If you look at how most support tools or chat providers allow you to embed, it's through a script tag. You add a tag, and a floating button appears on the bottom right. And that's your chat. In our world, we wanted to allow chat to be a bit more embeddable, to essentially look like it's part of your product and deeply look like its native. To do that, we've built a React package.
It’s been a tough nut to crack. Everyone has such specific expectations of how your embed should behave. And you're confronted with the multitude of different stacks and approaches people take. People do things that are super delightful, but unexpected. And that's where the complexity comes in when you are trying to deliver that seamless Developer Experience.
Are there metrics you track to measure impact of the work on your API’s DevEx?
Not yet, we're still so focused on every customer that metrics don’t really make sense yet. We track all the feedback we get meticulously. Even slight grievances with our API or our integrations we discuss thoroughly. That's a scale thing, largely.
What's also interesting is, by focusing on developer tools as a customer base, the feedback we get is really, really good. You get feedback similar to when an in-house engineer reports a bug. So. much. detail. So yeah, for us, feedback has generally been very, very specific and high quality.
What’s the Plan for 2023
What’re you most excited for in the coming year? Plain is now in a really cool place where we have moved on from the basics and are now getting really deep into some of the hard problems within customer support. For example, right now we're looking at managing triaging and SLA and complex queue management. It's going to bring with it, a whole host of other API integrations, to enable users to be in control of their support queues and prioritise some customer issues over others, and so on. I really can't wait to share our solution here.
We’re also going to be growing the team (we’re hiring! (opens in a new tab)) and onboard many more customers - it’s going to be an exciting year for Plain!