Flask, EveでREST+NormalSite構築のはまりどころ

Flaskの派生のひとつでRESTサービスを簡単に構築できる[Eve](http://python-eve.org/)というのがある。スキーマの設計さえしておけば、SiteRootにREST APIを展開してくれる優れものだが、Django+REST Framework+angularのような感じで、構築しようとしたときに結構はまったので記録に残しておく。

##REST API Rootの変更
Eveの場合通常API Root=Rootとなるので、rootアクセス時にindex.html表示なんてことができない。
そこで、

```py:settings.py
URL_PREFIX = 'api'
```

みたく、prefixを定義してやることで、APIルートを変更できる。

##Flask とEveの設定
EveとFlaskで別々に設定がある。
Eveは指定しないと同じディレクトリのsettings.pyを読みに行く。
別途読み込みたい場合は

```py
app=EVE(settings='hoge.py')
```

と書くとそちらを読みに行く。ただし、settingsはdictとfileしか受け付けない。

Eveが使用している設定以外はsettings.pyに書いても機能しないはず・・・
Flaskの設定は切り離して、create_app()などのappFactoryで与える必要がある。

```py:app/__init__.py
def create_app(api_settings=None, flask_config='oss_app.config', package_name=__name__, flask_conf_override=None):

    # Define the WSGI application object
    if api_settings is not None:
        app = Eve(settings=api_settings, import_name=__name__)
    else:
        app = Eve()

    # Configurations
    app.config.from_object(flask_config)
    app.config.from_object(flask_conf_override)
```

##static path
Eveの場合、無設定で/staticをたたくと、404が返ってくる。
理由はeveのパッケージのflaskapp.pyで

```py:flaskapp.py
class Eve(Flask, Events):

　中略

    def __init__(self, import_name=__package__, settings='settings.py',
                 validator=Validator, data=Mongo, auth=None, redis=None,
                 url_converters=None, json_encoder=None,
                 media=GridFSMediaStorage, **kwargs):

```
となっている。
Flaskはstatic_root_pathを探す時に、import_nameがあるとimport_nameを探すので、import_name=__package__=EVEとなり、site-package内のEVEディレクトリがsatticfileのディレクトリと認識してしまい、404が返ってしまう。
対策はEveインスタンス生成時にimport_name=\__name__としてやること。

```py
app=Eve(import_name=__name__)
```

##Eve-mongoengineを使う。
Eveの場合、初期状態はpymongoを使用する、ORMを使用したい場合、Eve-mongoengineが使える。ただし、1年ほど更新が止まっているためか、使用すると起動シークエンスで_etag errorとなり落ちる。
EveのどこかのバージョンからEtagあが必須になったのだが追い付いていないのだと思う。
これにについては
eve-mongoengine\\__init_.pyの102行目あたりと190行目あたりにEtagの定義追加で何とかなる。

```py:eve-mongoengine\__init_.py

91:
    def _parse_config(self):
        # parse app config
        config = self.app.config
        try:
            self.last_updated = config['LAST_UPDATED']
        except KeyError:
            self.last_updated = '_updated'
        try:
            self.date_created = config['DATE_CREATED']
        except KeyError:
            self.date_created = '_created'
+        try:
+            self.etag = config['ETAG']
+        except KeyError:
+            self.etag = '_etag'

    def fix_model_class(self, model_cls):

中略
192:
        date_field_cls = mongoengine.DateTimeField
+        string_field_cls = mongoengine.StringField

        # field names have to be non-prefixed
        last_updated_field_name = self.last_updated.lstrip('_')
+        date_created_field_name = self.date_created.lstrip('_')
        etag__field_name = self.etag.lstrip('_')
        new_fields = {
            # TODO: updating last_updated field every time when saved
            last_updated_field_name: date_field_cls(db_field=self.last_updated,
                                                    default=get_utc_time),
            date_created_field_name: date_field_cls(db_field=self.date_created,
                                                    default=get_utc_time),
             etag__field_name: string_field_cls(db_field=self.etag,
                                                    default=""),
        }

```