まとめ未完了 ドキュメ(今日中にやる)
これから触りたいAPI
OpenWeatherMap 天気情報 「今日の天気」を表示
🐶 Dog API 犬の画像を取得できる 「クリックでランダム犬画像」
🧠 Advice Slip ランダムな名言・助言 「元気が出る一言」アプリ
📦 JSONPlaceholder 仮データで練習できる 投稿一覧/新規投稿などのCRUD練習に最適
📅 Holidays API 祝日一覧 カレンダーと組み合わせて使える
ワシが作りたいAPI アイデア
① 投稿→表+PDF出力 Flask + HTML + pdfkit
② Ajaxで通知 Ajax + 通知テーブル + .append() 「PDF作ったよ」 通知
③ Notion APIでメモ取得 .append()で表示
④ LINE Messaging API連携 FlaskでWebhook受信・送信 「こんにちは」で返信させる
⑤ Outlook APIでメール取得 MS Graph API + OAuth認証 メール一覧 Ajaxで表示
⑥ メールPDF化+企業名抽出 pdfkit + reやspaCy PDF生成して正規表現で企業名抽出+CSV保存
#restful APIとは
フロントをVue/ Ajax /スマホアプリにしたい or チーム開発でフロントとバックをわけたい時に便利。
Restful APIの仕組みは、JSONデータを受け取る +受け取ったJsondataの整形。
JsonをSQLAcademyやDBからとってきて加工するには、
必ずMAshmaronがいる。
MAshmaron使用例
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from marshmallow import fields
class User(db.Model):
id = db.Column(db.Integer, primary_key=True, nullable=False, autoincrement=True)
first_name = db.Column(db.String(100), default=None)
last_name = db.Column(db.String(100), default=None)
created_at = db.Column(db.DateTime, default=datetime.now)
updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now)
class UserSchema(ma.SQLAlchemySchema):
class Meta:
model = User
load_instance = True
id = ma.auto_field()
name = ma.auto_field()
email = ma.auto_field()
is_active = ma.auto_field()
first_name = ma.auto_field()
last_name = ma.auto_field()
created_at = fields.DateTime(format='%Y-%m-%dT%H:%M:%S+09:00')
updated_at = fields.DateTime(format='%Y-%m-%dT%H:%M:%S+09:00')
full_name = fields.Method("get_full_name")
def get_full_name(self, obj):
return f"{obj.first_name} {obj.last_name}"
###出力結果
{
"status": "ok",
"users": [
{
"id": 1,
"full_name": "yuto matsuki",
"created_at": "2017-08-19T19:50:39+00:00",
"updated_at": "2017-08-19T19:50:39+00:00"
},
{
...
}
...
]
}
### marshmallowでModelSchemaを定義
class UserSchema(ma.SQLAlchemySchema):
class Meta:
model = User
load_instance = True
id = ma.auto_field()
name = ma.auto_field()
email = ma.auto_field()
is_active = ma.auto_field()
first_name = ma.auto_field()
last_name = ma.auto_field()
created_at = fields.DateTime(format='%Y-%m-%dT%H:%M:%S+09:00')
updated_at = fields.DateTime(format='%Y-%m-%dT%H:%M:%S+09:00')
full_name = fields.Method("get_full_name")
Schemaは「1ユーザー=1行」用。
複数形 guest_list や guests(複数人)は、全体の一覧 → Schemaには入れない
引用元: https://techblog.recochoku.jp/3107
おすすめギッハブ
参考サイト(初心者向け)
### API作り基本(Restful API)
```ruby:
# データ取得 (GET) + .get
users = {
1: {"name": "John", "birthdate": "1990-01-01"},
2: {"name": "Jane", "birthdate": "1995-05-05"}
}
@app.route('/api/user/<int:user_id>', methods=['GET'])
def get_user(user_id):
user = users.get(user_id)
if user:
return jsonify(user) # ユーザー情報をJSONで返す
return jsonify({"message": "User not found"}), 404
# 新規作成 (post)
users = {}
@app.route('/api/user', methods=['POST'])
def add_user():
user_data = request.get_json() # JSONデータを取得
user_id = len(users) + 1 # ユーザーID自動生成
users[user_id] = user_data
return jsonify({"message": "User added", "user_id": user_id}), 201
# 更新 (PUT) + .update
users = {1: {"name": "John", "birthdate": "1990-01-01"}}
@app.route('/api/user/<int:user_id>', methods=['PUT'])
def update_user(user_id):
if user_id in users:
user_data = request.get_json() # 更新するデータを取得
users[user_id].update(user_data) # ユーザー情報を更新
return jsonify({"message": "User updated"}), 200
return jsonify({"message": "User not found"}), 404
# 削除(DELETE) + del [消したいもの]
users = {1: {"name": "John", "birthdate": "1990-01-01"}}
@app.route('/api/user/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
if user_id in users:
del users[user_id] # ユーザー削除
return jsonify({"message": "User deleted"}), 200
return jsonify({"message": "User not found"}), 404
複数人をリストに追加 samplecode
from flask import Flask
from flask_restful import Resource, Api, reqparse
app = Flask(__name__)
api = Api(app)
guest_list = ['Akansh', 'Bill Gates', 'Elon Musk']
parser = reqparse.RequestParser()
parser.add_argument('name', type=str, help='Name of guest')
class GuestList(Resource):
def get(self):
return {'guests': guest_list}, 200
class GuestById(Resource):
def get(self, id):
if id < 0 or id >= len(guest_list):
return {'error': 'Guest not found'}, 404
return {'name': guest_list[id]}, 200
def put(self, id):
args = parser.parse_args()
name = args['name']
if id < 0 or id >= len(guest_list):
return {'error': 'Guest not found'}, 404
guest_list[id] = name
return {'message': 'Updated', 'guests': guest_list}, 200
def delete(self, id):
if id < 0 or id >= len(guest_list):
return {'error': 'Guest not found'}, 404
deleted_name = guest_list.pop(id)
return {'message': f'{deleted_name} deleted', 'guests': guest_list}, 200
class GuestAdd(Resource):
def post(self):
args = parser.parse_args()
name = args['name']
guest_list.append(name)
return {'message': 'Added', 'guests': guest_list}, 201
api.add_resource(GuestList, '/guests')
api.add_resource(GuestById, '/guest/<int:id>')
api.add_resource(GuestAdd, '/guest')
Comment → Post → User スキーマ
from flask_marshmallow import Marshmallow
from marshmallow import fields
ma = Marshmallow()
class UserSchema(ma.SQLAlchemySchema):
class Meta:
model = User
load_instance = True
id = ma.auto_field()
username = ma.auto_field()
class PostSchema(ma.SQLAlchemySchema):
class Meta:
model = Post
load_instance = True
id = ma.auto_field()
content = ma.auto_field()
user = ma.Nested(UserSchema) # ← Post の中に User を入れる!
class CommentSchema(ma.SQLAlchemySchema):
class Meta:
model = Comment
load_instance = True
id = ma.auto_field()
text = ma.auto_field()
post = ma.Nested(PostSchema) # ← Comment の中に Post(→ さらに User)を入れる!
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
db = SQLAlchemy()
ma = Marshmallow()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String)
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.String)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user = db.relationship('User', backref='posts')
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.String)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
post = db.relationship('Post', backref='comments')
{
"id": 1,
"text": "Nice post!",
"post": {
"id": 10,
"content": "Flaskは楽しい!",
"user": {
"id": 5,
"username": "YamadaTarou"
}
}
}
### json出力例
CommentSchema().dump(comment_obj)
リレーションを含める ma.Nested(他のSchema)
複数データをまとめて表示(リスト表示)
comments = Comment.query.all()
CommentSchema(many=True).dump(comments)
class UserSchema(ma.SQLAlchemySchema):
class Meta:
model = User
load_instance = True
id = ma.auto_field()
username = ma.auto_field()
posts = ma.Nested(PostSchema, many=True)
id = fields.Int(dump_only=True) # 出力のみ。入力❌ dump?only = true
password = fields.Str(load_only=True) # 入力だけ。出力には含めない
post = fields.Nested(PostSchema) # Comment スキーマでPostも表示
TypeError: Object of type X is not JSON serializable Nested()がない or many=Trueの付け忘れ
AttributeError: 'dict' object has no attribute load_instance = Trueがないと、dictしか返らない
name = fields.Str(required=True, validate=Length(min=2))
POSTで受け取ったJSONをUserモデルに自動で変換して保存できる : load_instance = True
###IDでゲストを検索し、guest.nameを更新
# PUTリクエストで更新
class GuestUpdate(Resource):
def put(self):
# JSONデータを解析
args = parser.parse_args()
guest_id = args['id']
name = args['name']
# IDでゲストを検索して更新
guest = Guest.query.get(guest_id)
if guest:
guest.name = name # 新しい名前に更新
db.session.commit() # 変更をデータベースに保存
return {'message': 'Guest updated successfully'}
return {'message': 'Guest not found'}, 404
削除するレコードが存在しない場合、または編集する際に、入力値が不正な場合などを事前にチェック
from marshmallow import ValidationError
# 編集時のバリデーション
class GuestUpdate(Resource):
def put(self):
args = parser.parse_args()
guest_id = args['id']
name = args['name']
if len(name) < 3:
raise ValidationError('Name must be at least 3 characters long')
guest = Guest.query.get(guest_id)
if guest:
guest.name = name
db.session.commit()
return {'message': 'Guest updated successfully'}
return {'message': 'Guest not found'}, 404
一括削除 argsの中身が複数形に
# 複数ゲスト削除(DELETEリクエスト)
class BatchDelete(Resource):
def delete(self):
args = parser.parse_args()
guest_ids = args['ids'] # 複数のIDをリストで受け取る
for guest_id in guest_ids:
guest = Guest.query.get(guest_id)
if guest:
db.session.delete(guest)
db.session.commit() # 一括で変更を反映
return {'message': f'{len(guest_ids)} guests deleted successfully'}
###エラー処理 dataがない以外のエラーも必ずつける
except Exception as e:
return {'message': f'Error: {str(e)}'}, 500
guest = Guest.query.get(guest_id)
if guest:
# 処理
return {'message': 'Guest updated successfully'}
else:
return {'message': 'Guest not found'}, 404
except Exception as e:
return {'message': f'Error: {str(e)}'}, 500
Outlookメール +REstfulAPI
Azure ADでアプリ登録 → OAuth 2.0でアクセストークン取得
$.ajax({
type:"GET",
dataType: "json",
data:{'name':'Payam'},
url: "http://mypythonapp-spacepirate.rhcloud.com/hello/",
data: { name: 'Payam' },
dataType: "json",
success: function(data) {
console.log(data); // => {key: "Hello World!", q: "Payam"}
},
error: function(err) {
console.error("AJAX Error:", err);
}
})
# Flaskでこう書く
@app.route('/hello/', methods=['GET'])
def hello_world():
name = request.args.get('name')
response = {'key': 'Hello World!', 'q': name}
return jsonify(response)
mysql接続
from flask import current_app
from flask_sqlalchemy_session import flask_scoped_session
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
class WriteEngine:
def __init__(self):
username = 'hogehoge'
password = 'mogemoge'
hostname = 'localhost'
dbname = 'rest'
charset = 'utf8mb4'
url = f'mysql+mysqldb://{username}:{password}@{hostname}/{dbname}?charset={charset}'
self.engine = create_engine(url, echo=True)
class WriteSession(WriteEngine):
def __init__(self):
super().__init__()
self.session = scoped_session(sessionmaker(bind=self.engine))
セキュリティ対策
https://chatgpt.com/c/6816dfc6-ffc8-8010-86eb-ef079cc666ce
続き
dairy
Dockerより軽 初心者向. : Podman Desktop
→Heroku : Render / Fly.io
管理者機能 いる状況
→ 使うユーザー 多 (不正利用防止)
・ Flaskでレスポンシブ
→ HTMLに " <meta name="viewport" content="width=device-width, initial-scale=1.0">"
デザインパターン編 参考サイト