Hacker News new | ask | show | jobs
by danpalmer 1918 days ago
We've just started developing a Shopify integration and used their Python API library because we're building it into an existing large Django codebase, and I've been shocked at the quality of the API library. We're now aiming to rewrite the bits we need.

- `import shopify` makes an API request. If their API rate limits you, your server will probably crash. This happened to us in production.

- That API request gets a dynamic list of supported API versions. If the version you've hard-coded in your app (because it's what you support) is no longer in that list, it will raise a VersionNotFoundError and your app will probably fail in some significant way.

- There's no connection persistence. Every API call sets up and tears down a full connection, a noticeable performance impact.

- Internally the library uses a lot of global state, it's certainly not safe to use in async code – too easy to use the wrong credentials on a request – and I suspect it's also not thread safe.

- Despite having something called a Session, very similar in documentation to a requests.Session or httpx.Session, it's neither, it's just a container for some creds. No sessions are available at all.

- It's mostly a wrapper around Pyactiveresource, which appears to have a lot of similar issues – internal state that's hidden that causes things to not work as you expect.

I suspect that the Python library was developed by Ruby engineers, some of the practices are things I've seen in Ruby but that just don't fit into the Python ecosystem.

From what I can tell their API deprecation strategy is quite hostile to developers.

I think it would be difficult to build what I'd consider to be production-grade services on top of the library. This is in stark contrast to others such as Stripe's API/libraries which are fantastic.

7 comments

> `import shopify` makes an API request.

Especially for a company that prides itself on great API design, this is head scratching.

‘shopify.Init()’ seems like such an obvious solution

The fact that you can have side effects on imports, and that a lot of libraries relied on side effects on import, was one of my biggest sources of frustration with Python
What other packages have you seen abusing import side effects?

Shopify is the first one I've seen, so I don't think it's quite as common as you are implying, but I'm curious to know what other bad behavior you have found

Sometimes libraries do a switcheroo where they run interpreted code on startup to locate the "real" implementation in a shared object, and then load that and replace themselves with it. I'm not sure this is really idomatic, but here's an example of what it looks like from OpenCV:

https://github.com/opencv/opencv/blob/master/modules/python/...

Not GP but I've been bitten by plenty of first-party implicit side-effects, both intended (by not me not now) and not (by me or otherwise).
LaunchDarkly does. It does some querying behind the scenes and added a significant delay to the coldstarts of our lambda apis
Their PHP one had a similar shell_exec after-affect (c2017), caused some odd things in our logs but we backed away from that solution
SKiDL (circuit design library) does this to a very large extent...

https://github.com/xesscorp/skidl

An example in the standard library is the antigravity package. While it is an inside joke it still requires a HTTP transaction similar to the shopify package import.
Can’t you do this with any interpreted language? On ruby your import could redefine anything.
Is there any real way around that? The import keyword might as well be renamed to exec.
I think this depends on how brutal the workarounds you will accept are
Almost all 3rd party SDKs should be avoided like the plague as a general rule. I have a much better time taking control of the HTTP requests to 3rd party APIs
I don't really understand why developers use SDKs/libraries at all when the RESTful APIs are easy enough to consume directly.
Handroll marshalling for every payload, handle the auth sequence, check arguments, endpoint semantics, sort out sparse versus full entity patching mismatch, build in retry that matches status codes, and do this for every endpoint.

If you're moving fast, you don't have time for this. Especially if it isn't your core competency / core product.

> sort out sparse versus full entity patching mismatch

I thought we are talking about Shopify... where people browse and search products, buy products, make a transaction, and review past orders/invoices/transactions.

Where does PATCH fit?

Customers do all that, but admins also upload and edit products, orders, and other entities typical of an eCommerce model. I’m assuming it’s that?
Shopping cart is an obvious one.
Most APIs there's usually only a handful of endpoints. There's never an auth sequence, just a simple API key. Patching is exceedingly rare. I don't want an SDK to auto-retry. Interacting with an API actually usually is or needs to be a core competency.

I still think the major promise of RESTful APIs is avoided by the prevalence of SDKs.

Depends to be honest. Where they expose OpenAPI docs it's dead simple to generate the models from that. In .NET I use those plus Refit and boom. Now I have full control and it took barely any time.
I like this approach too, but a non trivial amount of time the models come out wrong. I assume this is because of bad openapi docs, but maybe I'm wrong.

What do you use to consume the openapi docs and generate models with?

Haha yes we got bitten by that on a recent project but it resulted in a minor bug we patched pretty quick. I don't mind taking that downside.

Can't remember the exact name of it but it's one of the open API generators that supports all the major languages. Unfortunately the csharp and dotnet core generator generates clients with RestSharp which doesn't use the almighty HttpClient, so I consider them unusable, but it generates the models faithfully. If it so happens the open API spec is wrong that's unfortunate. Though usually if they have an SDK I just use the models directly from the SDK! That's the absolute sweet spot for me. Especially if their SDK is generated off open API it probably stays perfectly or acceptably accurate with incentives to correct any inaccuracies.

One word answer: Types.

