Home About Contact
Micronaut , React , Kotlin

React と Micronaut で JSON を POST して JSON を取得する

JSON を POST して JSON を返すウェブサービスを Micronaut でつくる、クライアントはReact。

Micronaut でサーバの用意

Micronautのバージョンを確認。

$ mn --version
Micronaut Version: 3.8.4

サーバをまずは用意。

$ mn create-app myapp --build=gradle --lang=kotlin

プロジェクトディレクトリに移動して、 item という名前でコントローラーの雛形を作成。

$ cd myapp
$ mn create-controller item
| Rendered controller to src/main/kotlin/myapp/ItemController.kt
| Rendered test to src/test/kotlin/myapp/ItemControllerTest.kt

とりあえず ./gradlew run します。

$ ./gradlew run

ポート 8080 でウェブサーバーが起動するので、ブラウザで http://localhost:8080/item/ にアクセスすると Example Response の文字列が表示されます。

ctrl + C して一旦サーバを停止します。

それでは、JSON を受け取り JSON を返すようにコントローラーを変更します。

item コントローラのコード ( src/main/kotlin/myapp/ItemController.kt ) を見てみましょう。

package myapp

import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.HttpStatus

@Controller("/item")
class ItemController {

    @Get(uri="/", produces=["text/plain"])
    fun index(): String {
        return "Example Response"
    }
}

これを変更して JSON を受け取り JSON を返すように設定します。

package myapp

import io.micronaut.http.annotation.Controller
//import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.Post
import io.micronaut.http.annotation.Body
//import io.micronaut.http.HttpStatus
import io.micronaut.http.HttpResponse

@Controller("/item")
class ItemController {
    /*
    @Get(uri="/", produces=["text/plain"])
    fun index(): String {
        return "Example Response"
    }
    */

    @Post(uri="/", consumes=["application/json"], produces=["application/json"])
    fun index(@Body item: Item): HttpResponse<Item> {
        return HttpResponse.created(item)
    }
}

data class Item(val name: String, val price: Int)

POST された JSON を Item クラスのインスタンスとして受け取り、それをそのまま返す実装にしました。

クライアント curl で POST 実行

$ curl -X POST "http://localhost:8080/item/" -d '{ "name": "mac mini", "price": 128000 }' -H "Content-Type: application/json"
{"name":"mac mini","price":128000}
$ curl -X POST "http://localhost:8080/item/" -d '{ "name": "mac studio", "price": 278000 }' -H "Content-Type: application/json"
{"name":"mac studio","price":278000}

こちらからPOSTした JSON をそのまま返すエンドポイントができました。

クライアント React で POST 実行

それでは、今度は curl ではなく React から POST してみます。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>multiple select buttons</title>
        <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
        <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
        <!-- Don't use this in production: -->
        <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    </head>
    <body style="margin: 20px;">
        <div id="app"></div>
    
        <script type="text/babel">
            class App extends React.Component {
                constructor(props) {
                    super(props);

                    this.state = {
                        value: '',
                        result: ''
                    };

                    this.handleChange = this.handleChange.bind(this);
                    this.handleSubmit = this.handleSubmit.bind(this);
                }
                
                handleChange(event){
                    const newState = {
                        value: event.target.value,
                        result: this.state.result
                    };
                    this.setState(newState);

                    console.log(newState);
                }

                handleSubmit(event){
                    event.preventDefault();

                    const name = this.state.value.split(/,/)[0];
                    const price = this.state.value.split(/,/)[1];

                    const obj = {
                        name: name,
                        price: parseInt(price)
                    };

                    const requestOptions = {
                        method: 'POST',
                        headers: {'Content-Type': 'application/json'},
                        body: JSON.stringify(obj)
                    };

                    fetch('http://localhost:8080/item/', requestOptions)
                        .then(response => response.json())
                        .then(jsonObj => {
                            const newState = {
                                value: this.state.value,
                                result: JSON.stringify(jsonObj)
                            };
                            this.setState(newState);
                        });
                }
    
                render(){
                    return (
                        <>
                        <div>
                            <form onSubmit={this.handleSubmit}>
                                <label>name,price:
                                  <input type="text" value={this.state.value} onChange={this.handleChange} />
                                </label>
                                <input type="submit" value="GO" />
                            </form>
                        </div>
                        <div>
                            <p>{this.state.result}</p>
                        </div>
                        </>
                    );
                }
            }
    
            const container = document.getElementById('app');
            const root = ReactDOM.createRoot(container);
            root.render(<App />);
        </script>
    </body>
</html>

ローカルでウェブサーバを起動:

$ python3 -m http.server 8000 

http://localhost:8000/index.html をブラウザで開くと、以下のような画面になります。

name-price

mac,100000 と入力して GOボタンをクリックして POST すると・・・CORS のエラーになりました。

それでは、一旦 micronaut のサーバは終了して、 src/main/resources/application.yml に CORS を許可する設定を入れます。

micronaut:
  application:
    name: myapp
  server:
    cors:
      enabled: true
netty:
  default:
    allocator:
      max-order: 3

再び起動 ./gradlew run します。

http://localhost:8000/index.html からPOST実行すると・・・

name-price-result

できました。