Python Web Framework の Bottle で GET/POST する方法を確認します。 その後、React からPOSTを使うところまでの備忘録です。
環境は Ubuntu 20.04 です。
$ python3 --version
Python 3.8.10
$ python3 -m pip --version
pip 23.1.2 from /home/foo/.local/lib/python3.8/site-packages/pip (python 3.8)
venv を入れます。
$ sudo apt-get install python3-venv
mybottle 環境を作成して、有効にします。
$ python3 -m venv ./mybottle
$ source ./mybottle/bin/activate
(mybottle) $
bottle をインストール。
(mybottle) $ pip install bottle
これで環境の準備と bottle インストール完了です。
pip list すれば、この mybottle 環境にインストール済みのモジュールを確認できます。
(mybottle) $ pip list
app.py を用意。
from bottle import Bottle, run
app = Bottle()
@app.get('/hello')
def hello():
return 'Hello, World!'
run(app, host='localhost', port=8080, debug=True)
実行:
(mybottle) $ python app.py
Bottle v0.12.25 server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.
別のターミナルから curl を実行。
$ curl http://localhost:8080/hello
Hello, World!
できました。
次に POST を試します。
app.py
from bottle import Bottle, run, request
app = Bottle()
@app.post('/echo')
def echo():
return request.body.getvalue().decode('utf-8')
run(app, host='localhost', port=8080, debug=True)
実行:
(mybottle) $ python app.py
Bottle v0.12.25 server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.
別のターミナルから curl を実行。
$ curl -X POST "http://localhost:8080/echo" -d 'Hello!' -H "Content-Type: text/plain"
Hello!
できました。
おうむ返しするサーバなので、別のメッセージを入れてみます。
$ curl -X POST "http://localhost:8080/echo" -d 'Hello, World!' -H "Content-Type: text/plain"
Hello, World!
問題ありません。
ここまではクライアントは curl を使いましたが、今度は React からこのサーバを使います。
現在のプロジェクトディレクトリに index.html, post.js を追加します。
(mybottle) $ touch index.html post.js
それぞれ内容は以下の通り。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv='cache-control' content='no-cache'>
<meta http-equiv='expires' content='0'>
<meta http-equiv='pragma' content='no-cache'>
<title>client</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@16.8.6/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.8.6/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel" src="./post.js"></script>
</body>
</html>
post.js
const { useState } = React;
const SERVER_IP = 'localhost'
const SERVER_PORT = '8080'
const END_POINT_URL = `http://${SERVER_IP}:${SERVER_PORT}/echo`
const DEFAULT_TEXT = 'Hello, World!'
function Form({model, actions}){
const submitStyle = { marginTop: '1em', marginBottom: '1.2em' }
return (
<div>
<form onSubmit={actions.handleSubmit} >
<textarea type='text' value={model.text} onChange={actions.handleChange} />
<br/>
<input style={submitStyle} type='submit' value='Post'/>
</form>
</div>
)
}
function Result({model}){
return (
<>
{model.result!='' && <div>{model.result}</div>}
</>
)
}
function Main({initialModel}){
const [model, setModel] = useState(initialModel)
const actions = {}
actions.handleChange = (e)=>{
setModel({
text: e.target.value,
result: model.result
})
}
actions.handleSubmit = (evt)=>{
evt.preventDefault()
if( model.text.trim()!='' ){
const text = model.text.trim()
const requestOptions = {
method: 'POST',
headers: {'Content-Type': 'text/plain'},
body: text
}
fetch(END_POINT_URL, requestOptions)
.then(response => response.text())
.then(result => {
setModel({
text: text,
result: result
})
})
}
}
return (
<>
<Form
model={model}
actions={actions}
/>
<Result
model={model}
/>
</>
)
}
const model = {
text: DEFAULT_TEXT,
result: ''
}
ReactDOM.render(
<Main initialModel={model} />,
document.getElementById("root"))
現在のプロジェクトファイルを確認します。
.
├── app.py
├── index.html
└── post.js
app.py を修正して、index.html, post.js を static file として扱えるようにします。
from bottle import Bottle, run, request, static_file
app = Bottle()
@app.post('/echo')
def echo():
return request.body.getvalue().decode('utf-8')
@app.route('/<filename>')
def index(filename):
return static_file(filename, root='.')
run(app, host='localhost', port=8080, debug=True)
import に static_file を追加し、def index(filename) で index.html と post.js を static file として publish できるようにしました。
これですべての準備ができたので、 python app.py でサーバを起動した上で、 ブラウザから http://localhost:8080/index.html にアクセスします。
Post ボタンをクリックして、テキストフィールドに入れた文字列が返ってくることを確認します。
もし、bottle を起動しているサーバとテストしているブラウザが別マシンの場合は、 localhost ではなく、IP アドレスを直接指定します。
localhost 指定部分は post.js と app.py にそれぞれあるので注意。
Bottle 本当に簡単に使えました。 感動しました。