Web

[Python] BottleでAPIを作成する方法

Bottleは軽量なPythonのWebフレームワークで、簡単にAPIを作成できます。

まず、Bottleをインストールし、bottleモジュールをインポートします。

次に、@routeデコレータを使ってエンドポイントを定義し、HTTPメソッド(GET, POSTなど)に応じた処理を記述します。

最後に、run()関数でサーバーを起動します。

例えば、@route('/api', method='GET')でGETリクエストを処理するAPIを作成できます。

Bottleのインストールとセットアップ

Bottleのインストール方法

BottleはPythonの軽量なWebフレームワークで、簡単にインストールできます。

以下のコマンドを使用して、pipを使ってBottleをインストールします。

pip install bottle

インストールが完了したら、次のコマンドでBottleが正しくインストールされたか確認できます。

pip show bottle

最初のBottleアプリケーションの作成

Bottleを使って最初のアプリケーションを作成してみましょう。

以下のコードをapp.pyというファイルに保存します。

from bottle import Bottle, run
# Bottleアプリケーションのインスタンスを作成
app = Bottle()
# ルートエンドポイントの定義
@app.route('/')
def home():
    return "こんにちは、Bottleの世界へようこそ!"
# アプリケーションの実行
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行すると、http://localhost:8080/にアクセスすることで、”こんにちは、Bottleの世界へようこそ!”というメッセージが表示されます。

Bottleアプリケーションの基本構造

Bottleアプリケーションの基本構造は非常にシンプルです。

以下の要素から成り立っています。

要素説明
Bottleアプリケーションのインスタンスを作成するクラス
@routeURLパスと関数を関連付けるデコレータ
runアプリケーションを実行する関数

この基本構造を理解することで、Bottleを使ったWebアプリケーションの開発がスムーズに進むでしょう。

APIエンドポイントの作成

@routeデコレータの使い方

@routeデコレータは、特定のURLパスに対して処理を行う関数を関連付けるために使用します。

以下の例では、/helloというパスに対してhello関数を関連付けています。

from bottle import Bottle, run
app = Bottle()
@app.route('/hello')
def hello():
    return "こんにちは!"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、http://localhost:8080/helloにアクセスすると、”こんにちは!”というメッセージが表示されます。

GETリクエストの処理

GETリクエストは、データを取得するために使用されます。

以下の例では、/greetエンドポイントにGETリクエストを送信すると、名前を受け取り、挨拶を返します。

from bottle import Bottle, run, request
app = Bottle()
@app.route('/greet')
def greet():
    name = request.query.name or "ゲスト"
    return f"こんにちは、{name}さん!"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、http://localhost:8080/greet?name=太郎にアクセスすると、”こんにちは、太郎さん!”というメッセージが表示されます。

POSTリクエストの処理

POSTリクエストは、データをサーバーに送信するために使用されます。

以下の例では、/submitエンドポイントにPOSTリクエストを送信すると、送信されたデータを受け取ります。

from bottle import Bottle, run, request
app = Bottle()
@app.route('/submit', method='POST')
def submit():
    name = request.forms.get('name')
    return f"受け取った名前: {name}"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、Postmanなどのツールを使って/submitnameフィールドを含むPOSTリクエストを送信すると、受け取った名前が表示されます。

受け取った名前: 太郎

パスパラメータの使用方法

パスパラメータを使用すると、URLの一部を変数として扱うことができます。

以下の例では、/user/<username>というパスを定義し、usernameを受け取ります。

from bottle import Bottle, run
app = Bottle()
@app.route('/user/<username>')
def show_user(username):
    return f"ユーザー名: {username}"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、http://localhost:8080/user/太郎にアクセスすると、”ユーザー名: 太郎”というメッセージが表示されます。

クエリパラメータの処理

クエリパラメータは、URLの末尾に?を付けて指定します。

以下の例では、/searchエンドポイントでクエリパラメータを処理します。

from bottle import Bottle, run, request
app = Bottle()
@app.route('/search')
def search():
    query = request.query.q
    return f"検索キーワード: {query}"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、http://localhost:8080/search?q=Pythonにアクセスすると、”検索キーワード: Python”というメッセージが表示されます。

JSONデータの送受信

Bottleでは、JSONデータの送受信も簡単に行えます。

以下の例では、JSON形式のデータを受け取り、レスポンスとしてJSONを返します。

