Have default arguments and decide their values according to the most common use cases.

Have default settings and decide their values according to the most common use cases.

Decide argument order by listing the most used ones first and grouping related ones together.

E.g. JavaScript
history.pushState
has bad default argument order:
state, title, URL
. Most API clients just want to add a URL to the history and they're forced to specify state and title.

Don't require copy and pasting of code snippets.

Avoid cumbersome inputs:

Check if parameter name is misleading.

E.g. In Scrapy 1.2, the send method accepts a "to" parameter as a list of strings. If the client passes a single string, the method will iterate over the string, trying to send emails to each character of it. Scrapy 1.3 fixed this by accepting both a single string and a list of strings.

Check if the user is instantiating something just to call the API. If so, consider accepting the wrapped value.

E.g. a function that only accepts file-like objects will force clients to use
StringIO
if they want to pass strings.

Check if it's possible to replace a custom type with a built-in one, or support both.

Draw away from the physical HOW nature of the solution to focus on the WHAT nature.

E.g. to make a simple Celery task, devs don't need to worry much about task queues, workers, message brokers, serialization, etc. They just need to use the
@app.task
decorator. The API is focused on the task definition, not on the tasks inner-workings.

Don't connect code implicitly by name or module. Use a registry or a registry-decorator:

E.g. django-admin
registry
, which supports both register by function or by decorator.

Avoid depending on order of method calls, try to use with-statement contexts instead.

Fail-fast: crap in crap out is not a Pythonic idea:

Raise
ValueError
if the library receives an invalid argument, like something that overflows, has a wrong format or is in a wrong state.

Raise
TypeError
if the library receives an argument with incompatible type, like a
duck
that doesn't
quack
. But don't do it inside a
if isinstance(duck, LibDuck)
or
if type(duck) == LibDuck
)! First try to call
quack
, then raise
TypeError
if it fails to give a clearer error.

5. Conclusion

My API tries to make the simple easy, the complex possible and the wrong impossible.