Why use raw HTTP calls instead of SDK?

When I recently opened a pull request at work, I got a following question: Why are we not using SDKs more often?. This also reminded me, that I was asked on my documentation speech, how useful the addons like SDKs and so on are.

Since most of my thinking on the subject is not specific to the circumstances of my company, I though I would share it here on my blog as well.

There are generally a couple of reasons, why I prefer the raw HTTP calls to the SDK by default. That does not mean, that I will never use the SDKs, just that whatever the SDK is offering will need to be better then the pain of using the raw HTTP calls.

Please, do not take this as an excuse to make the HTTP calls to the API more of a pain in the ass. Pretty please? With the cherry on top?

I am asking this, because the main reason why we use SDKs in some cases are horrendous authentication schemes. So, please don't do this, just so the people will use your SDK.

Let us now go to the actual reasons.

The first reason is the consistency of the code. Each SDK has their own way of dealing with the authentications and later calls and data. So the code for each integration will look as the code of that SDK. This means, that each new person would need to get used to each integration separately and not being shown around just once and they be able to deal with all of them.

Sure, the more integrations one has, the more this point is important. If one only needs to deal with one integration, then this point does not matter.

But just as HTTP calls are more consistent in the written code, they are also more consistent in the mental models. There are not a lot of moving parts in the HTTP calls, and for each HTTP call, they are the same. For requests there are usually the URL, the verb, the headers, the body. For response one needs to add an HTTP code to this as well.

But each of the different SDKs have different mental models around this. In order to make this simple thing easier, they try to provide their own way of dealing with this. But this means, that each time the mental models for the each SDK needs to be loaded to the brain and then used.

Also, these mental models are not always portable. They are usually applicable only to the specific library, which can only be used in the specific circumstances. Not the best way to gain any generalizable skills.

Even if using the library like the requests for Python to make calls, as least this knowledge can be used for many other types of problems.

The third one is also related to this - since each SDK have their own way of dealing with things, then it makes it hard to do some generally flows.

We might be in a bit unique situation, but our team had developed and now needs to maintain over 100 of integrations. It makes it a lot easier, that we have a general flow for some situations.

For example, with HTTP code 401 (Unauthorized), the code either finished with the code indicating the need to authenticate again and calls the authentication code, or finished with the message about the invalid credentials. Or the HTTP code 403 (Forbidden) maps to the insufficient privileges message. There are other examples like this, but this gives the taste of it.

But each SDK have a different way of expressing the errors. If one is lucky, they return this status and the objects only need to be translated from one to another. But in some cases, the SDK only return custom text messages, indicating what is wrong.

In which case, this handling code needs to be written for each integration separately. And hope that they are documented somewhere, otherwise there might be errors, that the code is not handling.

Also, while I don't really care about the typing of the code, using uniform objects makes it easier to use the types in the code. Which gives HTTP calls another point over the SDKs. Unless the types are already present in the SDK.

But I still see SDKs using the callbacks (JavaScript), so I would not depend on this.

The next point is the security. The more libraries one is using, the more libraries one needs to be checking and updating. And even if one is using some sort of automatic system, like Synk, or depend-bot or renovate or any other solutions that might exist there, somebody still needs to address these issues.

One way of how to control this is to only use the libraries, when this pain is smaller than the pain of going without this library. And most SDKs don't clear this barrier.

Sure, one also needs to be careful about the 'not invented here' syndrome, but thinking about the maintenance when writing the code from the start could help avoid this.

I think this is also my main point for this entire article. It is important to think about the future person, that will need to maintain this. And think about what will be easier for this person.

And in the most cases, the SDKs do not pass this check.

I also think this is a good way of thinking about all the code.