Skip to content

C++ SDK#1421

Open
bhardwajparth51 wants to merge 39 commits intoappwrite:masterfrom
bhardwajparth51:feat/cpp-sdk-generator
Open

C++ SDK#1421
bhardwajparth51 wants to merge 39 commits intoappwrite:masterfrom
bhardwajparth51:feat/cpp-sdk-generator

Conversation

@bhardwajparth51
Copy link
Copy Markdown
Contributor

@bhardwajparth51 bhardwajparth51 commented Apr 4, 2026

What does this PR do?

Adds a modern, production-ready C++ SDK generator targeting the C++20 standard.
This implementation focuses on high performance, thread-safety, and a seamless developer
experience through a monolithic header-only architecture and coroutine-compatible async dispatch.


Key Features

  • Monolithic Header-only: Simple integration with a single include/appwrite/appwrite.hpp entry point. No separate compilation units required.
  • Concurrent Dispatch via ThreadPool: All API calls are dispatched onto a dedicated ThreadPool, enabling concurrent execution across multiple threads. The Task<T> type provides a coroutine-compatible interface (co_await / .get()). Note: true non-blocking I/O would require an async runtime (Asio/libuv), which is intentionally out of scope for this SDK.
  • Robust Transport Layer: Full support for chunked multi-part uploads, binary responses (callBytes), and complex JSON serialization.
  • Topological Model Sorting: Automatically resolves circular dependencies in model definitions at generation time.
  • Thread-Safety: The Client uses a copy-on-write config pattern via shared_ptr<const Config> with mutex protection, making it safe for concurrent use across multiple threads.

Production Hardening

  • Designated initializers for InputFile::Progress (C++20 compliant, order-safe).
  • Error type extraction in verify() — extracts the namespaced "type" field from error JSON and passes it to ServerException for richer error context.
  • Safe coroutine exception wrapping in makeResolvedTask — exceptions captured by std::future are caught and returned as Result<T>::Err rather than propagating as raw exceptions.
  • PHP-style array serialization — GET and Multipart parameters backed by arrays are serialized with the [] suffix (e.g. k[]=v1&k[]=v2).
  • Geospatial Nesting: Corrected to the 4-level array format required by the Appwrite backend for all query types.

Test Plan

  1. Integration Verification: 444 assertions passing across the full Appwrite integration test suite, covering:
    • Full REST lifecycle against the Appwrite Mock API.
    • Large file chunked uploads with x-appwrite-id propagation.
    • Binary response handling and HTTP error model parsing.
    • Query, Permission, and ID helper correctness.
  2. CI Compliance: test.sh executes the suite within the mockapi Docker network. The build-validation CI step compiles headers without running integration tests, keeping CI fast.

Verified output (condensed):

x-sdk-name: cpp; x-sdk-platform: server; x-sdk-language: cpp; x-sdk-version: 0.0.1
GET:/v1/mock/tests/foo:passed
POST:/v1/mock/tests/foo:passed
...
OK (1 test, 444 assertions)

@bhardwajparth51 bhardwajparth51 force-pushed the feat/cpp-sdk-generator branch 8 times, most recently from 76958b4 to 6fe7d9c Compare April 7, 2026 16:02
@bhardwajparth51 bhardwajparth51 marked this pull request as ready for review April 7, 2026 16:08
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 7, 2026

Greptile Summary

This PR adds a C++ SDK generator targeting C++20, and represents substantial iteration over a previous round of review: the vast majority of the 50+ previously flagged issues have been resolved. The generated examples/cpp/ output now exists, all template files are registered in getFiles(), the Dockerfile pre-builds dependencies, test.sh passes the correct cmake flags, ID::unique() returns a 20-char hex string, model ADL hooks are present, fileUpload exceptions are wrapped, and the integration test output order matches $expectedOutput.

  • P1: model_test.cpp.twig only catches nlohmann::json::exception in the GTest round-trip fixture. DeserializationException (a std::exception subclass thrown by fromJson for required-but-null fields) propagates unhandled and causes GTest to report a test failure (not a skip), which would fail CI. Adding catch (const std::exception& e) { GTEST_SKIP() << e.what(); } after the existing catch block fixes it.

Confidence Score: 3/5

The PR has addressed the vast majority of prior issues but carries the known complexity of a brand-new language SDK; one remaining P1 in the model test fixture could break CI.

Extensive iteration has resolved 50+ previously flagged bugs. One new P1 remains: model_test.cpp.twig does not catch DeserializationException, which can cause GTest to report failures in CI. Score reflects meaningful progress but the need to close that gap before the test suite is reliably green.

templates/cpp/tests/model_test.cpp.twig — catch scope must be widened to cover std::exception.

Important Files Changed

