├── .gitignore ├── LICENSE ├── README.md ├── api ├── __init__.py ├── config.py ├── run.py ├── tests │ ├── __init__.py │ ├── test_api_v1.py │ └── test_api_v2.py ├── v1.py └── v2.py ├── bin └── runner.sh ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.py[cod] 3 | 4 | # C extensions 5 | *.so 6 | 7 | # Packages 8 | *.egg 9 | *.egg-info 10 | venv 11 | dist 12 | build 13 | eggs 14 | parts 15 | var 16 | sdist 17 | develop-eggs 18 | .installed.cfg 19 | lib 20 | lib64 21 | __pycache__ 22 | 23 | # Installer logs 24 | pip-log.txt 25 | 26 | # Unit test / coverage reports 27 | .coverage 28 | .tox 29 | nosetests.xml 30 | 31 | # Translations 32 | *.mo 33 | 34 | # Mr Developer 35 | .mr.developer.cfg 36 | .project 37 | .pydevproject 38 | .settings 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Marat Khayrullin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | flask-restful-example 2 | ===================== 3 | 4 | An example of using a Flask-Restful module with several version of API and using unittest 5 | -------------------------------------------------------------------------------- /api/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | from flask import Flask 5 | import flask_restful 6 | import os 7 | 8 | #from api.database import db 9 | from api.v1 import api_v1, api_v1_bp, API_VERSION_V1 10 | from api.v2 import api_v2, api_v2_bp, API_VERSION_V2 11 | 12 | 13 | def create_app(environment=None): 14 | app = Flask(__name__) 15 | 16 | if not environment: 17 | environment = os.environ.get('FLASK_CONFIG', 'development') 18 | app.config.from_object('api.config.{}'.format(environment.capitalize())) 19 | app.config.from_pyfile( 20 | 'config_{}.py'.format(environment.lower()), 21 | silent=True 22 | ) 23 | 24 | app.register_blueprint( 25 | api_v1_bp, 26 | url_prefix='{prefix}/v{version}'.format( 27 | prefix=app.config['URL_PREFIX'], 28 | version=API_VERSION_V1)) 29 | 30 | app.register_blueprint( 31 | api_v2_bp, 32 | url_prefix='{prefix}/v{version}'.format( 33 | prefix=app.config['URL_PREFIX'], 34 | version=API_VERSION_V2)) 35 | 36 | return app 37 | -------------------------------------------------------------------------------- /api/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | from os import path 5 | 6 | 7 | class Config(object): 8 | DEBUG = False 9 | PORT = 5000 10 | HOST = '0.0.0.0' 11 | URL_PREFIX = '/api' 12 | PROJECT_ROOT = path.abspath(path.dirname(__file__)) 13 | TEMPLATE_FOLDER = path.join(PROJECT_ROOT, 'templates') 14 | MYSQL_DATABASE_HOST = '127.0.0.1' 15 | MYSQL_DATABASE_DB = 'default_db' 16 | MYSQL_DATABASE_USER = 'default_user' 17 | MYSQL_DATABASE_PASSWORD = 'password' 18 | 19 | 20 | class Development(Config): 21 | DEBUG = True 22 | SECRET_KEY = 'development' 23 | 24 | 25 | class Production(Config): 26 | pass 27 | 28 | 29 | class Testing(Config): 30 | TESTING = True 31 | SECRET_KEY = 'testing' 32 | -------------------------------------------------------------------------------- /api/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | from api import create_app 4 | 5 | app = create_app() 6 | 7 | if __name__ == "__main__": 8 | 9 | app.run(host=app.config['HOST'], port=app.config['PORT']) 10 | -------------------------------------------------------------------------------- /api/tests/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import unittest 5 | from test_api_v1 import * 6 | from test_api_v2 import * 7 | 8 | 9 | if __name__ == '__main__': 10 | unittest.main() 11 | -------------------------------------------------------------------------------- /api/tests/test_api_v1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | from api import create_app 5 | import unittest 6 | import flask 7 | import json 8 | 9 | 10 | class APIV1TestCase(unittest.TestCase): 11 | 12 | def setUp(self): 13 | self.app = create_app(environment="Testing") 14 | 15 | def test_hello_version(self): 16 | data = json.loads(self.app.test_client().get('/api/v1/helloworld').data) 17 | assert data.get('version') == 1 18 | assert data.get('hello') == 'world' 19 | 20 | 21 | if __name__ == '__main__': 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /api/tests/test_api_v2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | from api import create_app 5 | import unittest 6 | import flask 7 | import json 8 | 9 | 10 | class APIV2TestCase(unittest.TestCase): 11 | 12 | def setUp(self): 13 | self.app = create_app(environment="Testing") 14 | 15 | def test_hello_version(self): 16 | data = json.loads(self.app.test_client().get('/api/v2/helloworld').data) 17 | assert data.get('VERSION') == 2 18 | assert data.get('HELLO') == 'WORLD' 19 | 20 | 21 | if __name__ == '__main__': 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /api/v1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Copyright (c) 2013 4 | @author: Marat Khayrullin 5 | ''' 6 | 7 | from flask import Flask, Blueprint 8 | import flask_restful 9 | 10 | 11 | API_VERSION_V1=1 12 | API_VERSION=API_VERSION_V1 13 | 14 | api_v1_bp = Blueprint('api_v1', __name__) 15 | api_v1 = flask_restful.Api(api_v1_bp) 16 | 17 | 18 | class HelloWorld(flask_restful.Resource): 19 | def get(self): 20 | return { 21 | 'hello': 'world', 22 | 'version': API_VERSION, 23 | } 24 | 25 | 26 | api_v1.add_resource(HelloWorld, '/helloworld') 27 | -------------------------------------------------------------------------------- /api/v2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Copyright (c) 2013 4 | @author: Marat Khayrullin 5 | ''' 6 | 7 | from flask import Flask, Blueprint 8 | import flask_restful 9 | 10 | 11 | API_VERSION_V2=2 12 | API_VERSION=API_VERSION_V2 13 | 14 | api_v2_bp = Blueprint('api_v2', __name__) 15 | api_v2 = flask_restful.Api(api_v2_bp) 16 | 17 | 18 | class HelloWorld(flask_restful.Resource): 19 | def get(self): 20 | return { 21 | 'HELLO': 'WORLD', 22 | 'VERSION': API_VERSION, 23 | } 24 | 25 | 26 | api_v2.add_resource(HelloWorld, '/helloworld') 27 | -------------------------------------------------------------------------------- /bin/runner.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | full_path=`readlink -f "$0"` 4 | TOP_DIR=${full_path%%/bin/runner.sh} 5 | PROJ_DIR=$TOP_DIR 6 | 7 | source $TOP_DIR/venv/bin/activate 8 | 9 | export PYTHONPATH=$PYTHONPATH:$PROJ_DIR 10 | cd $PROJ_DIR 11 | 12 | exec python $@ 13 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | flask-restful 2 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from setuptools import setup 4 | 5 | setup( 6 | name='flask-restful-example', 7 | version='0.1', 8 | description='An example of using a Flask-Restful module with several version of API and using unittest', 9 | licence='BSD', 10 | keywords = 'flask restful api unittest', 11 | install_requires=['Flask-Restful'], 12 | ) 13 | --------------------------------------------------------------------------------