Ask HN: Best Way to Mock APIs in 2020?

71 points by HiddenCanary ↗ HN
I'm looking for a good way to Mock APIs for a sideproject, so far I haven't found any solution that has blown me away and I'm wondering If I'm missing anything.

I'm curious what people recommend for the best way to Mock APIs?

62 comments

[ 2.7 ms ] story [ 74.3 ms ] thread
I'm using Wiremock
Depends how advanced the mocking behaviour requirements are. For most projects, I find json-server sufficient.

Remember that perfect is the enemy of good enough. If you're looking to be blown away by your mock server you may never get round to building your product.

I would suggest having a look at Microcks (https://microcks.io) as a way to produce mocks from OpenAPI contracts, Postman collection or other assets...

Full disclosure : I am the founder of the project ;-)

Nice! Have you considered doing a free online SaaS version, rather than a self-hosted k8s version?
Yes it’s something we have in mind for next months or so.
> Keycloak 4.8.0 > MongoDB 3.4

That's a pretty heavyweight dependency list (and I'll leave my snide remarks about Mongo out of this)

Does your usecase involve such high security for your mocks?

Haven’t tried it yet, but https://www.npmjs.com/package/msw looks very interesting. It uses Service Workers in the browser to intercept requests to the APIs, instead of running a real mock server.

There’s support for mocking in Node as well for SSR and jsdom tests.

I've found mitmproxy (https://mitmproxy.org) in reverse mode really useful. I'm a mobile dev and when the backend work is still pending I usually mock the backend requirements by selectively patching or adding endpoint support, it can be used like so:

    mitmproxy --mode reverse:https://my.privateapi.com -s ./path/to/mockscript.py

This allows me to implement most of the UI and server interactions w/o being blocked by server work.
I've found Hasura to be great for this, maybe slightly more longer to set up but you get a full CRUD graphql setup for little effort.
Can someone explain to me what this is all about? Shouldn't you hide all your API calls behind an interface, and then mock that interface? Dependency inversion principle, depend upon abstractions and all that.
I personally am not a fan of too many abstractions.

If the only reason for abstraction is testing, then mocking an interface seems like a more valid choice to me.

The abstraction is there because in many static languages you will immediately have two implementations, the infrastructure one (database, API call, 3rd party) and the tests.
> I personally am not a fan of too many abstractions.

Then you're likely in the wrong business, since most of what programming is is dealing with the various facets of one abstraction or another.

This is definitely a valid approach to software development, e.g. in embedded development (where you still might need to call APIs).
For me, this is part of the design and development phase to help me plan the API structure and also to provide test API data mocks to the frontend, so that frontend doesn't have to wait on the backend to finish development before they can start.
What does mocking an interface mean, like a mock implementation?

How is that different then defining an API and then having stub methods on the front returning pretend data?

I think they mean wrapping the REST api in a class (aka "data provider" or "repository pattern") this way you've abstracted the HTTP request logic away from your application.

Both the API and the Mock implementation will require the same interface.

I've gone through this process a few times:

1) Join a project and fume about how they didn't write nice, clean, "testable" code.

2) Build some sort of integration testing framework that also mocks out REST API calls relatively cheaply (e.g. using recording/playback against a live system).

3) Realize that I can now refactor the code such that it is nice, clean and more easily "unit testable".

4) Realize that with an effective and easy to use, fast integration testing framework the lack of dependency inversion doesn't bother me nearly as much as it used to.

5) Wonder if dependency inversion is actually more of a hack to deal with the sheer utter crappiness of unit tests... and whether making vast architectural changes to code in order to accommodate the sheer ineffectiveness of the current state of test tooling is really the height of wisdom after all.

In a number of these projects there were noises about rewriting the whole damn thing in a different language (usually because management wanted to consolidate hiring around fewer languages), and it occurred to me that it would actually be kind of great to write tests where the entire implementation including the language itself could be swapped out without really changing the tests.

> it occurred to me that it would actually be kind of great to write tests where the entire implementation including the language itself could be swapped out without really changing the tests.

I think this basically already exists with "Cucumber" and behavior-driven development. The test definition is specified in a natural-language-looking DSL which supports a number of underlying languages. When you swapped out the system you would have to implement the step definitions in the new language, but the tests would remain valid.

Totally agree with you. I think the industry is going through an "emperor has no clothes" thing with unit tests and dependency inversion at the moment.

The creator of BDD gave this talk a few years ago, which resonated with me: https://www.youtube.com/watch?v=4Y0tOi7QWqM

> it occurred to me that it would actually be kind of great to write tests where the entire implementation including the language itself could be swapped out without really changing the tests.

This is exactly what I've been doing and advocating for for a while. Don't mock things like databases at all in your code. If you want to use a mock, use a "first class" mock like https://cloud.google.com/bigtable/docs/emulator.

The other thing is that TDD was born in a world where containers aren't the norm. All the pain of higher level testing really comes up from setting up an appropriate environment. If you're already using Docker or k8s, that pain is pretty much 0.

Some reasons not do to that:

- Now it's harder to navigate my codebase because I introduced an extra layer of indirection everywhere only for the sake of testing.

- If there is some difference between how the actual protocol client and actual upstream behave and how my fake interface behaves in test, my tests will be wrong, and I will find out when I push to prod. If my tests exercised the actual code that speaks the actual protocol to a fake upstream, I may have caught the issue in the tests.

- If I ever want to replace the process entirely with a completely different one, I must now throw away my tests. If my tests tested the end-to-end behavior of the system, I would be able to keep my tests.