If you dont use a language with strong type safety the benefits are less.

For instance the OpenAPI3 (Swagger-NG) standard. It allows the typing/schema'ing of the JSON bodies. It also provides a bunch of generators[1] that can be used to generate client libs. And when the languages of the client libs permit it, those libs come with lots of type safety and greatly reduce boilerplate.

1: https://openapi-generator.tech/docs/generators/

One of the reason I don't like types.

There really shouldn't be much boilerplate to passing JSON around back and forth.

I also find it frustrating as a python / django / vue developer working on Shopify apps.

The python api doc is not good. I'm always not sure about how to call the api. I can only leave an issue on GitHub.

The ecosystem obviously leans toward react and ruby. The examples are not suitable for me most of the time. The tooling like CLI, example will not include what you need.

Use Polaris for your UI? Sorry, it's not supporting vue. You need to build it with npm. Only for react. But I want the easy way to work with CDN

Need python examples on the latest session token auth? Sorry, there is no such thing. I spent 2 - 3 weeks working on it (and still working now). What I got are the workflow diagram and step instructions. Welcome back to the uni!

But the session token auth is mandatory for all new apps. You must use it NOW!

Developer / Partner support? Please provide a store id to identify yourself. But I clicked the link INSIDE the partner portal. (Half an hour later, still got nothing. ) I spend an hour and get nothing most of the time. The worst thing is that they answer you 'Sorry, I don't know or it is not feasible' with a thousand word long email.

Being a python developer I am interested to know more. Are there resources you use to make the app? Do they provide rest api?
> From what I can tell their API deprecation strategy is quite hostile to developers.

Yes, every 3 months you need to revisit the API. It's good and bad. It means that if you're casually developing an app, this will consume a lot of time. Good because if forces you to update and keep your app relevant.

Well, yeah, but why do they need to make changes to their API so frequently? This is both developer and business hostile. I get extremely pissy when paying for a service where the provider regularly dumps non-value-adding work into my product backlog that sucks up time I could invest in more valuable areas.
OP is wrong. While there’s a new version of the API after few months, they support older versions for 18 months. They have versioning.
Correct, but if you make one call to a deprecated api, your app will be unlisted immediately
This is very poor from Shopify's perspective if that's the case: API can change as often as they want,but each new version comes as a new thing with its own documentation and so on,while the old ones stay there for a long time with whatever functionality was supported. I did receive some emails from Salesforce, saying they will be retiring version 7 of their API soon. Guess what, their current version is 51.
>Good because if forces you to update and keep your app relevant.

The real question we should be asking is, is churn adding value? I understand security updates but otherwise you can only improve the wheel so many times before it just becomes a waste of time (decreasing marginal returns). Software engineering _badly_ needs a concept of finished version and mature software. Often there is very little gained from a new framework every few months besides assuaging the egos of a new generation of developers.

> Software engineering _badly_ needs a concept of finished version and mature software

It used to be like that. Back before the expectation of regular updates, in fact back before downloading updates off the internet was considered desirable or even feasible, when releasing a patch was a borderline embarrassing admission that we didn't get it right the first time, software shipped on CD and the version that shipped was understood to be the version installed on the vast, vast majority of customer systems, so it had better be a finished product or there were reputations on the line.

Keeping your app relevant because the API it is built upon is unstable or has breaking changes is hardly a good.
"Good because if forces you to update"

That's the opposite of good.

> forces you to update and keep your app relevant.

"Relevant" to whom? As long as the store is selling stuff, it's highly relevant to the buyer and seller.

> Good because if forces you to update and keep your app relevant.

That is the consumer being "good". There is nothing regarding the provider there which is good.

> forces you to...

Never good.

Python forces you to indent.
Python is a great language for other reasons. Forcing you to indent isn't one of those reasons.
The statement wasn't on greatness. The statement was on "never good."

I think the programming community largely agrees that indenting is good. If something is forcing you to do something that is good, then it definitely doesn't fall into the category of "never good."

I can't think of a single time in the nearly 10 years of using Python daily that made me want it to operate differently w.r.t. indenting.

The programming community most certainly does not agree that "forcing you to indent the way the language designer decided you should indent" is good. There are lots of programmers that disagree with it. There are lots that agree with it. But the "programming community" as a whole has certainly not come to a consensus on it.
When you're testing fragments of code by copying from one place to another to run, such as just pasting directly into a shell, indenting is an unnecessary hassle.
Indenting is good. (as is, generally, being consistent and readable)

Indenting as code always struck me as a horrible idea. Better than, say, type coercion... but still horrible.

So code linters, code formatters, and style guides used in any well maintained code base.
Many of the pain points in the OP and comments are things we're addressing at Saleor. Open Source First with Cloud option Exclusive focus on GraphQL API API-first rather than headless as an afterthought Solid Documentation *Responsive community and team Fastest growing oss commerce platform on gh. Proven at scale. For a headless solution that prioritizes dev experience above all else, please check us out.

(Full disclosure, Saleor Head of Growth. A friend sent me this link. Yes, my account is new.)