JSON を POST して JSON を返すウェブサービスを Micronaut でつくる、クライアントはReact。
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 -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 をそのまま返すエンドポイントができました。
それでは、今度は 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 をブラウザで開くと、以下のような画面になります。
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実行すると・・・
できました。