Devon Bernard: How to design a great API using Flask
Talk by Devon Bernard at the Plone Conference 2017 in Barcelona.
At Enlitic we study lots of medical data using computers. I hope to teach you how to create an api that developers and users love. If you are a backend developer, you can see the front end developers as your user. It should be intuitive, durable, flexible.
Your API should not surprise your users.
Hard coded variables are bad. Keep runtime variables in one central place, so users can find them. Make it so that you do not need to juggle with git to avoid accidentally committing a password. Search github for 'removed password' and you find over 300,000 commits with that commit message... Good: create a Config class, and DevelopmentConfig, and ProductionConfig and handle the differences there.
Use object relational mappers (ORM), instead of writing SQL, as you constantly worry about SQL injections.
How to standardise database migrations? A tool like alembic helps, to create a way to upgrade and downgrade. But please change the alembic file template to start with a date instead of a random hash.
Have a standard database seed, that users can use to get a database with standard content.
Use a requirements.txt file with all the requirements that you need. You can get packages from a git repository too. And you can install packages from the local file system, which is especially handy if you develop two packages at the same time, so you don't need to push changes all the time for package A when you yet know if they actually work with package B.
Is the setup code in your README working? If you can replace this by a single command, that would be better.
Create unit tests. You may hear:
- "But it wastes time." No, you still have to verify your code before you deploy it to production. And you do not just need to verify the new code, also the older code, as it may be affected by your change.
- "But writing it is boring." Manually clicking to verify that it works, is even more boring.
Database flush versus commit. A flush reserves a placeholder spot in the database. A commit saves records in the database. If you explicitly commit, and later something goes wrong, your commit is still in the database; usually you do not want this: either all changes should be written, or none at all. Also: use flush instead of commit when you need to get an auto increment id back: what is the id of the row that will be committed to the database.
Create an app factory, so there is one way to instantiate your app. This may also help for avoiding circular imports, like when your API depends on your database code, and the other way around.
Create blueprints. For example create one decorator for registering an admin view, and another for anonymous views. That makes it very clear which view is for what kind of user.
How to maximize uptime? Prevent downtime by not shipping bugs: have automated testing, have staging servers
Versioning: have a way to know what the used version is. Keep backwards compatibility. Communicate when you will drop a feature.
Get some analytics about API usage. If one of your front end developers is still calling a deprecated part of the API, detect this and send them an email.
First rule of endpoint design is: be consistent.
Document your API, or it does not exist.
A tool like Postman can be used to show the end points, and is helpful for debugging: paste the exact payload that gave an error on production.
Use Python profiling: what lines of your code take the most time?
Caching: store common responses in memory for quick retrieval.
Find me on Twitter: @devonwbernard.