From ba913cb8cae95875b33c2fe5a14eac97fea6dd9f Mon Sep 17 00:00:00 2001 From: Vigneshwer Vaidyanathan Date: Wed, 12 Aug 2026 13:26:50 -0400 Subject: [PATCH] Align the batch docs and changelog with the Node and Python SDKs The batch section led with a hand-written nested hash and pushed typed payloads into a second section, so the first thing a reader copied was the form we tell them not to use. The Node and Python READMEs both lead with the typed payload, link the batch guide, and close with one line naming the payloads. This matches that shape, and drops the surrounding prose -- atomicity and union handling, unset vs nil, value equality -- that neither sibling documents. 95 lines to 34; theirs are 29. Adds the guide links the sibling READMEs carry and this one was missing: post-to-the-api, batch-ledger-entries, sync-payments#custom-link, reconcile-payments#reconcile-a-tx and read-balances#latest. Every link and anchor was checked against the live docs. The changelog gains the Keep a Changelog preamble both siblings use, and the two batch entries pick up their shared wording. The 2.0.0 section already matched. --- CHANGELOG.md | 20 +++++-- README.md | 97 +++++++-------------------------- test/add_ledger_entries_test.rb | 3 +- 3 files changed, 36 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6096153..8374f3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,26 @@ # Changelog +All notable changes to `fragment-dev` will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/). + +Releases prior to `2.0.0` were published before this changelog was added and +are not documented here. + ## [2.1.0] ### Added -- `add_ledger_entries` commits a batch of Ledger Entries atomically. It accepts +- `add_ledger_entries` posts a batch of Ledger Entries atomically. It accepts raw `AddLedgerEntryInput` hashes, typed payloads, or both in one batch, and preserves their order. -- Typed batch payloads. `FragmentClient::TypedEntries.load` derives one payload - class per `(Ledger Entry type, typeVersion)` from the per-entry-type - `addLedgerEntry` operations the Fragment CLI generates for your Schema, so a - batch can be built with real parameter names instead of untyped hashes: +- Strongly-typed batch payloads. `FragmentClient::TypedEntries.load` derives one + payload class per `(Ledger Entry type, typeVersion)` from the per-entry-type + `addLedgerEntry` operations the Fragment CLI generates for your Schema. Because a + batch mutation takes one list of one input type, GraphQL cannot type each entry's + `parameters` field individually; these payloads do. Payload names always carry the + entry type version, defaulting to `V1`: ```ruby fragment.add_ledger_entries(entries: [ diff --git a/README.md b/README.md index 809e320..28c4009 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ [Fragment](https://fragment.dev) is the Ledger API for engineers that move money. Stop wrangling payment tables, debugging balance errors and hacking together data pipelines. Start shipping the features that make a difference. +See [CHANGELOG.md](CHANGELOG.md) for release notes and upgrade guidance. + ## Installation To install the Fragment SDK for Ruby, you'll need to install the gem. Run the following command in your terminal: @@ -34,7 +36,7 @@ fragment = FragmentClient.new( ### Post a Ledger Entry -To post a Ledger Entry defined in your schema: +To [post](https://fragment.dev/guides/post-ledger-entries#post-to-the-api) a Ledger Entry defined in your Schema: ```ruby fragment.add_ledger_entry({ @@ -51,95 +53,36 @@ fragment.add_ledger_entry({ ### Post a batch of Ledger Entries -`add_ledger_entries` commits a batch atomically — either every entry commits or -none do. Idempotency keys are per entry, so a retried batch reports `isIkReplay` -for each one. - -```ruby -result = fragment.add_ledger_entries(entries: [ - { - ik: "some-ik", - entry: { - ledger: { ik: "your-ledger-ik" }, - type: "user_funds_account", - posted: "1968-01-01T16:45:00Z", - parameters: { user_id: "user-1", funding_amount: "200" } - } - } -]) - -case result.data.add_ledger_entries.__typename -when "AddLedgerEntriesResult" - result.data.add_ledger_entries.results.each { |r| puts [r.entry.ik, r.is_ik_replay].inspect } -when "AddLedgerEntriesError" - # One element per failing entry, each carrying the ik that identifies it. - result.data.add_ledger_entries.errors.each { |e| warn "#{e.ik}: #{e.message}" } -end -``` - -Writing those nested hashes by hand is easy to get wrong, and nothing checks the -parameter names against your Schema. The next section is about not doing that. - -### Typed batch payloads - -The Fragment CLI generates a per-entry-type `addLedgerEntry` operation for each -Ledger Entry in your Schema. Those operations know two things GraphQL cannot -express for a batch: the entry type, and the type of every parameter. The SDK -derives a payload class per Ledger Entry from them. - -Pass the `.graphql` file as an extra queries file and the payloads are registered -for you: +To [post](https://fragment.dev/guides/post-ledger-entries#batch-ledger-entries) a +batch of Ledger Entries atomically: ```ruby -fragment = FragmentClient.new( - 'your-client-id', - 'your-client-secret', - extra_queries_filenames: ['app/graphql/entries.graphql'] -) - fragment.add_ledger_entries(entries: [ FragmentClient::Entries::UserFundsAccountV1.new( - ik: "some-ik", + ik: "some-ik-1", ledger_ik: "your-ledger-ik", posted: "1968-01-01T16:45:00Z", user_id: "user-1", - funding_amount: "200" + funding_amount: "20000" + ), + FragmentClient::Entries::UserFundsAccountV1.new( + ik: "some-ik-2", + ledger_ik: "your-ledger-ik", + posted: "1968-01-01T16:45:00Z", + user_id: "user-2", + funding_amount: "20000" ) ]) ``` -A payload is named for its Ledger Entry type and the version it posts, so adding -`user_funds_account` v2 later leaves every existing `...V1` call site alone. A -misspelled or missing parameter raises immediately rather than reaching the API, -and typed payloads can be mixed with the raw hashes above in a single batch. - -Nothing you did not set is sent. An omitted field is absent from the request; an -explicit `nil` is sent as `null`, because those mean different things to the API. - -Readers behave the way you would expect either way — an unset field reads as `nil`, -so `entry.posted&.iso8601` and `if entry.description` do the obvious thing. When -you need to tell "never set" from "set to `nil`", ask: - -```ruby -entry = FragmentClient::Entries::UserFundsAccountV1.new( - ik: "some-ik", ledger_ik: "your-ledger-ik", user_id: "user-1", funding_amount: "200" -) -entry.posted #=> nil -entry.set?(:posted) #=> false - -entry.to_entry_input # the exact hash that goes on the wire, if you want to inspect it -``` - -Payloads compare by value, so they are straightforward to assert on in your own -tests. +Construct the entries in the batch using the typed payloads generated for your +Schema, named `V` under `FragmentClient::Entries`. -You can register payloads without constructing a client — no credentials, no +Payloads can also be registered without constructing a client — no credentials, no network: ```ruby FragmentClient::TypedEntries.load('app/graphql/entries.graphql') -FragmentClient::TypedEntries.fetch('user_funds_account', 1) -#=> FragmentClient::Entries::UserFundsAccountV1 ``` ### Sorbet @@ -159,7 +102,7 @@ does not declare. ### Sync Transactions -To sync transaction using a custom link: +To sync transaction using a [Custom Link](https://fragment.dev/guides/sync-payments#custom-link): ```ruby fragment.sync_custom_accounts({ @@ -197,7 +140,7 @@ fragment.sync_custom_txs({ ### Reconcile a Transaction -To reconcile a transaction: +To [reconcile](https://fragment.dev/guides/reconcile-payments#reconcile-a-tx) a transaction: ```ruby fragment.reconcile_tx({ @@ -250,7 +193,7 @@ ledger_entry_details = ledger_entry_response.data.ledger_entry ### Get a Ledger Account with Balance -To get the balance details of a specific ledger account: +To read a Ledger Account's [balance](https://fragment.dev/guides/read-balances#latest): ```ruby ledger_account_balance_response = fragment.get_ledger_account_balance({ diff --git a/test/add_ledger_entries_test.rb b/test/add_ledger_entries_test.rb index 4622b7e..449a8f2 100644 --- a/test/add_ledger_entries_test.rb +++ b/test/add_ledger_entries_test.rb @@ -79,8 +79,7 @@ def test_a_payload_converts_to_a_hash_under_either_name def test_raw_entries_work_without_loading_any_typed_payloads # The batch method is not conditional on the typed-payload machinery: a client - # constructed with no extra queries still posts a batch of plain hashes, which - # is the first example in the README. + # constructed with no extra queries still posts a batch of plain hashes. entry = { ik: 'raw-1', entry: { ledger: { ik: 'prod' }, type: 'user_funds_account', parameters: { user_id: 'user-1' } } }