-
Notifications
You must be signed in to change notification settings - Fork 12
feat: implement GraphQL interface to the middleware DB #2162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
radrow
wants to merge
29
commits into
master
Choose a base branch
from
radrow/graph-ql
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+5,692
−28
Draft
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
94c215e
GraphQL stub
radrow 236b341
More GraphQL resolvers and tests
radrow efda4b3
Fix stupid test dep
radrow f3f9ab8
Code formatting
ghallak 8eb69d8
Add stats queries
ghallak 33def4e
Refactor graphql schema
ghallak b5db8e3
Add more queries
ghallak f65b4a0
Update blocks resolvers and queries
ghallak f86d0d2
Run mix format
ghallak 83f5589
Micro blocks queries
ghallak fb9838f
Remove scope from micro blocks query
ghallak 9328cdb
Remove duplicated transactions query
ghallak 402dc90
Fix single transaction query
ghallak 2f1b49a
Fix pending txns queries
ghallak f8473c6
Remove block query from txns queries
ghallak 78ba564
Comment txns and txns count resolvers
ghallak 041aa34
Fix oracles types, comment extends
ghallak 365fb33
Remove duplicated funs
ghallak fae4161
Fix all oracle queries
ghallak 3705687
Enable oracle extensions
ghallak d837ec4
Fix all channel queries
ghallak a7d9e26
Disable aex9 queries
ghallak f54dec5
Enable aex9 contract queries
ghallak 670f2e0
Enable aex9 contract balances
ghallak e4bee66
Enable balance history query
ghallak 513de12
Comment unused aex141 queries and types
ghallak 7ef29eb
Complete the stats queries
ghallak 901c147
Remove duplicated stats types
ghallak 9042c40
Convert map keys from string to atom before return
ghallak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| # GraphQL Integration (Experimental) | ||
|
|
||
| Status: INITIAL SKELETON (alpha). Only a single field (`contract(id)`) is exposed so far. | ||
|
|
||
| This document explains how to use, test, and extend the new GraphQL endpoint. | ||
|
|
||
| --- | ||
| ## Endpoints | ||
|
|
||
| | Path | Method | Description | | ||
| |------|--------|-------------| | ||
| | `/graphql` | POST | Execute GraphQL operations (queries & mutations — only queries exist now). | | ||
| | `/graphiql` | GET | Interactive GraphiQL / Playground UI (available only in non-prod Mix envs). | | ||
|
|
||
| Both are mounted ahead of the REST versioned routes. CORS follows the existing `:api` pipeline configuration. | ||
|
|
||
| ### Example Query | ||
| ```graphql | ||
| { | ||
| contract(id: "ct_invalid") { id aexn_type meta_name meta_symbol } | ||
| } | ||
| ``` | ||
| Expected error response: | ||
| ```json | ||
| { | ||
| "errors": [ { "message": "invalid_contract_id" } ] | ||
| } | ||
| ``` | ||
|
|
||
| ### Current Fields | ||
| | Field | Args | Returns | Notes | | ||
| |-------|------|---------|-------| | ||
| | `contract` | `id: ID!` | `Contract` | Fetches contract metadata; only partially populated today. | | ||
|
|
||
| `Contract` type fields: | ||
| - `id: ID!` (echo of provided contract pubkey) | ||
| - `aexn_type: String` (e.g. `"aex9"`, `"aex141"`, or null) | ||
| - `meta_name: String` | ||
| - `meta_symbol: String` | ||
|
|
||
| > Decimals, version, holders, total supply, and on-chain state are not yet exposed. | ||
| --- | ||
| ## Resolver Behavior & Limitations | ||
| - The resolver decodes `ct_`-prefixed contract public keys using the node encoder. | ||
| - If the ID does not look like a contract pubkey, it returns an Absinthe error with message `invalid_contract_id`. | ||
| - It tries to derive AEXN token meta info (name & symbol) when the contract type is recognized. | ||
| - It currently expects a `:state` entry in the Absinthe context (to be provided by future context plug). If absent, it may fall back to returning `missing_state` errors when more logic is added. | ||
|
|
||
| Planned improvements: | ||
| 1. Add context bridge to inject the same chain state used by REST (so queries reflect latest sync snapshot). | ||
| 2. Add batching (Dataloader) if multiple contracts are queried in one request. | ||
| 3. Provide structured error extensions (e.g. `{ code, detail }`). | ||
|
|
||
| --- | ||
| ## Running Queries (Development) | ||
| 1. Start the application normally (REST server + GraphQL): | ||
| ```bash | ||
| mix phx.server | ||
| ``` | ||
| 2. Navigate to: `http://localhost:4000/graphiql` | ||
| 3. Run the sample query. | ||
|
|
||
| If you run into node / DB ownership errors while running tests or starting the node, set a consistent Erlang node name: | ||
| ```bash | ||
| elixir --name aeternity@localhost -S mix phx.server | ||
| ``` | ||
| Or for tests: | ||
| ```bash | ||
| elixir --name aeternity@localhost -S mix test | ||
| ``` | ||
|
|
||
| > Avoid using `--sname` with an `@host` suffix; use `--name` for long names or `--sname aeternity` for short names. | ||
| --- | ||
| ## Testing | ||
| A minimal ExUnit test exists at: | ||
| `test/ae_mdw_web/graphql/contract_query_test.exs` | ||
|
|
||
| It currently checks error handling for invalid IDs. The test spins up the full application tree which includes a heavy node startup phase. | ||
|
|
||
| ### Making Tests Faster (Planned) | ||
| A future refactor will: | ||
| - Introduce a config flag (e.g. `config :ae_mdw, :start_node_services, false` in test) to skip aecore-related apps in unit tests. | ||
| - Provide a mock or lightweight in-memory state for resolvers. | ||
|
|
||
| --- | ||
| ## Roadmap | ||
| | Phase | Goal | Notes | | ||
| |-------|------|------| | ||
| | 1 | Basic contract query (DONE) | Skeleton online. | | ||
| | 2 | Context bridge & graceful missing state handling | Use existing StatePlug output. | | ||
| | 3 | Add account & name queries | Mirror frequently used REST endpoints. | | ||
| | 4 | Pagination & connections | Cursor-based pattern for lists (contracts, transfers). | | ||
| | 5 | Complexity & depth limits | Mitigate resource exhaustion; e.g. `max_depth: 12`. | | ||
| | 6 | Token (AEX9 / AEX141) richer fields | Supply, holders, balances (with pagination). | | ||
| | 7 | Subscriptions (optional) | Uses existing PubSub for real-time events. | | ||
| | 8 | Telemetry + structured errors | Unified metrics and improved DX. | | ||
|
|
||
| --- | ||
| ## Design Principles | ||
| - Parity-first: GraphQL fields will align with existing REST semantics before introducing novel aggregations. | ||
| - Explicit pagination: No unbounded list fields. | ||
| - Streaming / large scans avoided; use indexed / cached paths exposed by the DB layer. | ||
| - Deterministic errors: Each validation failure maps to a stable error message code. | ||
|
|
||
| --- | ||
| ## Extending the Schema | ||
| 1. Add a new resolver module under `lib/ae_mdw_web/graphql/resolvers/`. | ||
| 2. Define object / field additions in `AeMdwWeb.GraphQL.Schema` (or split into type modules later with `import_types`). | ||
| 3. Ensure arguments are validated early; return domain errors via `{:error, code}`. | ||
| 4. Add tests that do NOT rely on the full chain when possible (inject or mock state). | ||
|
|
||
| Example (future) field stub: | ||
| ```elixir | ||
| field :account, :account do | ||
| arg :id, non_null(:id) | ||
| resolve &AccountResolver.account/3 | ||
| end | ||
| ``` | ||
|
|
||
| --- | ||
| ## Security Considerations | ||
| - Depth & complexity limits are not yet enforced (add them before exposing publicly). | ||
| - Rate limiting is inherited from existing stack (none specific to GraphQL yet). | ||
| - User input is limited to IDs now; later additions must validate pagination cursors and filters. | ||
|
|
||
| --- | ||
| ## Contributing | ||
| Open a PR adding new fields and include: | ||
| - Schema changes | ||
| - Resolver(s) | ||
| - Unit tests (success + failure) | ||
| - Brief addition to this doc (Roadmap or new section) | ||
|
|
||
| --- | ||
| ## FAQ | ||
| **Why Absinthe instead of generating GraphQL from REST automatically?** | ||
| Absinthe offers strong flexibility, custom middleware, and Elixir-native patterns for batching and instrumentation. | ||
|
|
||
| **Will REST be deprecated?** | ||
| Not in the short term. GraphQL is additive and will target aggregate and selective data retrieval patterns first. | ||
|
|
||
| **How do I enable GraphiQL in prod for debugging?** | ||
| You should not. If absolutely necessary, guard it behind an env flag and temporary branch only. | ||
|
|
||
| --- | ||
| ## Support / Contact | ||
| File an issue in the repository with the `graphql` label for feature requests or bugs. | ||
|
Comment on lines
+122
to
+149
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove |
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be removed