Hacker News new | ask | show | jobs
Ask HN: Should we waste hours writing REST API clients?
3 points by ForeverAPadawan 1958 days ago
I recently joined a product where the teams manually write the client for each REST API. It's fine if we use REST sparingly but the product is a microservice architecture is so we have tons of API.

Spend hours writing the client, testing, and reviewing the code feels very wrong to me. To make things worst, the tests aren't good enough because there are no integration or contract tests. The client tests will still pass even if the API's URL is changed.

How ca we be more efficient?

I have some ideas but I don't know what's the best.

1. Be more efficient in writing the client

Our client code is written using a low-level HTTP library so just switching to a REST client library such as Square's Retrofit or Flurl will make us more efficient. We still need to write integration or contract tests (see Pactflow) though.

2. Use OpenAPI

OpenAPI is the WSDL of the REST world. The great thing about OpenAPI is it has tools that automatically generates client code. However, those generators are either buggy or may require us to customize the generator.

3. Use Postman or Apimatic

Those two products can automatically generate client code as well but instead of OpenAPI, you use their product to define the API specification. I don't have experience in using those products but my hunch is we will eventually want to customize the generator as well.

What's the best practice?

Do you prefer a hand-rolled client or generated client?

If you are hand-rolling your client, how do you test it?

Lastly, how important is contract testing in your product? It seems that I don't need contract testing to test the schema if I'm already using OpenAPI. Contract testing is still important though for replying the requests or responses.

6 comments

I agree with you that some generators are less mature. For example, we just added a Crystal client generator several weeks ago and we only have tests for posting a JSON body and getting it back to verify the result. Features like oneOf, anyOf are not yet supported (of course we welcome contributions to improve the Crystal client generator).

You can use customized templates (e.g. via -t option in the CLI) to meet your unique requirements. Another tips is to use code formatter such as https://prettier.io/, eslint etc to format the auto-generated code based on the style you want.

Please open an issue via http://github.com/OpenAPITools/openapi-generator/issues/new if you need help with OpenAPI Generator.

Disclosure: I'm the top contributor to OpenAPI Generator

Retrofit, OpenAPI, Postman, Apimatic... they old smell as "complexity not needed".

> Spend hours writing the client, testing, and reviewing the code feels very wrong to me. To make things worst, the tests aren't good enough because there are no integration or contract tests. The client tests will still pass even if the API's URL is changed.

There you got your answer: write a tiny wrapper/library that gives you a generic way to write the client. It's not rocket science exactly (so no need to add yet another framework). As for the tests, well, just add tests that you find meaningful.

> It seems that I don't need contract testing to test the schema if I'm already using OpenAPI

How's OpenAPI prevent you from writing tests? Unless you auto-generate the client code (but that's another bad choice imo).

Thanks for you reply.

Yes, the answer to your question is to auto-generate the client. But as I mentioned, the current generators has drawbacks. They are buggy, produces ugly code, and hard to customize.

How do you test that the client can actually still call the server when you make changes to the server? Do you have automated tests?

My actual recommendation is to use GraphQL instead. But I assume that’s not an option.

OpenAPI is the way to go. The official client generator libraries are fairly consistent in my experience, albeit the design patterns sometimes stray outside ecosystem standards.

Alternatively, you could add JSON-Schema validation & schema endpoints to the API’s, then use a library like QuickType to generate types. Or even setup sample requests for each endpoint then use QuickType to generate types based on the response JSON.

Agree with GraphQL. Spin up a Hasura instance, point it at Postgres and you're done.
We don't use GraphQL. I never heard of QuickType before so thanks for that.
I write by hand. Generated clients are ugly. Its not very hard to write those clients.

There are several auto-rest implementations that can generate stuff based on open API specification.

https://github.com/Azure/AutoRest

AutoRest is one of those buggy generators that I mentioned.

I agree that generated clients are ugly which is one reason why I'm hesitant. On the other hand, generators saves time and doesn't need to be tested (If you can trust the generator).

The other option that I'm thinking of is to create my own template for one of those OpenAPI generator so that the client code isn't ugly but creating a template is not a trivial task.

I'm wondering companies that has tons of REST microservices do it.

I don't have tones of micros but dozens of pretty big backends. I create all in PowerShell which is epic as it isn't compiled so you can ad hoc change it while you still have serious dev tools to do that. I am not talking only about 1 to 1 interface either, but little conveniences here and there too that are in the language or domain sprit.

I looked once into making it automatic but didn't make anything of it at that moment. While I appreciate the option and there is certainly a context where it can apply, I didn't use it so far myself.

Microservices should really have only a couple of APIs to be micro. Yeah, there are tones of them but it should be in the job description of the maker to implement client too, and do service automatic tests using it.

How often do you really write REST clients in the grand scheme of things? Are you sure you aren't optimizing for the 5%?
Yes I'm sure. The team that I joined surprisingly writes very little logic.

In order to implement a JSON GET and POST to one endpoint, they had to write 186 lines of code and unit tests so something is clearly wrong!

Even just being smarter on manually writing the client will save us a lot of time.

write some REST client factory infrastructure to generate stuff on the fly...?
You mean at runtime? We use a type-safe language and prefer to keep it that way