from bottle import Bottle, run, request, response
import json
app = Bottle()
@app.route('/json', method='POST')
def json_endpoint():
    data = request.json
    response.content_type = 'application/json'
    return json.dumps({"message": f"受け取ったデータ: {data}"})
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、Postmanなどのツールを使ってJSONデータを含むPOSTリクエストを/jsonに送信すると、受け取ったデータがJSON形式で返されます。

{"message": "受け取ったデータ: {'key': 'value'}"}

エラーハンドリング

404エラーの処理

404エラーは、リクエストされたページが見つからない場合に発生します。

Bottleでは、404エラーをカスタマイズすることができます。

以下の例では、404エラーが発生した際にカスタムメッセージを返すように設定しています。

from bottle import Bottle, run, abort
app = Bottle()
@app.route('/')
def home():
    return "ホームページ"
@app.route('/<path:path>')
def catch_all(path):
    abort(404)  # 404エラーを発生させる
@app.error(404)
def error404(error):
    return "404 エラー: ページが見つかりません。"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、存在しないパスにアクセスすると、”404 エラー: ページが見つかりません。”というメッセージが表示されます。

カスタムエラーメッセージの作成

Bottleでは、特定のエラーコードに対してカスタムメッセージを設定することができます。

以下の例では、500エラー(サーバーエラー)のカスタムメッセージを作成しています。

from bottle import Bottle, run, abort
app = Bottle()
@app.route('/error')
def error_route():
    abort(500)  # 500エラーを発生させる
@app.error(500)
def error500(error):
    return "500 エラー: サーバー内部のエラーが発生しました。"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、http://localhost:8080/errorにアクセスすると、”500 エラー: サーバー内部のエラーが発生しました。”というメッセージが表示されます。

例外処理の実装

Bottleでは、例外処理を実装することで、予期しないエラーが発生した際に適切なレスポンスを返すことができます。

以下の例では、特定の例外をキャッチしてカスタムメッセージを返します。

from bottle import Bottle, run, response
app = Bottle()
@app.route('/divide/<num1>/<num2>')
def divide(num1, num2):
    try:
        result = int(num1) / int(num2)
        return f"結果: {result}"
    except ZeroDivisionError:
        response.status = 400  # Bad Request
        return "エラー: ゼロで割ることはできません。"
    except ValueError:
        response.status = 400  # Bad Request
        return "エラー: 数値を入力してください。"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、http://localhost:8080/divide/10/0にアクセスすると、”エラー: ゼロで割ることはできません。”というメッセージが表示されます。

また、http://localhost:8080/divide/10/abcにアクセスすると、”エラー: 数値を入力してください。”というメッセージが表示されます。

ミドルウェアの利用

ミドルウェアとは

ミドルウェアは、リクエストとレスポンスの間で処理を行うコンポーネントです。

リクエストがアプリケーションに到達する前や、レスポンスがクライアントに送信される前に、特定の処理を挿入することができます。

これにより、ロギング、認証、セッション管理などの機能を簡単に追加できます。

Bottleでのミドルウェアの設定方法

Bottleでは、ミドルウェアを簡単に設定できます。

以下の例では、リクエストの開始時にメッセージを表示するミドルウェアを作成しています。

from bottle import Bottle, run, request
app = Bottle()
# ミドルウェアの定義
@app.middleware
def simple_middleware(app, environ, start_response):
    print("リクエストが処理される前に実行されます。")
    return app(environ, start_response)
@app.route('/')
def home():
    return "ホームページ"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、http://localhost:8080/にアクセスすると、コンソールに”リクエストが処理される前に実行されます。”というメッセージが表示されます。

ログ記録の実装

ミドルウェアを使用して、リクエストのログを記録することもできます。

以下の例では、リクエストのメソッドとパスをログに記録します。

from bottle import Bottle, run, request
app = Bottle()
@app.middleware
def log_middleware(app, environ, start_response):
    method = environ['REQUEST_METHOD']
    path = environ['PATH_INFO']
    print(f"リクエスト: {method} {path}")
    return app(environ, start_response)
@app.route('/')
def home():
    return "ホームページ"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、http://localhost:8080/にアクセスすると、コンソールにリクエストのメソッドとパスが表示されます。

認証の実装

ミドルウェアを使用して、簡単な認証機能を実装することも可能です。

以下の例では、特定のパスにアクセスする際に、認証トークンをチェックします。