What I find works well is to use dependency inversion to mock things out within your code, but mock out the transport layer.

I.e: If you have a "stack" like this:

- Application

- MainService

- ApiService

- HttpClient

What you might think of doing is replacing the ApiService with a mock, such that you can test your MainService's interactions with it.

You can do that, sure, and it's useful - but as you rightly point out now you can't find any bugs in your ApiService.

Instead, mock out the HttpClient (or if it's not Http, mock out the Socket). Typically because these kinds of things are at the bottom of the stack, they have very simple interfaces and are really easy to mock, and because the interfaces are so simple the mocks don't introduce much - if any - damage to the rest of your code around them.

There are significant advantages to doing it this way too, over using an external mocked API.

- Way faster

- More reliable

- Single codebase (if the mock API is some external NodeJS thing now you have to wrangle that too)

- You have perfect control over timing. For example, if you have a bug in your ApiService which happens when two packets get interleaved in exactly the wrong way, you can reproduce this easily. If you had a real HttpClient talking to an external process it's nigh impossible.

Good luck!

All good points, but you missed the most important part: in any mature programming language, you're not implementing the HttpClient yourself: it's a library, package, bundle, whatever. Which means that when you mock that you're not missing out on testing any code that you wrote, and the project that maintains your HttpClient (hopefully) has their own community-maintained test suite.
Have a look at VCR. It was developed for Ruby, and does exactly that: mock out the actual HTTP part of your HTTPClient.

It does this by first making the actual request and then storing that record in a plain YAML file (which you can alternatively generate yourself, by hand or from an openapi spec)

Have a look at "Ports in Other Languages" in their README to find the VCR port for your language, framework or stack.

1) Sure but that's the same as saying tests makes navigating the codebase harder because now when you "jump to usages" you find all the references from the tests. Probably fixable by tooling configuration.

2) For each unit test setup an independent mock of the interface for your subject-under-test. You should not create catch-all mocks for all your interfaces, unless it's to be used for offline work.

3) If you replace the process, as in the business process, you need to redo the tests as well yes. If you replace the implementation, you must throw away your "white-box" tests but should be able to keep your "black-box" tests.

1) I haven't actually seen a tooling configuration that gives you the experience of having the concrete type in your code when you write code that uses an interface (in e.g. golang or Java) for the sole purpose of swapping it out in a test.

2) Right. I agree.

3) It looks like your original post in this thread says "Do not make black box tests. Make white box tests"

1) Me neither to be honest, but would love to see it.

3) All right. That was not my intend. I think they both do different stuff, some projects need both, some only need one or the other.

Definitely you should do that, but it's still useful to have automated API tests too. That way you can upgrade client libraries risk free (and even automate these upgrades with tools like https://dependabot.com/). If your tests are green then you're good.
If you have a database - try this https://github.com/xgenecloud/xgenecloud

Automatically generates REST & GraphQL APIs within seconds from your database schema.

Here is a demo on how to create 8000+ REST APIs within 10 seconds - https://youtu.be/NtCwnlLudnk

Not just mock - you may even consider writing the full backend on it.

Im the creator - happy to answer any questions.

edit : added demo link

your mother was a SOAP request
I feel like that might have been better mockery for 2010 than 2020. While there’s something to be said for mockery that goes over someone’s head (so that you get to feel smugly superior, and they just feel vaguely discomfited because they can tell you were deriding them, but they’re not sure how), it can also be nice if they understand, so that they know just how insulted they should feel.
Don’t bother with mock APIs tbh. I assume you’re trying to unit test the front end?

If anytime, write integration tests using something like selenium or whatever the latest hotness is.

Mockito exists as an option
Api-framework works really good for this
If you like wiremock, try https://intervene.dev - config in TypeScript with automatic https and CORS.

Open for questions + feedback [author]

https://miragejs.com/ is a great complement to frontend first development. Some folks on my team use it and love it. I tend to dev from back to front so I don't run into the need as much. If I do I typically just mock a JSON response in my frontend call function. Depending on the need I'll sometimes set the call to return an error response as well.
I use Mountebank extensively and it's a pleasure to use.
There are lots of variations depending upon your use case.

For unit testing and CI you may want mock objects that are implemented in the same language as your code. Google search for "mock object <language>". That's where you'll find Mockito (Java) or Mocha Spy (NodeJS) or Testify (golang). This list never ends.

Specifically for unit testing of a UI, you may want your browser driver to handle this, ex: Cypress has built-in support for mock AJAX endpoints. https://docs.cypress.io/guides/guides/stubs-spies-and-clocks...

If you want an endpoint you can call, Postman has a feature for this, there are several others like this in the comments (JSON Server, mmock, mountebank, etc.). https://learning.postman.com/docs/postman/mock-servers/setti...

If you need to capture traffic, check out goreplay or mitmproxy: https://github.com/buger/goreplay https://docs.mitmproxy.org/stable/

There is a whole class of "VCR" projects for recording traffic, these tend to be language specific (VCR is in Ruby), but there are ports to other languages: https://github.com/vcr/vcr https://github.com/bblimke/webmock

The vendor products tend to be labelled Service Virtualization. I used to work for one of those companies, ITKO, we were acquired by CA Technologies (now Broadcom) in 2011. There are vendor products from Micro Focus, Tricentis, Broadcom, Parasoft, etc.

It's important to think about your use case: local development, unit testing, CI, integration testing, performance testing, recording vs. programming, protocol support, payload support, etc. Many of the tools focus on just a subset of these areas.