Filename Overview
templates/cpp/tests/model_test.cpp.twig Round-trip serialization tests for all model definitions, but the catch scope only handles nlohmann::json::exception, leaving DeserializationException (subclass of std::exception) uncaught — GTest reports a failure instead of a skip if any required field is null in example data.
templates/cpp/include/client.hpp.twig Core HTTP transport layer; Content-Type, x-appwrite-id propagation, array GET expansion, and fileUpload exception wrapping are all now present. dispatchAsync/makeResolvedTask correctly block on f->get() (documented limitation). No new issues identified.
templates/cpp/include/base.hpp.twig Defines AppwriteException, Result<T>, Task<T>, BinaryResponse, and SocketBackend. error() returns by value (no dangling reference). Task<T> is correctly awaitable and its get() blocks via future::get().
templates/cpp/include/models.hpp.twig Required-field guards use has_value() correctly; from_json/to_json ADL hooks added; sub_schema optional wrapping is now applied.
templates/cpp/include/services.hpp.twig Uses parameterDispatchBlock/parameterDispatchAsyncBlock PHP filters for correct type-aware dispatch; Realtime guarded behind #ifdef APPWRITE_ENABLE_REALTIME; double-wrapped Result<Result<T>> issue resolved.
templates/cpp/include/enums/enums.hpp.twig Generates from_json/to_json ADL hooks for each enum; correctly placed inside namespace appwrite::enums.
templates/cpp/include/core.hpp.twig ID::unique() now generates a 20-char random hex string. distanceEqual 6-arg developer asserts 444 assertions pass against this implementation.
templates/cpp/tests/integration_logic.cpp.twig Correctly exercises FOO/BAR (5 each), UPLOAD (4), DOWNLOAD (1), EXCEPTION (7) responses using the Result<T> API. Resource directory read from APPWRITE_RESOURCE_DIR env var.
templates/cpp/tests/integration.cpp.twig Prints "Test Started" first, calls runIntegration() when APPWRITE_RUN_INTEGRATION is defined, then prints helpers — output order matches Cpp20Test::$expectedOutput.
templates/cpp/tests/tests_main.cpp.twig Proper GTest entry point with InitGoogleTest and RUN_ALL_TESTS(); linked against GTest::gtest (no duplicate main).
tests/languages/cpp/Dockerfile Pre-builds and installs cpr, nlohmann/json, and googletest during Docker image build, avoiding the --network=mockapi constraint at test runtime.
tests/languages/cpp/test.sh Correctly passes -DAPPWRITE_BUILD_TESTS=ON -DAPPWRITE_RUN_INTEGRATION=ON, sets APPWRITE_RESOURCE_DIR and APPWRITE_MOCK_ENDPOINT, runs both test binaries.
tests/Cpp20Test.php Manually runs build commands, starts mock server via docker compose, and polls for readiness before running the test.
src/SDK/Language/Cpp.php All major template files registered in getFiles(); getPropertyType correctly wraps non-required sub_schema in std::optional; getDispatchBlock routes all method types to the correct client methods.
templates/cpp/CMakeLists.txt.twig Uses GTest::gtest (no bundled main); integration_logic.cpp properly linked to integration_test target; APPWRITE_RUN_INTEGRATION compile definition applied correctly.
.github/workflows/sdk-build-validation.yml C++ build step now correctly passes -DAPPWRITE_BUILD_TESTS=ON and runs ctest, exercising header compilation via the test executables.

Reviews (60): Last reviewed commit: "Clean up base.hpp.twig formatting" | Re-trigger Greptile

Comment thread templates/cpp/include/client.hpp.twig Outdated
Comment thread src/SDK/Language/Cpp.php
Comment thread templates/cpp/include/services/service.hpp.twig Outdated
Comment thread src/SDK/Language/Cpp.php Outdated
Comment thread templates/cpp/README.md.twig Outdated
Comment thread src/SDK/Language/Cpp.php
Comment thread templates/cpp/include/exception.hpp.twig Outdated
@bhardwajparth51 bhardwajparth51 force-pushed the feat/cpp-sdk-generator branch from 9f55656 to a07a162 Compare April 7, 2026 16:52
Comment thread templates/cpp/include/input_file.hpp.twig Outdated
Comment thread templates/cpp/include/models/model.hpp.twig Outdated
Comment thread templates/cpp/include/services/service.hpp.twig Outdated
Comment thread templates/cpp/include/input_file.hpp.twig Outdated
Comment thread templates/cpp/include/input_file.hpp.twig Outdated
Comment thread templates/cpp/include/services/service.hpp.twig Outdated
Comment thread templates/cpp/include/client.hpp.twig Outdated
Comment thread templates/cpp/include/client.hpp.twig Outdated
@bhardwajparth51
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Comment thread templates/cpp/include/client.hpp.twig Outdated
Comment thread templates/cpp/tests/tests.cpp.twig Outdated
Comment thread src/SDK/Language/Cpp.php Outdated
Comment thread templates/cpp/tests/tests.cpp.twig Outdated
Comment thread templates/cpp/tests/tests.cpp.twig Outdated
@bhardwajparth51 bhardwajparth51 marked this pull request as draft April 13, 2026 19:59
@bhardwajparth51 bhardwajparth51 marked this pull request as ready for review April 13, 2026 20:49
Comment thread tests/languages/cpp/test.sh Outdated
Comment thread src/SDK/Language/Cpp.php
Comment thread templates/cpp/include/services.hpp.twig Outdated
Comment thread templates/cpp/include/services.hpp.twig Outdated
Comment thread templates/cpp/include/models.hpp.twig
Comment thread templates/cpp/include/models.hpp.twig
Comment thread examples/cpp/include/appwrite/services.hpp Outdated
Comment thread templates/cpp/include/services.hpp.twig Outdated
Comment thread templates/cpp/include/base.hpp.twig Outdated
Comment thread templates/cpp/include/client.hpp.twig Outdated
Comment thread example.php Outdated
Comment thread templates/cpp/include/models.hpp.twig Outdated
Comment thread tests/Cpp20Test.php Outdated
Comment thread .github/workflows/sdk-build-validation.yml Outdated
Comment thread templates/cpp/README.md.twig Outdated
Comment thread templates/cpp/README.md.twig Outdated
Comment thread tests/languages/cpp/Dockerfile
Comment thread examples/cpp/tests/integration.cpp Outdated
Comment thread tests/languages/cpp/Dockerfile
Comment thread templates/cpp/tests/integration.cpp.twig Outdated
Comment thread examples/cpp/tests/integration.cpp Outdated
- Updated Dockerfile to pre-install dependencies and build cpr/json/gtest from source
- Updated test.sh with CMAKE_PREFIX_PATH to ensure air-gapped dependency discovery
- Added GTest find_package check to CMakeLists.txt.twig
- Synchronized SDK project name to 'cpp' in example.php
- Restored hardened client architecture (mutable config, error extraction, C++20 compliance)
- Regenerated examples/cpp output
Comment thread templates/cpp/include/base.hpp.twig Outdated
Comment thread templates/cpp/tests/integration_logic.cpp.twig
@bhardwajparth51 bhardwajparth51 force-pushed the feat/cpp-sdk-generator branch from bead5f0 to 80b900d Compare April 19, 2026 06:54
Comment thread templates/cpp/include/services.hpp.twig
- Guarded Realtime service with APPWRITE_ENABLE_REALTIME feature flag
- Implemented robust call-time static_assert stub for disabled Realtime
- Moved RealtimeResponse to services.hpp for better visibility
- Aligned setEndpoint exception type and integration test reporting
- Fixed integration test output flushing to prevent null-match errors
Comment thread examples/cpp/tests/integration_logic.cpp
Comment thread tests/Cpp20Test.php Outdated
Comment thread templates/cpp/CMakeLists.txt.twig Outdated
Comment thread templates/cpp/tests/integration_logic.cpp.twig Outdated
Comment thread tests/Cpp20Test.php
@bhardwajparth51 bhardwajparth51 force-pushed the feat/cpp-sdk-generator branch from 22ba2ca to a3b8729 Compare April 19, 2026 15:37
Comment thread examples/cpp/tests/integration_logic.cpp Outdated
Comment thread tests/Cpp20Test.php
Comment thread templates/cpp/include/core.hpp.twig
Comment thread templates/cpp/include/core.hpp.twig
Removed unnecessary blank lines and fixed namespace closing.
Comment on lines +14 to +20
// Deserialization must not throw (skip on type mismatch in example data)
appwrite::models::{{ definition.name | casePascal }} model;
try {
model = appwrite::models::{{ definition.name | casePascal }}::fromJson(seed);
} catch (const nlohmann::json::exception&) {
GTEST_SKIP() << "Seed example data type mismatch — skipped";
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 DeserializationException not caught — GTest failure instead of skip

The catch block only handles nlohmann::json::exception, but fromJson can also throw AppwriteException subclasses (e.g. DeserializationException("Required field '...' is null") for a required field that is present in the JSON but explicitly null). When that exception propagates out of the TEST() body, GTest catches it at the framework level and records a test failure rather than a skip — causing test_appwrite to exit non-zero and fail CI.

Add a second catch arm before the closing brace to cover std::exception (which AppwriteException inherits from):

Suggested change
// Deserialization must not throw (skip on type mismatch in example data)
appwrite::models::{{ definition.name | casePascal }} model;
try {
model = appwrite::models::{{ definition.name | casePascal }}::fromJson(seed);
} catch (const nlohmann::json::exception&) {
GTEST_SKIP() << "Seed example data type mismatch — skipped";
}
try {
model = appwrite::models::{{ definition.name | casePascal }}::fromJson(seed);
} catch (const nlohmann::json::exception&) {
GTEST_SKIP() << "Seed example data type mismatch — skipped";
} catch (const std::exception& e) {
GTEST_SKIP() << "Deserialization error — skipped: " << e.what();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant