1. 正しい出品は201
  2. 0円は止める
  3. 文字列の価格も止める
  4. タイトルが空
  5. 問題が2つあれば2つとも返す
  6. 何も送らなければ2つとも返る
コース一覧
Express道場 fleama開発室のIssue10件
#105 0円出品が通ってしまう

Express道場 fleama開発室のIssue10件

Node.js入門で作り上げた fleama API の開発室に、スプリントの助っ人として参加する演習専用コースです。解説はありません。1問が1件の Issue で、報告者は商店街の住人たち。依頼と完成条件だけを読み、白紙から自分で組み立てます。手が止まったときのために、方針・使う構文・部分解の3段階のヒントを各問に用意しています。ヘルスチェックから始まり、一覧API、404の扱い、並び替えとページング、入力検証、自作ミドルウェア、エラー形式の統一、所有者チェック、二重販売を止めるトランザクションを経て、最後はいいね機能をエンドポイント設計から任されるところまで、10件の Issue で Express の主要な道具を一巡します。1問15分から45分、全10問で約5時間です。Node.js入門を終えて「作れたけれど実務で通用するか不安」と感じている方に向いています。

1
今週のスプリント
01. #101 監視用ヘルスチェックが欲しい15分
02. #102 カテゴリ一覧APIが欲しい20分
03. #103 消えた商品を開くと落ちる20分
04. #104 検索に並び替えとページングを25分
05. #105 0円出品が通ってしまう25分
06. #106 調査用のアクセスログを25分
07. #107 エラーの形式がバラバラ30分
08. #108 他人の出品を値下げできてしまう30分
09. #109 同じ商品が2人に売れた35分
10. #110 新機能「いいね」を設計から45分

#105 0円出品が通ってしまう

中段 / 目安 25分


Issue #105 0円出品が通ってしまう

報告者: 凛(テックリード)

「昨夜、0円出品が3件登録されました。POST /items の検証が甘い。タイトル必須・価格は1円以上・型チェック。400 とエラー理由を返す形で塞いでください」


0円出品そのものより深刻なのは、それが登録できてしまうことです。データベースに入ってしまえば、集計も検索も、その先の処理がすべて汚染されます。

止めるのは入口です。見るべきことは3つに分かれます。

観点例
必須タイトルが入っているか
型価格が数値か
範囲価格が1円以上か

順番も決まっています。 値が無いのに型は調べられませんし、型が数値だと分かっていないのに大小は比べられません。土台から順に見ます。

"3500" のような文字列を弾くのを忘れないでください。"3500" > 0 は成り立ってしまうので、範囲だけ見ていると通り抜けます。

返すのは 400 と理由です。凛さんは「理由を配列で返すと親切」と言い添えました。問題が複数あるなら全部まとめて返すという考え方です。1つ直すたびに送り直すのは、送る側にとって手間だからです。

完成条件

POST /items に検証を足してください。

問題があれば 400 で {"errors":["タイトルは必須です"]} の形で返します。当てはまるものは全部入れてください。

条件文言
title が無い・空文字タイトルは必須です
price が数値でない価格は数値で指定してください
price が数値で 0 以下価格は1円以上にしてください

並びはこの順です。すべて通れば 201 で {"id":3,"title":"...","price":...} を返します。id は「いまある最大の id + 1」です。

要件

  1. 問題を配列に集めて、1件でもあれば 400 で {"errors":[...]} を返す
  2. price が数値でないときは範囲の判定をしない(文字列の "3500" も弾く)
  3. 通れば 201 で {id, title, price} を返し、id は最大の id + 1 にする

入出力例

request("POST", "/items", {"price":3500,"title":"木製のスツール"}) → "201 {"id":3,"title":"木製のスツール","price":3500}" request("POST", "/items", {"price":0,"title":"木製のスツール"}) → "400 {"errors":["価格は1円以上にしてください"]}" request("POST", "/items", {"price":"3500","title":"木製のスツール"}) → "400 {"errors":["価格は数値で指定してください"]}" request("POST", "/items", {"price":3500,"title":""}) → "400 {"errors":["タイトルは必須です"]}" request("POST", "/items", {"price":-100,"title":""}) → "400 {"errors":["タイトルは必須です","価格は1円以上にしてください"]}" request("POST", "/items", {}) → "400 {"errors":["タイトルは必須です","価格は数値で指定してください"]}"

ヒント

前のヒントを開くと次が開きます。開かずに解けると未開封クリアです

問題を集める配列を先に用意し、当てはまるたびに `push` します

ヒント 2ヒント 1 を開くと読めます
ヒント 3ヒント 2 を開くと読めます
生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/08/10

関連レッスン

  • #106 調査用のアクセスログを

    全リクエストのメソッドとパスを記録するミドルウェアを自作します。

  • #107 エラーの形式がバラバラ

    バラバラだったエラー応答を、共通ハンドラで1つの形に統一します。

  • #108 他人の出品を値下げできてしまう

    出品者だけが値下げできるよう、401と403を使い分けて守ります。

  • #109 同じ商品が2人に売れた

    確認と更新の隙間をトランザクションで塞ぎ、二重販売を止めます。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • データベースデータを構造化して保存する仕組み
  • 処理計算や代入を表す長方形
  • 配列サイズ固定の同型データの集まり
main.js
学習モード
エディタを読み込んでいます

メモ

#105 0円出品が通ってしまう

⌘S で保存