from bottle import Bottle, run, request, abort
app = Bottle()
@app.middleware
def auth_middleware(app, environ, start_response):
    token = request.query.get('token')
    if token != 'secret_token':
        abort(403)  # Forbidden
    return app(environ, start_response)
@app.route('/protected')
def protected():
    return "このページは保護されています。"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、http://localhost:8080/protectedにアクセスすると、403エラーが発生します。

http://localhost:8080/protected?token=secret_tokenにアクセスすると、”このページは保護されています。”というメッセージが表示されます。

データベースとの連携

SQLiteとの連携

SQLiteは、軽量で使いやすいデータベースです。

BottleとSQLiteを連携させることで、簡単にデータの保存や取得ができます。

以下の例では、SQLiteデータベースに接続し、データを挿入および取得する方法を示します。

import sqlite3
from bottle import Bottle, run, request, response
app = Bottle()
# SQLiteデータベースの接続
def get_db_connection():
    conn = sqlite3.connect('example.db')
    conn.row_factory = sqlite3.Row
    return conn
# テーブルの作成
@app.route('/setup')
def setup():
    conn = get_db_connection()
    conn.execute('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)')
    conn.commit()
    conn.close()
    return "テーブルが作成されました。"
# ユーザーの追加
@app.route('/add_user', method='POST')
def add_user():
    name = request.forms.get('name')
    conn = get_db_connection()
    conn.execute('INSERT INTO users (name) VALUES (?)', (name,))
    conn.commit()
    conn.close()
    return f"ユーザー {name} が追加されました。"
# ユーザーの取得
@app.route('/users')
def get_users():
    conn = get_db_connection()
    users = conn.execute('SELECT * FROM users').fetchall()
    conn.close()
    return {'users': [dict(user) for user in users]}
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、/setupエンドポイントにアクセスしてテーブルを作成した後、/add_userにPOSTリクエストを送信してユーザーを追加し、/usersにアクセスすると、追加したユーザーのリストが表示されます。

MySQLとの連携

MySQLデータベースと連携するには、mysql-connector-pythonライブラリを使用します。

以下の例では、MySQLデータベースに接続し、データを挿入および取得する方法を示します。

import mysql.connector
from bottle import Bottle, run, request, response
app = Bottle()
# MySQLデータベースの接続
def get_db_connection():
    return mysql.connector.connect(
        host='localhost',
        user='your_username',
        password='your_password',
        database='your_database'
    )
# ユーザーの追加
@app.route('/add_user', method='POST')
def add_user():
    name = request.forms.get('name')
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute('INSERT INTO users (name) VALUES (%s)', (name,))
    conn.commit()
    cursor.close()
    conn.close()
    return f"ユーザー {name} が追加されました。"
# ユーザーの取得
@app.route('/users')
def get_users():
    conn = get_db_connection()
    cursor = conn.cursor(dictionary=True)
    cursor.execute('SELECT * FROM users')
    users = cursor.fetchall()
    cursor.close()
    conn.close()
    return {'users': users}
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、MySQLデータベースに接続してユーザーを追加し、リストを取得することができます。

接続情報は適宜変更してください。

ORMの導入と使用方法

ORM(Object-Relational Mapping)を使用すると、データベース操作をオブジェクト指向で行うことができます。

ここでは、SQLAlchemyを使用したORMの導入と使用方法を示します。

まず、SQLAlchemyをインストールします。

pip install sqlalchemy

次に、以下のコードを使用して、SQLAlchemyを使ったデータベース操作を行います。

from bottle import Bottle, run, request
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
app = Bottle()
Base = declarative_base()
engine = create_engine('sqlite:///example.db')
Session = sessionmaker(bind=engine)
# ユーザーモデルの定義
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String)
# テーブルの作成
Base.metadata.create_all(engine)
# ユーザーの追加
@app.route('/add_user', method='POST')
def add_user():
    name = request.forms.get('name')
    session = Session()
    new_user = User(name=name)
    session.add(new_user)
    session.commit()
    session.close()
    return f"ユーザー {name} が追加されました。"
# ユーザーの取得
@app.route('/users')
def get_users():
    session = Session()
    users = session.query(User).all()
    session.close()
    return {'users': [{'id': user.id, 'name': user.name} for user in users]}
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行すると、SQLAlchemyを使用してSQLiteデータベースにユーザーを追加し、リストを取得することができます。

