'It's an interesting question!
Some of the things that make APIs "bad" are that they require verbose,
awkward code to do simple things. This happens for various reasons.
In IndexedDB's case, part of it is because the API was created before
promises were standardized, so doing any async operation requires a
lot of tedious boilerplate. Another problem with IndexedDB is it
assumes you need all the complexity and power of a full database
engine, so for example you have to understand transactions and
upgrading between multiple database versions before you can simply
write something to disk and read it back.
Classic DOM APIs are often bad because of simple verbosity and
awkwardness, especially compared to something like jQuery which showed
us a better way. Although it's getting a little better now, with
methods like before(), after(), replaceWith(), and remove(), before
you had to do annoying things like el.parentNode.removeChild(el) to
remove an element. And all the names are just absurdly long, like
el.addEventListener instead of jQuery's $(el).on.
Another problem is that sometimes "weird objects" show up in web
platform APIs, like "fake arrays" that are missing common methods like
map, filter, etc.
Yet another problem is people not designing APIs for idiomatic
JavaScript, e.g. making them super object-oriented because they have a
Java background. My favorite example of this is the FileReader API,
which involves constructing this FileReader object and configuring its
options in order to read something out of a Blob object. That whole
setup could have been replaced with a simple set of methods like a
promise-returning blob.asText(). We might still try to do that; then
people won't have to use FileReader any more.
I feel that we're doing generally better these days, with APIs like
service worker, fetch(), and the cache API being IMO fairly
well-designed. It's a game of constant vigilance though. A large part
of my job is trying to oversee new platform APIs and make sure they're
good, not bad :).'