Pythonで認証・CRUD無しの簡易APIサーバを作る方法

Pythonで本格的なAPIサーバを作ろうとすると「Django REST Framework」が真っ先に思い浮かぶと思いますが、簡易的にAPIレスポンスが欲しい時もあると思います。

ここでは、ローカルホスト上でPythonから、認証・CRUD無しでhttpレスポンスを返す方法を2つ紹介します。

### 注意事項
下記方法ではCSRFの対策を行なっていません。
本番環境で使用する際には、他の方法で正しい(想定したサイトの想定したユーザーから受け取った)リクエストかどうかを検証する必要があります。

# Python WSGI を使う方法
一番簡易的に使えるのは、Pythonの標準インターフェイスであるWSGI(Web Server Gateway Interface)を使う方法です。

WSGIの詳細について、調べれば詳しい記載が出てくると思いますが、今回は簡単にPOSTされたデータを返すAPIサーバを例に挙げます。

```python:test_api.py
from wsgiref.simple_server import make_server
import json

def app(environ, start_response):
    # POST dataの取得
    query = environ['wsgi.input'].read(int(environ.get('CONTENT_LENGTH', 0))).decode('utf-8')

    # レスポンスヘッダの作成
    status = "200 OK"
    headers = [
        ("Content-type", "application/json; charset=utf-8"),
        ("Access-Control-Allow-Origin", "*"),
    ]

    if query == "":
        # POSTが空だった時の処理
        response_json = {"message": "Data not sent."}
    else:
        # JSONをPythonの辞書型に変換
        loaded_query = json.loads(query)

        # JSONの中身を記述
        response_json = {
            "message": "This is response data!",
            "query_data": loaded_query,
        }

    start_response(status, headers)
    return [json.dumps(response_json).encode("utf-8")]


with make_server("", 8000, app) as httpd:
    print("Serving on port 8000...")
    httpd.serve_forever()
```
一つのターミナルでサーバを起動します。

```bash:shell-1
$ python test_api.py 
>> Serving on port 8000...
```

上とは別のターミナルを起動し、挙動を確認します。

```bash:shell-2
$ curl -X POST -H "Content-TyGET application/json" -d '{"data":"hoge"}' localhost:8000
>> {"message": "This is response data!", "query_data": {"data": "hoge"}}
```

これでWGISを利用した、簡易的なAPIサーバの完成です。

# Djangoを使う方法
PythonのWebフレームワークであるDjangoを使い、APIレスポンスを返す `views.py` を作成することで実現することもできます。

WSGIを直接操作した場合に比べて、環境構築が必要ですが、DjangoがWSGIをラップしてくれているので、データ操作が簡単なメリットがあります。

またDjangoの場合、デフォルトでCSRFの検証を行うため、APIのレスポンスサーバとしてこれを無効にする処理を書かないと、エラーになってしまうので注意が必要です。

```bash:shell
$ mkdir 作業フォルダ
$ cd 作業フォルダ
$ django-admin startproject config .
$ python manage.py startapp api
```

```python:config/urls.py
from django.contrib import admin
from django.urls import path, include #"include"を追加

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('api.urls')), #追加
]
```
下記ファイルを追加

```python:api/urls.py
from django.urls import path
from . import views

app_name = 'api'
urlpatterns = [
    path('', views.index, name='api'),   
]
```
下記ファイルを編集

```python:api/views.py
from django.views.decorators.csrf import csrf_exempt
from django.http.response import JsonResponse
import json

@csrf_exempt
def index(request):
    # GET時の処理
    if request.method == 'GET':
        return JsonResponse({"message": "This is GET respons."})

    # POST dataの取得
    if request.body == b"":
        return JsonResponse({"message": "Data not sent."})
    query = request.body.decode("utf-8")

    # JSONをPythonの辞書型に変換
    loaded_query = json.loads(query)

    # JSONの中身を記述
    response_json = {
        "message": "This is response data!",
        "query_data": loaded_query,
    }

    # JSONに変換して戻す
    return JsonResponse(response_json)
```
一つのターミナルでサーバを起動します。

```bash:shell-1
$ python manage.py runserver
>> Django version 3.x.x, using settings 'config.settings'
   Starting development server at http://127.0.0.1:8000/
   Quit the server with CONTROL-C.
```

上とは別のターミナルを起動し、挙動を確認します。

```bash:shell-2
$ curl -X POST -H "Content-TyGET application/json" -d '{"data":"foo"}' localhost:8000/api/
>> {"message": "This is response data!", "query_data": {"data": "foo"}}
```

これでDjangoを利用した、簡易的なAPIサーバの完成です。