ORMを使用することで、データベース操作がより直感的に行えるようになります。

Bottleアプリケーションのデプロイ

ローカル開発環境での実行

Bottleアプリケーションをローカル開発環境で実行するのは非常に簡単です。

以下の手順で実行できます。

まず、アプリケーションのコードをapp.pyというファイルに保存します。

次に、以下のように実行します。

from bottle import Bottle, run
app = Bottle()
@app.route('/')
def home():
    return "ホームページ"
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行するには、ターミナルで次のコマンドを入力します。

python app.py

ブラウザでhttp://localhost:8080/にアクセスすると、アプリケーションが表示されます。

WSGIサーバーでのデプロイ

Bottleアプリケーションを本番環境で実行する場合、WSGIサーバーを使用することが推奨されます。

以下の例では、gunicornを使用してBottleアプリケーションをデプロイします。

まず、gunicornをインストールします。

pip install gunicorn

次に、以下のコマンドを使用してアプリケーションを実行します。

gunicorn -w 4 app:app

ここで、-w 4は4つのワーカーを指定しています。

これにより、同時に複数のリクエストを処理できるようになります。

アプリケーションはデフォルトでhttp://127.0.0.1:8000で実行されます。

Herokuへのデプロイ

Herokuは、アプリケーションを簡単にデプロイできるクラウドプラットフォームです。

以下の手順でBottleアプリケーションをHerokuにデプロイします。

  1. Heroku CLIのインストール: Heroku CLIをインストールします。
  2. Herokuアカウントの作成: Herokuのアカウントを作成します。
  3. アプリケーションの作成: ターミナルで以下のコマンドを実行して新しいHerokuアプリを作成します。
heroku create your-app-name
  1. requirements.txtの作成: アプリケーションの依存関係を記述したrequirements.txtファイルを作成します。
bottle
gunicorn
  1. Procfileの作成: アプリケーションの起動コマンドを指定するProcfileを作成します。
web: gunicorn app:app
  1. アプリケーションのデプロイ: 以下のコマンドでアプリケーションをHerokuにデプロイします。
git init
git add .
git commit -m "Initial commit"
git push heroku master
  1. アプリケーションの起動: デプロイが完了したら、以下のコマンドでアプリケーションを起動します。
heroku open

これで、Heroku上でBottleアプリケーションが実行されます。

Dockerを使ったデプロイ

Dockerを使用すると、アプリケーションをコンテナ化して簡単にデプロイできます。

以下の手順でBottleアプリケーションをDockerでデプロイします。

  1. Dockerfileの作成: アプリケーションのルートディレクトリにDockerfileを作成します。
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "-w", "4", "app:app", "-b", "0.0.0.0:8000"]
  1. requirements.txtの作成: アプリケーションの依存関係を記述したrequirements.txtファイルを作成します。
bottle
gunicorn
  1. Dockerイメージのビルド: 以下のコマンドでDockerイメージをビルドします。
docker build -t bottle-app .
  1. Dockerコンテナの実行: 以下のコマンドでDockerコンテナを実行します。
docker run -d -p 8000:8000 bottle-app

これで、http://localhost:8000でBottleアプリケーションにアクセスできるようになります。

Dockerを使用することで、アプリケーションの環境を簡単に管理できます。

Bottleを使ったAPIの応用例

シンプルなTodoリストAPIの作成

シンプルなTodoリストAPIを作成することで、タスクの追加、取得、削除ができるアプリケーションを実装します。

以下のコードでは、SQLiteを使用してTodoリストを管理します。

import sqlite3
from bottle import Bottle, run, request, response
app = Bottle()
# SQLiteデータベースの接続
def get_db_connection():
    conn = sqlite3.connect('todo.db')
    conn.row_factory = sqlite3.Row
    return conn
# テーブルの作成
@app.route('/setup')
def setup():
    conn = get_db_connection()
    conn.execute('CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY, task TEXT)')
    conn.commit()
    conn.close()
    return "Todoリストのテーブルが作成されました。"
# Todoの追加
@app.route('/todos', method='POST')
def add_todo():
    task = request.forms.get('task')
    conn = get_db_connection()
    conn.execute('INSERT INTO todos (task) VALUES (?)', (task,))
    conn.commit()
    conn.close()
    return {"message": "Todoが追加されました。"}
# Todoの取得
@app.route('/todos', method='GET')
def get_todos():
    conn = get_db_connection()
    todos = conn.execute('SELECT * FROM todos').fetchall()
    conn.close()
    return {'todos': [dict(todo) for todo in todos]}
# Todoの削除
@app.route('/todos/<id>', method='DELETE')
def delete_todo(id):
    conn = get_db_connection()
    conn.execute('DELETE FROM todos WHERE id = ?', (id,))
    conn.commit()
    conn.close()
    return {"message": "Todoが削除されました。"}
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、/setupエンドポイントでテーブルを作成した後、/todosにPOSTリクエストを送信してタスクを追加し、GETリクエストでタスクを取得、DELETEリクエストでタスクを削除できます。

ユーザー認証APIの作成

ユーザー認証APIを作成することで、ユーザーの登録とログイン機能を実装します。

以下のコードでは、SQLiteを使用してユーザー情報を管理します。

import sqlite3
from bottle import Bottle, run, request, response
app = Bottle()
# SQLiteデータベースの接続
def get_db_connection():
    conn = sqlite3.connect('users.db')
    conn.row_factory = sqlite3.Row
    return conn
# テーブルの作成
@app.route('/setup')
def setup():
    conn = get_db_connection()
    conn.execute('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, username TEXT, password TEXT)')
    conn.commit()
    conn.close()
    return "ユーザーテーブルが作成されました。"
# ユーザーの登録
@app.route('/register', method='POST')
def register():
    username = request.forms.get('username')
    password = request.forms.get('password')
    conn = get_db_connection()
    conn.execute('INSERT INTO users (username, password) VALUES (?, ?)', (username, password))
    conn.commit()
    conn.close()
    return {"message": "ユーザーが登録されました。"}
# ユーザーのログイン
@app.route('/login', method='POST')
def login():
    username = request.forms.get('username')
    password = request.forms.get('password')
    conn = get_db_connection()
    user = conn.execute('SELECT * FROM users WHERE username = ? AND password = ?', (username, password)).fetchone()
    conn.close()
    if user:
        return {"message": "ログイン成功!"}
    else:
        response.status = 401
        return {"message": "ログイン失敗。ユーザー名またはパスワードが間違っています。"}
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、/setupエンドポイントでテーブルを作成した後、/registerにPOSTリクエストを送信してユーザーを登録し、/loginにPOSTリクエストを送信してログインできます。

外部APIとの連携

外部APIと連携することで、他のサービスからデータを取得したり、データを送信したりできます。

以下の例では、JSONPlaceholderという外部APIからデータを取得します。

import requests
from bottle import Bottle, run
app = Bottle()
@app.route('/posts')
def get_posts():
    response = requests.get('https://jsonplaceholder.typicode.com/posts')
    return response.json()
if __name__ == '__main__':
    run(app, host='localhost', port=8080)

このコードを実行し、http://localhost:8080/postsにアクセスすると、JSONPlaceholderから取得した投稿データが表示されます。

WebSocketを使ったリアルタイムAPIの作成

WebSocketを使用することで、リアルタイム通信が可能なAPIを作成できます。

以下の例では、Bottleとgeventを使用してWebSocketを実装します。

まず、geventをインストールします。

pip install gevent

次に、以下のコードを使用してWebSocketを実装します。

from bottle import Bottle, run, template
from bottle_websocket import WebSocketPlugin, websocket
app = Bottle()
app.install(WebSocketPlugin())
# WebSocket接続
@app.websocket('/ws')
def ws_handler(ws):
    while True:
        message = ws.receive()
        if message is not None:
            ws.send(f"受信したメッセージ: {message}")
if __name__ == '__main__':
    run(app, host='localhost', port=8080, server='gevent')

このコードを実行し、WebSocketクライアントを使用してws://localhost:8080/wsに接続すると、メッセージを送信し、受信したメッセージを確認できます。

リアルタイムでの双方向通信が可能になります。

まとめ

この記事では、Bottleを使用してAPIを作成する方法や、データベースとの連携、エラーハンドリング、ミドルウェアの利用、さらには実際の応用例について詳しく解説しました。

Bottleはシンプルで軽量なフレームワークであり、特に小規模から中規模のプロジェクトに適しているため、開発者はその特性を活かして効率的にアプリケーションを構築することが可能です。

これを機に、Bottleを使ったプロジェクトに挑戦してみてはいかがでしょうか。

関連記事

Back to top button
目次へ