Help us understand the problem. What is going on with this article?

json-serverのDELETEで全てのアイテムや予期しないアイテムが削除される問題

More than 1 year has passed since last update.

json-serverは非常に便利なのですが、あるアイテムを削除しようとしたときに、なぜか全てのアイテムが削除されてしまう現象に出くわしました。

TL;DR

デフォルトで設定されている外部キーのサフィックスIdと自動的に実行されるcascading deleteの組み合わせで起きる現象なので、外部キーのサフィックスを変えてやれば(一応は)解決します。

json-server db.json --fks _id

問題の再現

db.json
{
  "customers": [
    {
      "id": 1,
      "customerId": "顧客ID1",
      "name": "顧客1"
    },
    {
      "id": 2,
      "customerId": "顧客ID2",
      "name": "顧客2"
    },
    {
      "id": 3,
      "customerId": "顧客ID3",
      "name": "顧客3"
    }
  ]
}

何の変哲もないDBです。サロゲートキーidを自動生成、ナチュラルキーcustomerIdを手入力することを想定した、よくある設計です。

json-server db.json

普通にjson-serverを立ち上げます。

curl -XDELETE http://localhost:3000/customers/1

普通にid=1のアイテムを削除します。

db.json
{
  "customers": []
}

なんということでしょう、全アイテムが削除されました

原因

自動的に外部キーを設定し、自動的にcascading deleteしてしまう仕様が原因でした。

  1. デフォルトでは、Idが自動的に外部キーのサフィックスとみなされるようになっており、
  2. customerIdcustomerへの外部キーとみなされ、
  3. 任意のcustomerを削除すると、
  4. customerIdによって参照されていないcustomerはcascading deleteによって全て削除されてしまう…

ということのようです。

試しに、customerIdを外部キーと考え、以下のようにid=1id=2のアイテムがお互いを参照するようにcustomerIdを設定し、id=3を削除すると、無事にid=3のみが削除されます。

db.json
{
  "customers": [
    {
      "id": 1,
      "customerId": 2,
      "name": "顧客1"
    },
    {
      "id": 2,
      "customerId": 1,
      "name": "顧客2"
    },
    {
      "id": 3,
      "customerId": 1,
      "name": "顧客3"
    }
  ]
}

対策

外部キーのサフィックスはオプションで設定できるので、適当な値に変えてやれば解決します。

json-server db.json --fks _id

ただし、実際の外部キーのサフィックスとしてIdを利用することはできなくなってしまうので、外部参照をせずアイテムを埋め込んでおくか、apiのpayloadの設計を変える必要があります。
しかし、モックサーバーの制限に合わせて本体の設計を変えるのは、控えめに言ってもおかしな話です。
個人的には、埋め込みによる対応でモックサーバーとしての役目は十分に果たせるので、問題ないといえばないのですが。

例外的なユースケースというわけでもないと思うので、公式に対策してほしいところです。しかし、現状ではcascading deleteはドキュメントにも記載されておらず、制御する方法もありません。
issueも上がっており、従属的なアイテムのみを削除+カスケードしないフラグを追加するプルリクも上がっているのですが、もう半年近く放置されています…。

mshackers
ソフトウェア開発から産業用機械開発までこなすモノづくり集団
https://mshackers.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした