yommy
@yommy (yomm)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Spring の Web API で JSON 形式でデータを受け取る方法について

解決したいこと

Springでアプリを開発しているのですが、その中で非同期通信を使用したく最近学んだfetch関数でjsを実装しようと思いました。
下記のコードは実際に使用しているコードではなくchatGptに生成してもらったタスク管理アプリで特定のタスクの完了状態を更新するシナリオになります。

しかし、下記の書き方だとbad requestといわれてしまいます。なぜなのでしょうか?

問題のコード

sample.js
function updateTaskStatus(taskId, isComplete) {
    // リクエストデータの作成
    let requestData = {
        id: taskId,          // 更新したいタスクのID
        completed: isComplete // 完了かどうかの状態
    };

    // fetch関数でサーバーにPOSTリクエストを送信
    fetch('/api/task/updateStatus', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json', // JSON形式で送信する
        },
        body: JSON.stringify(requestData) // リクエストデータをJSONに変換して送信
    })
    .then(response => {
        if (!response.ok) {
            throw new Error('タスクの更新に失敗しました');
        }
        return response.json(); // JSONのレスポンスをパース
    })
    .then(data => {
        console.log('タスクの状態が更新されました:', data); // 成功した場合の処理
    })
    .catch(error => {
        console.error('更新エラー:', error); // エラーが発生した場合の処理
    });
}
TaskController.java
@RestController
@RequestMapping("/api/task")
public class TaskController {

    @PostMapping("/updateStatus")
    public ResponseEntity<String> updateTaskStatus(@RequestBody TaskUpdateRequest request) {
        // リクエストからタスクIDと完了状態を取得
        Integer taskId = request.getId();
        Boolean isComplete = request.getCompleted();

        // サービスでタスクの状態を更新する(仮の処理)
        boolean success = taskService.updateTaskStatus(taskId, isComplete);

        return ResponseEntity.ok("タスクの状態が正常に更新されました");
        }
    }
}

私が実際に書いたコードでは、@RequestBody Integer taskId,Boolean isCompleteのような形でしたがそれがだめっだったのでしょうか:cold_sweat:

(下記のコードだとうごきました)

sample.js
function updateTaskStatus(taskId, isComplete) {
    // FormDataオブジェクトの作成
    let formData = new FormData();
    formData.append('id', taskId);          // 更新したいタスクのIDを追加
    formData.append('completed', isComplete); // 完了かどうかの状態を追加

    // fetch関数でサーバーにPOSTリクエストを送信
    fetch('/api/task/updateStatus', {
        method: 'POST',
        body: formData // FormDataをリクエストボディに送信
    })
    .then(response => {
        if (!response.ok) {
            throw new Error('タスクの更新に失敗しました');
        }
        return response.json(); // JSONのレスポンスをパース
    })
    .then(data => {
        console.log('タスクの状態が更新されました:', data); // 成功した場合の処理
    })
    .catch(error => {
        console.error('更新エラー:', error); // エラーが発生した場合の処理
    });
}

TaskController.java
@RestController
@RequestMapping("/api/task")
public class TaskController {

    @PostMapping("/updateStatus")
    public ResponseEntity<String> updateTaskStatus(
            @RequestParam("id") Integer taskId,        // リクエストからタスクIDを取得
            @RequestParam("completed") Boolean isComplete // リクエストから完了状態を取得
    ) {
        // サービスでタスクの状態を更新する(仮の処理)
        boolean success = taskService.updateTaskStatus(taskId, isComplete);

        if (success) {
            return ResponseEntity.ok("タスクの状態が正常に更新されました");
        } else {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("タスクの更新に失敗しました");
        }
    }
}

変更したこと
・元々、JavaScriptでfetch関数を使用してJSON形式でデータを送信していましたが、これをFormData形式に変更しました。
・コントローラーで受け取る引数のアノテーションを@RequestBodyから@RequestParamに変更しました。

質問まとめ

なぜJSON形式でデータを送信するとbad requestになるのか、JSON形式では書けないのか?という質問になります。
有識者の方がいましたらご教示いただけますと幸いです。

0

1Answer

Comments

  1. @yommy

    Questioner

    @twsnmpさん

    ご丁寧にありがとうございます。
    試してみたところ、consumes = "application/json"を追加するのみではうまくいかず、
    @RequestBody Map requesBodyという引数に変えるとJSON形式でもうまく動きました!
    consumesについては初めて学びましたので、今後は特定のContent-Typeのみを受け入れる必要がある場合に活用していきたいと考えています。

    本当にありがとうございます:sob:

  2. 解決できたよかったです。

Your answer might help someone💌