Drogon ORMでの安全なページネーション実装とJSON入力チェック

HTTPリクエストからJSONオブジェクトを取得する際、事前にヌルチェックを行わないとセグメンテーションフォールトが発生する可能性があります。

if (!req->getJsonObject()) {
    throw std::invalid_argument("リクエストボディに有効なJSONが含まれていません");
}
auto jsonInput = req->getJsonObject();

DrogonのORM Mapperクラスは、SQL制約(limit, offsetなど)をメソッドチェーン形式でサポートしています。これらの制約は1回のクエリ実行後にクリアされるため、毎回明示的に設定する必要があります。

Mapper<User> userMapper(dbClient);
auto users = userMapper
    .orderBy(User::Cols::_created_at)
    .limit(25)
    .offset(0)
    .findAll();

上記コードは、ユーザーを登録日時でソートし、1ページ目(25件)を取得します。offsetは手動で計算する必要がある点に注意してください。

以下は、安全なページネーション処理の実装例です:

Json::Value response;
response["status"] = "success";

try {
    auto jsonBody = req->getJsonObject();
    if (!jsonBody) {
        throw std::runtime_error("JSONパラメータが必須です");
    }

    int currentPage = (*jsonBody).get("page", 1).asInt();
    int itemsPerPage = (*jsonBody).get("pageSize", 10).asInt();

    if (currentPage < 1 || itemsPerPage < 1) {
        throw std::invalid_argument("pageおよびpageSizeは正の整数である必要があります");
    }

    int skipItems = (currentPage - 1) * itemsPerPage;

    auto db = drogon::app().getDbClient();
    Mapper<Administrator> adminMapper(db);

    auto admins = adminMapper
        .orderBy(Administrator::Cols::_id)
        .limit(itemsPerPage)
        .offset(skipItems)
        .findAll();

    Json::Value result;
    result["total"] = static_cast<int>(admins.size());

    Json::Value adminArray;
    for (const auto& admin : admins) {
        adminArray.append(admin.toJson());
    }
    result["items"] = adminArray;

    response["payload"] = result;
    auto httpResponse = HttpResponse::newHttpJsonResponse(response);
    callback(httpResponse);
} catch (const std::exception& ex) {
    response["status"] = "error";
    response["message"] = ex.what();
    auto errorResp = HttpResponse::newHttpJsonResponse(response);
    errorResp->setStatusCode(k400BadRequest);
    callback(errorResp);
}

Mapperのチェーンメソッドは直感的な命名となっており、詳細はソースコード内のMapper.hを参照してください。

タグ: drogon C++ ORM pagination json-validation

5月24日 08:39 投稿