Fortran+FastAPIで数値解析webAPIを生やす
Fortranユーザの方々は主に科学技術計算を行うアプリケーションを実装されているかと思います.
アプリケーションをブラウザ/API経由で行えると,外部のアプリケーションとの連携ができて嬉しいです.
ここでは,FastAPIによりFortranにwebAPIを生やす方法を概説します.
1. Fortranの入出力をJSONに対応させ,コマンドライン引数でJSON形式ファイルを指定できるようにする.
WebAPI経由でFortranに入力データを受け渡す際には,JSON形式を使うと便利です.
use your_module
implicit none
type(Your_object) :: your_object
character(256) :: json_file_name
call get_command_argument(number=1,value=json_file_name)
your_object = your_object%initialize(json_file=json_file_name)
!!! call some operations !!!
call your_object%execute_something()
call your_object%export_json_file(json_flle=trim(json_file_name)//".result.json")
end
2. FastAPIでオンラインフォームを作成し,ユーザからの入力を受け付ける(必須ではない).
(content headerにbootstrapを使用していますが,省略しています.)
@app.get("/your_api/createjsonfile")
async def get_json_form():
content = """
<h2>Online json editor </h2><br>
<form class="form-group" action="/your_api/download_new_json" method="get">
<div class="col-auto">
arg1 (integer)
<input name="arg1" type="text" class="form-control" value="1">
</div>
<div class="col-auto">
arg2 (real32)
<input name="arg2" type="text" class="form-control" value="1.00">
</div>
...
<div class="col-auto">
Download from here!
<input type="submit" value="Download">
</div>
</form>
"""
return HTMLResponse(content=content)
3. FastAPIでアクセスポイントを作成し,フォームから情報を受け取り保存する.
あらかじめ,working directoryでテンプレート(以下のyour_template.json
)を作成しておく.
@app.get("/your_api/download_new_json/")
async def download_new_json(arg1: str, arg2: str):
current = Path()
filename = "your_template.json"
file_path = current / filename
with open(file_path, 'r') as fcc_file:
fcc_data = json.load(fcc_file)
fcc_data["arg1"] = int(arg1)
fcc_data["arg2"] = float(arg2)
new_filename = "download_"+str(uuid.uuid4())+"_bridge.json"
f = open(new_filename,"w")
f.write((json.dumps(fcc_data, indent=4)))
f.close()
file_path = current / new_filename
response = FileResponse(
path=file_path,
filename=f"{new_filename}"
)
return response
4. FastAPIでjsonファイルのuploadを受け,ビルド済みの実行ファイルを呼び出し,処理を行い,jsonファイルをローカルに保存してから,結果ファイルのダウンロードページへを遷移する.
(Fortran側の結果ファイルの名前を,[入力ファイル名].result.jsonとしたことに留意)
@app.post("/your_api/execute_fortran/")
async def create_upload_files(files: List[UploadFile] = File(...),
):
for file in files:
filename = 'uploaded_'+str(uuid.uuid4()) +'.json'
f = open(filename, 'wb+')
print(type(file.file) )
fileobj = file.file
shutil.copyfileobj(fileobj, f)
f.close()
sts = subprocess.Popen("./a.out " + filename , shell=True)
content = """
<html>
<body>
<form class="row g-3" action="/your_api/downloadfile/" method="get">
<div class="col-auto">
<input type="hidden" name="filename" value="""+filename+".result.json"+ """>
<input type="submit" class="btn btn-primary mb-2" value="Download output file as .json">
</div>
</form>
</body>
</html>
"""
return HTMLResponse(content=content)
@app.get("/your_api/downloadfile")
async def get_file(filename: str):
current = Path()
if not filename.endswith(".json"):
return {"status": "error"}
file_path = current / filename
response = FileResponse(
path=file_path,
filename=f"download_{filename}"
)
return response
APIのデプロイ
こちらを参照してください.
実装例
ボックスカルバート自動生成API
補足
上記の通り実装したAPIはあくまで簡易的なものです.
公開するためには,アクセス制御を行ったり,認証を実装したりするなどの工夫が要ります.
LANやVPN内での運用を推奨します.