Uncategorized

Organizing a web app with Python Flask and AngularJS

Here at Jana, we have several microservices for many different applications. We typically write our back-end as a RESTful API in Python, and we usually use Python Flask. Often, these microservices need a web UI, and when they do we usually use AngularJS.  Since we do this so often, we’ve spent a lot of time thinking about what the best way to structure an app like this is. Since building a web app with Flask and AngularJS seems like something that a lot of people would want to do, I thought I’d share how we do it here.

The basic app structure:

├── app
│   └── api
├── client
│   └── src
│       ├── directives
│       │   └── sample_directive
│       ├── images
│       ├── js
│       │   ├── filters
│       │   └── services
│       ├── less
│       └── views
│           └── view1
├── config
├── integration_tests
├── lib
│   ├── models
│   ├── repositories
│   └── serializers
├── migrations
│   └── config
└── tests
    ├── app
    │   └── api
    ├── helpers
    └── lib
    ├── repositories
    └── serializers

I removed a bunch of stuff that we have in our apps that’s pretty specific to how we do things, such as deploy/continuous integration config, logging, and some development and ops stuff like githooks, fabric/setup scripts, etc.

Working through the structure from the top:

/app

Where all of the endpoints are actually defined.  It looks like this:

├── __init__.py
├── api
│   ├── __init__.py
│   └── my_sample_api.py
└── jana_seed_app.py

We typically namespace the api along with the general model and repository (where all the database interaction lives) associated with it.  You can see this is also where we setup auth, and we configure the Flask app in jana_seed_app.py.

/client

Where the AngularJS app lives.  This is mostly inspired by Angular Seed, but you can ultimately set this part up however you prefer.

├── Gruntfile.js
├── bower.json
├── karma.conf.js
├── package.json
└── src
    ├── directives
    │   ├── _main.js
    │   └── sample_directive
    │       ├── sample_directive.html
    │       ├── sample_directive.js
    │       ├── sample_directive.less
    │       └── sample_directive_test.js
    ├── images
    ├── index.html
    ├── index_dev.html
    ├── js
    │   ├── app.js
    │   ├── filters
    │   │   ├── _main.js
    │   │   └── my_filter.js
    │   └── services
    │       ├── _main.js
    │       └── my_service.js
    ├── less
    │      ├── helpers.less
    │      └── main.less
    └── views
        ├── _main.js
        ├── template_inner.html
        └── view1
            ├── view1.html
            ├── view1.js
            ├── view1.less
            └── view1_test.js

This structure was heavily influenced by the Angular Seed project, but we’ve changed it over time to fit our needs.  We install dependencies with NPM and Bower.  We use Grunt to build our app, but you could pretty easily swap out Gulp, or whatever your preference is. We use a bunch of Grunt plugins like Babel, LESS, html-build, and more.  We run our JS unit tests with Karma, so that’s also wired up using Grunt’s karma runner, with a config file living in karma.conf.js.  Most of this is all pretty standard if you’re used to using AngularJS, especially if you’ve messed around with Angular Seed.

There are a lot of other files and folders that get built by NPM, Bower, Grunt, and Karma, and I’ve left those out here.  That explains why there’s only one subdirectory (/src), since everything else gets built dynamically.  There are a couple of things we’ve done here that I think are interesting, but I’ll save our detailed AngularJS setup for another post.

/config

├── __init__.py
├── app_config.py
├── application.py
├── development.py
├── production.py
├── staging.py
└── unittest.py

Contains app initialization details and environment variables.  We also setup app-level shared services here like logging and tracking.

/integration_tests

This one is pretty self-explanatory, but we setup the test environment in jana_seed_test.py, and then write actual tests in test_cases.py (which gets broken up at scale).

├── __init__.py
├── jana_seed_test.py
└── test_cases.py

/lib

This is sort of a catch-all for a lot of the logic of the app.  Models is nothing surprising–just where we define each of our models for use in the app.  Repositories is where all of the database interaction occurs.  Most of the endpoints in “/app/api” talk to a repository to actual read/write data.  Serializers is where we format models for display.

├── __init__.py
├── models
│   ├── __init__.py
│   ├── model_helpers.py
│   └── my_sample.py
├── repositories
│   ├── __init__.py
│   └── my_sample_repo.py
└── serializers
    ├── __init__.py
    ├── my_sample.py
    └── serializer.py

/migrations

└── config
└── cassandra.yml

Pick your poison.  We use Cassandra as our database.

/tests

Largely a mirror of the app structure for organization.  We’re very serious about testing at Jana, so a lot goes into this one.

├── __init__.py
├── app
│   ├── __init__.py
│   └── api
│       ├── __init__.py
│       └── my_sample_api_test.py
├── helpers
│      ├── __init__.py
│      ├── jana_seed_test_case.py
│      └── model_factory.py
├── lib
│      ├── __init__.py
│      ├── repositories
│      │   ├── __init__.py
│      │   └── test_my_sample_repo.py
│      └── serializers
│          ├── __init__.py
│          └── test_my_sample.py
└── test_cases.py

We find this structure really helpful for organizing our web apps.  If people find this helpful, then next time I’ll put together a repo of a test app so that you can give it a spin.  If you want to help us build more and better apps like this, hit us up, because we’re hiring.

Discussion

2 responses to ‘Organizing a web app with Python Flask and AngularJS

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s