見出し画像

REST API

サプライチェイン最適化のためのいろいろな関数ををWeb APIで呼び出せると便利かと思い,作ってみた.いわゆるREST(Representational State Transfer) APIをというやつだ.

以前はFlaskとか使って面倒だったのだが,FastAPI というのを使うとドキュメントも同時にできる.ドキュメント化はちょうどしたかったので,ついでということだ.上に示した画面がブラウザに出てくる.

- FastAPI https://fastapi.tiangolo.com/ は, APIを構築するためのWebフレームワークである.
- pydantic https://github.com/samuelcolvin/pydantic/ は,FastAPI内で使われるJSON互換のデータ定義のためのモジュールである.

インストールは,fastapiとサーバーとして uvicorn http://www.uvicorn.org/ を必要とする.(pipでできる.)

例として,連続型施設配置の最適化関数(反復Weiszfeld法)を使う.

モデルクラスMelosGfは,顧客クラスCustomer,製品クラスProduct,総需要クラスTotalDemandから構成され,以下のように定義される.

class Customer(BaseModel):
   name: str = Field(description="名称")
   lat: float = Field(description="緯度")
   lon: float = Field(description="経度")
   class Config:
       schema_extra = {
           "example": {
               "name": "響本店",
               "lat": 43.06417,
               "lon": 141.34694
           }
       }
class Product(BaseModel):
   name: str = Field(description="名称")
   average_demand: float = Field(description="平均需要量")
   weight: float = Field(description="重量")
   class Config:
       schema_extra = {
           "example": {
               "name": "いちご大福",
               "average_demand": 200.,
               "weight": 0.2
           }
       }
       
class TotalDemand(BaseModel):
   cust: str  = Field(description="顧客名")
   prod: str = Field(description="製品名")
   demand: float  = Field(description="需要量")
   class Config:
       schema_extra = {
           "example": {
               "cust": "響本店",
               "prod": "いちご大福",
               "demand": 20.
           }
       }
class MelosGf(BaseModel):
   num_facilities: int = Field(1, description="施設数", gt=1)
   epsilon: float = Field(0.00001, description="誤差", gt=0.)
   max_iter: int = Field(10, description="最大反復数", gt=1)
   seed: int = Field(1, description="乱数の種")
   customers: List[Customer]= Field(description="顧客リスト", default=[])
   products: List[Product] = Field(description="製品リスト", default=[])
   total_demand: List[TotalDemand] = Field(description="総需要リスト", default=[])

サーバーサイドにモデルインスタンスを渡して,結果をJSONで戻す.

main.pyでFastAPIを動かすためのコードを記述してから,サーバーを起動する.

uvicorn main:app --reload

appはコード内で定義されたFastAPIのインスタンスである.

データを入れた辞書をJSONファイルに変換してサーバーに渡すと,サーバー側でモデルインスタンスに変換される.
それをもとに,最適化計算を行い,結果を返す.NumPyの配列が入っているとエラーするので,返り値はリストに変換しておく.するとFastAPIが勝手にJSONにしてくれる.

from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from typing import List, Optional
from pydantic import BaseModel

app = FastAPI(
   title="SCM OPT REST API",
   description="Supply Chain Optimization Functions using REST API",
   version="1.0.0",)
@app.put("/melosgf/")
def solve_melos_gf(model: MelosGf):
   return solve_weiszfeld(model)

呼び出しは以下のように行う.元になるデータはデータフレームから変換して入れる.

import requests
test ={"num_facilities":5, "seed":1, "customers":cust_df.to_dict("records"), "products":prod_df.to_dict("records"),"total_demand":total_demand.to_dict("records")}
URL = "http://127.0.0.1:8000/melosgf"
r = requests.put(URL, data=json.dumps(test))
r.text

結果は以下のようになる.

'{"X":[35.01350991745481,36.654503169280886,33.09944338928921,35.47166691503066,39.64036433809142],"Y":[135.7644851375748,137.30155884486237,130.5265424716167,133.0504404534288,140.87199396073555],"partition":{"20":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"35":0,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1,"18":1,"19":1,"21":1,"34":2,"39":2,"40":2,"41":2,"42":2,"43":2,"44":2,"45":2,"46":2,"30":3,"31":3,"32":3,"33":3,"36":3,"37":3,"38":3,"0":4,"1":4,"2":4,"3":4,"4":4,"5":4,"6":4},"cost":126671550.60208969}'

この記事が気に入ったらサポートをしてみませんか?