ホーム › 技術仕様 & API
テスト実装ガイド
Game8 Storeと連携し、GET /check(購入可否チェック)および POST /register(購入登録)を簡単なテスト実装で試す方法を紹介します。
所要時間目安:15分
1. エンドポイントの実装(目安:10分)
1.1 必要な環境
- Node.js(Express)または Python(FastAPI) を使用
- サーバーをローカルまたはクラウド(AWS, GCP, Vercel, Renderなど)にデプロイ可能な状態
1.2 Node.js(Express)での実装
const express = require("express");
const cors = require("cors");
const crypto = require("crypto");
const app = express();
app.use(express.json());
app.use(cors());
const VALID_ACCESS_TOKEN = "your_access_token";
const SECRET_KEY = "your_secret_key";
// 認証ミドルウェア
app.use((req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).json({ result_code: "PUB1001", message: "認証情報が不足しています" });
}
const [scheme, token] = authHeader.split(" ");
if (scheme !== "Bearer" || token !== VALID_ACCESS_TOKEN) {
return res.status(401).json({ result_code: "PUB1002", message: "無効なアクセストークンです" });
}
next();
});
// X-Signature 検証ミドルウェア
const verifySignature = (req, res, next) => {
const signature = req.headers["x-signature"];
if (!signature) {
return res.status(400).json({ result_code: "PUB1004", message: "署名がありません" });
}
const requestData = req.method === "GET" ? req.query : req.body
const payload = JSON.stringify(requestData);
const computedSignature = crypto.createHmac("sha256", SECRET_KEY).update(payload).digest("base64");
if (signature !== computedSignature) {
return res.status(400).json({ result_code: "PUB1004", message: "署名が無効です" });
}
next();
};
// 購入可否チェック(アイテム確保対応)
app.get("/check", verifySignature, (req, res) => {
const { game, user, item, price, transaction_id } = req.query;
if (!game || !user || !item || !price || !transaction_id || isNaN(price)) {
return res.status(400).json({ result_code: "PUB2001", message: "必須パラメータ不足または無効な値" });
}
res.json({
request_id: "abc123",
timestamp: new Date().toISOString(),
result_code: "PUB0000",
message: "購入可能",
purchasable: "available",
age_category: "under_18",
account_limit: { total: 10000, remaining: 5000 },
requested_price: Number(price),
transaction_id: transaction_id
});
});
// 購入登録
app.post("/register", verifySignature, (req, res) => {
try {
const { game, user, item, transaction_id, item_name, price, quantity } = req.body;
if (!game || !user || !item || !transaction_id || !item_name || !price || !quantity || isNaN(price) || isNaN(quantity)) {
return res.status(400).json({ result_code: "PUB2001", message: "必須パラメータ不足または無効な値" });
}
res.json({
request_id: "def456",
timestamp: new Date().toISOString(),
result_code: "PUB0000",
message: "購入実績を登録しました。",
item_granted: true,
transaction_id: transaction_id
});
} catch (error) {
res.status(500).json({ result_code: "PUB5000", message: "内部サーバーエラー" });
}
});
app.listen(3000, () => console.log("Server running on port 3000"));
1.3 Python(FastAPI)での実装
from fastapi import FastAPI, Request, HTTPException, Header, Depends
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import hmac
import hashlib
import base64
import json
from datetime import datetime
from typing import Optional
from urllib.parse import urlencode
app = FastAPI()
# CORSミドルウェアの設定
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
SECRET_KEY = "your_secret_key"
VALID_ACCESS_TOKEN = "your_access_token"
# リクエストモデル
class RegisterRequest(BaseModel):
game: str
user: str
item: str
transaction_id: str
item_name: str
price: int
quantity: int
# 認証の依存関数
async def verify_auth(authorization: Optional[str] = Header(None)):
if not authorization:
raise HTTPException(
status_code=401,
detail={"result_code": "PUB1001", "message": "認証情報が不足しています"}
)
if authorization != f"Bearer {VALID_ACCESS_TOKEN}":
raise HTTPException(
status_code=401,
detail={"result_code": "PUB1002", "message": "無効なアクセストークンです"}
)
return True
# 署名検証の依存関数(GETリクエスト用)
async def verify_signature_get(request: Request, x_signature: Optional[str] = Header(None)):
if not x_signature:
raise HTTPException(
status_code=400,
detail={"result_code": "PUB1004", "message": "署名がありません"}
)
# クエリパラメータを取得
query_params = dict(request.query_params)
payload = urlencode(query_params)
# 署名を計算
computed_signature = base64.b64encode(
hmac.new(SECRET_KEY.encode(), payload.encode(), hashlib.sha256).digest()
).decode()
if x_signature != computed_signature:
raise HTTPException(
status_code=400,
detail={"result_code": "PUB1004", "message": "署名が無効です"}
)
return True
# 署名検証の依存関数(POSTリクエスト用)
async def verify_signature_post(request: Request, x_signature: Optional[str] = Header(None)):
if not x_signature:
raise HTTPException(
status_code=400,
detail={"result_code": "PUB1004", "message": "署名がありません"}
)
# リクエストボディを取得
body_bytes = await request.body()
if not body_bytes:
raise HTTPException(
status_code=400,
detail={"result_code": "PUB2001", "message": "必須パラメータ不足または無効な値"}
)
# JSONとしてパース
try:
body_json = json.loads(body_bytes)
payload = json.dumps(body_json)
except json.JSONDecodeError:
raise HTTPException(
status_code=400,
detail={"result_code": "PUB2001", "message": "無効なJSONフォーマット"}
)
# 署名を計算
computed_signature = base64.b64encode(
hmac.new(SECRET_KEY.encode(), payload.encode(), hashlib.sha256).digest()
).decode()
if x_signature != computed_signature:
raise HTTPException(
status_code=400,
detail={"result_code": "PUB1004", "message": "署名が無効です"}
)
return True
@app.get("/check")
async def check(
game: str,
user: str,
item: str,
price: int,
transaction_id: str,
_auth: bool = Depends(verify_auth),
_sig: bool = Depends(verify_signature_get)
):
return {
"request_id": "abc123",
"timestamp": datetime.utcnow().isoformat(),
"result_code": "PUB0000",
"message": "購入可能",
"purchasable": "available",
"age_category": "under_18",
"account_limit": {"total": 10000, "remaining": 5000},
"requested_price": price,
"transaction_id": transaction_id
}
@app.post("/register")
async def register(
request: RegisterRequest,
_auth: bool = Depends(verify_auth),
_sig: bool = Depends(verify_signature_post)
):
try:
return {
"request_id": "def456",
"timestamp": datetime.utcnow().isoformat(),
"result_code": "PUB0000",
"message": "購入実績を登録しました。",
"item_granted": True,
"transaction_id": request.transaction_id
}
except Exception as e:
raise HTTPException(
status_code=500,
detail={"result_code": "PUB5000", "message": "内部サーバーエラー"}
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=3000)2. Postmanを使ったテスト(目安:5分)
Authorizationヘッダーに Bearer your_access_token 、X-Signature に算定した署名を設定した上で以下のリクエストを試す
※本ページのサンプルは疎通確認用の最小構成です。実際のリクエスト・レスポンスの全項目はAPI仕様書をご参照ください。
2.1 GET /check のリクエスト例
GET http://localhost:3000/check
X-Signature: <SIGNED_DATA>
{
"game": "game123",
"user": "user456",
"item": "item789",
"transaction_id": "txn_123456",
"price": 500
}レスポンス例:
{
"request_id": "abc123",
"timestamp": "2025-02-27T12:00:00Z",
"result_code": "PUB0000",
"message": "購入可能",
"purchasable": true,
"transaction_id": "txn_123456"
}
2.2 POST /register のリクエスト例
POST http://localhost:3000/register
Content-Type: application/json
X-Signature: <SIGNED_DATA>
{
"game": "game123",
"user": "user456",
"item": "item789",
"transaction_id": "txn_123456",
"item_name": "100ジェム",
"price": 500,
"quantity": 1
}
レスポンス例:
{
"request_id": "def456",
"timestamp": "2025-02-27T12:00:00Z",
"result_code": "PUB0000",
"message": "購入実績を登録しました。",
"item_granted": true,
"transaction_id": "txn_123456"
}