スクリプトのお勉強 技術

Nuxt.js – CRUDアプリケーションのフォーム/一覧を作成する

投稿日:

前回で作ったAPIのフロントエンドアプリケーションを作ろうと思います。

どういうアプリ?

サンプルとして作ったAPIが住所録的だったので、住所録を作りました。

以下の機能があります。

  • 登録(確認付き)
  • 更新(確認付き)
  • 削除(確認ダイアログ付き)
  • 一覧表示

特徴

取り立てて特徴はありませんが、以下を追加してみました。

  • ほぼ全部TypeScript
    Nuxt.jsはあまりTypeScriptにやさしくないので使ったことがなかったのですが、
    今回はTypeScriptを採用してみました。
  • vee-validateによる親子コンポーネント間のバリデーション
     子コンポーネントのバリデーション結果を親コンポーネントで判定してみました。
  • デコレータ(vuex-module-decorators)を使用しない
     なんとなくデコレータが好きじゃないので、使わずに書いてみました。 

環境

  • nodejs: v12.16.3
  • yarn: 1.12.3
  • nuxt.js: 2.14.7

準備

以下で作り始めました。

$ npx create-nuxt-app

ソース(ディレクトリ)構成

ソースはここにあります。

以下が結果のソースです。

|-- components
|   |-- container
|   `-- present
|       |-- addr_form.vue         :登録フォーム
|       |-- addr_form_readonly.vue    :登録フォーム(確認用)
|       |-- addr_id_form.vue          :更新フォーム
|       |-- addr_id_readonly_form.vue :更新フォーム(確認用)
|       `-- confirm_dialog.vue        :削除確認用ダイヤログ
|-- layouts
|   |-- default.vue
|-- lib
|   |-- addr.ts                      :addrの型を設定
|   `-- api.ts             :axios API呼び出し用
|-- nuxt.config.js
|-- package.json
|-- pages
|   |-- addr_add.vue         :登録画面
|   |-- addr_confirm.vue       :登録画面(確認)
|   |-- addr_edit_confirm.vue    :更新画面(確認)
|   |-- addr_edit_save.vue      :更新画面(保存)
|   |-- addr_save.vue               :登録画面(保存)
|   |-- addrs.vue           :一覧画面
|   |-- editaddr
|   |   `-- _id.vue                 :更新画面
|   `-- index.vue  
|-- plugins
|   |-- axios.js           :$axios用プラグイン
|   `-- vee-validate.js             :フォームバリデーション設定
|-- store
|   `-- index.ts           :addrs(APIで保持している住所の配列)       
|-- tsconfig.json
|-- types
|   |-- index.d.ts          :TypeScriptの型指定
|   `-- vue-shim.ts
`-- yarn.lock

コンポーネントの種類

コンポーネントを以下のように分類してみました。よくある分類だと思います。

  • components/container <– データをもつコンポーネント。
  • components/present <– prop経由でしか持たない。callbackは親コンポーネント側を使用する。

と言っても、今回はcontainerはありませんでした。

起動方法

今回は、FastAPIとUI側で別のURLにしてみました。

FastAPI側の起動は以下の通りです。

$ pipenv run uvicorn app.run:app --reload --host 0.0.0.0 --port 18001

UI側の起動は以下の通りです。192.168.132.128:18000はテスト環境での値なので、
適宜変更してください。

$ cd mvc
$ yarn install
$ yarn run dev
? Listening on: http://192.168.132.128:18000/
No issues found.

CORS回避(API側)

CORSを回避するため、API側でoriginが違う場合の対処をしてみました。

FastAPI側で以下の対処を追加すれば、CORSを回避できます。
originsはUI側からどのようにアクセスしに来るかによります。

+from fastapi.middleware.cors import CORSMiddleware
 import os
 from starlette.requests import Request
 import sys
@@ -12,11 +13,24 @@ sys.path.append(ROOT_DIR)
 from app.urls import router as app_router
 from app.settings.settings import Settings

+origins = [
+    "http://192.168.132.128:18000",
+    "http://192.168.0.12:18000",
+]

 settings = Settings()

 app = FastAPI(openapi_url='/openapi.json')
 app.add_middleware(DBSessionMiddleware, db_url=settings.DATABASE_URI)

+app.add_middleware(
+    CORSMiddleware,
+    allow_origins=origins,
+    allow_credentials=True,
+    allow_methods=["*"],
+    allow_headers=["*"],
+)
+

vee-validateによる親子コンポーネント間のバリデーション

思ったよりは簡単で、子側は以下のように、v-slotとrulesを設定し

<validation-provider v-slot="{ errors }" rules="required|ipaddr" name="IPアドレス" >
<v-text-field
    v-model="addrObj.ipaddr"
    label="IPアドレス"
    :error-messages="errors"
    required
/>
</validation-provider>

親側には以下を設定し、submitのタイミングでvalidationを呼び出せばいいだけでした。

<validation-observer ref="validationObserver" tag="div">
  <AddrForm :addrObj=addrObj />
</validation-observer>

methods: {
  async submit(addrObj) {
    const isValid = await this.$refs.validationObserver.validate();
    if (!isValid) return false;
    this.$router.push({ name: 'addr_confirm', params: { addrObj: addrObj }});
  }
},

開発する際にはまったこと

むしろはまったことしかありません。。多すぎて覚えてない。。

前半は、そもそも何も動かなくて、後半はnuxt.config.jsやtsconfig.jsonに設定をする必要があったことが多い気がします。

まだ分からない点

いまだに実装上分かってないことがあります。

FastAPIで戻り値がおかしい

以下のようにDBのupdate後の値をAPIで戻すべくModelを返却しているのですが、なぜか辞書にしないとUI側で値が取れなかったりします。ちゃんと理由を調べてない。。

def asdict(self):
    result = OrderedDict()
    for key in self.__mapper__.c.keys():
        if getattr(self, key) is not None:
            result[key] = str(getattr(self, key))
        else:
            result[key] = getattr(self, key)
    return result


def update_addr_query(db: Session, addr: schemas.AddrUpdateEntity):
    db_addr = db.query(models.Addr).filter(models.Addr.id==addr.id).first()

    db_addr.name = addr.name
    db_addr.addr = addr.addr
    db_addr.ipaddr = addr.ipaddr
    db_addr.update_time = datetime.datetime.now()

    db.commit()
    # 辞書に変更しないと、modelsがそのまま反映されてしまうため
    asdict(db_addr)
    return db_addr

/addrsをリロード(Ctrl+R)すると画面が崩れる

リロードが終わると正常なんですが、、よく分かってません。

終わりに

思った通り苦労しました。作ったつもりでいきなり動かない。動かないけど、どこをどう調べていいかよく分からない。

なのでしょうがなく、これのように小さく作って、段々と大きくしていくことにしてます。。

参考

https://qiita.com/shindex/items/a90217b9e4c03c5b5215

  • Nuxt.jsのTypeScript環境

https://qiita.com/ikedaHi/items/1001594a386815c0ce85

  • ボダンでの遷移、コンポーネント間通信、syncのやりかた。

https://qiita.com/after666/items/7e94d61fed89406ae59a

  • actionsの引数について

https://qiita.com/tshcstrm/items/aeb9cc7da014fd2b8304

  • TypeScriptでのpropsの書き方。

https://se-tomo.com/2018/11/03/vue-js-%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E9%96%93%E3%81%AE%E9%80%9A%E4%BF%A1/

  • 親子間通信
  • emit
  • 親子間のイベント伝達

https://note.com/aliz/n/ne1d2fc4fb1ef

  • nuxt.jsでのvue-router

https://typescript.nuxtjs.org/cookbook/store.html#class-based

  • classベースの書き方(今回はVanilla的に記述)

-スクリプトのお勉強, 技術

執筆者:

関連記事

SimpleHTTPSAuthUploadServer というPython用モジュールを書いた

書いた動機 リモート開発になっているので、遠くのホストにあるファイルをお手軽に見たい、取ってきたいor編集したい、というニーズが、私の中であります。ftpなんか使わず、全部ブラウザでやりたいわけです。 …

fastapi + SQLAlchemy で CRUDアプリケーションを作ってみる

概要 勉強用に、PythonでPostgresqlを制御しようと思います。の続きです。 前回でPostgreSQLと、データベース/テーブルまでは用意したので、今回はAPIを作成しようと思います。 実 …

CentOS7 + Django2.2 + uwsgi + nginx 連携方法

Djangoとnginx連携方法 以前はApache経由で連携しましたが、今回はnginxと連携する方法を記述します。 環境 設定した環境は以下です。 OS: CentOS7Python3.6.8 ( …

言語別ログイン機能パスワード保存処理方針

ちょっと前に、ログイン機能を作成した際、パスワードを暗号化するか、という議論を目にしたことがありました。 昔だと、「パスワードを暗号化しない」方で実装していましたが、最近はセキュリティが当たり前になっ …

seaborn + Pandas + Python によるグラフ描画(その1: 準備編)

グラフ描画してみよう 今現在の仕事で、グラフ描画する可能性があるので、少し練習してみようと思います。 題材について 突然ですが、私は確定拠出型年金に加入しています。証券会社はSBI証券 にしています。 …

google オプトアウト Click here to opt-out.