From 9bbbe1fdbc50ebfd337fea3994f59e66a3a24d8e Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Thu, 5 Sep 2024 04:40:51 +0900 Subject: [PATCH 01/16] Overall reshaping of the GraphQL documentation renamed: docs/sdk/resources/graphql-server/_category_.json -> docs/sdk/reference/graphql-server/_category_.json new file: docs/sdk/reference/graphql-server/configuration/_category_.json renamed: docs/sdk/resources/graphql-server/authorization.md -> docs/sdk/reference/graphql-server/configuration/authorization.md renamed: docs/sdk/resources/graphql-server/caching.md -> docs/sdk/reference/graphql-server/configuration/caching.md renamed: docs/sdk/resources/graphql-server/custom-resolvers.md -> docs/sdk/reference/graphql-server/configuration/custom-resolvers.md renamed: docs/sdk/resources/graphql-server/dos-protection.md -> docs/sdk/reference/graphql-server/configuration/dos-protection.md renamed: docs/sdk/resources/graphql-server/subscriptions.md -> docs/sdk/reference/graphql-server/configuration/subscriptions.md new file: docs/sdk/reference/graphql-server/openreader/_category_.json renamed: docs/sdk/reference/openreader/and-or-filters.md -> docs/sdk/reference/graphql-server/openreader/and-or-filters.md renamed: docs/sdk/reference/openreader/cross-relation-field-queries.md -> docs/sdk/reference/graphql-server/openreader/cross-relation-field-queries.md renamed: docs/sdk/reference/openreader/intro.md -> docs/sdk/reference/graphql-server/openreader/intro.md renamed: docs/sdk/reference/openreader/json-queries.md -> docs/sdk/reference/graphql-server/openreader/json-queries.md renamed: docs/sdk/reference/openreader/nested-field-queries.md -> docs/sdk/reference/graphql-server/openreader/nested-field-queries.md renamed: docs/sdk/reference/openreader/paginate-query-results.md -> docs/sdk/reference/graphql-server/openreader/paginate-query-results.md renamed: docs/sdk/reference/openreader/queries.md -> docs/sdk/reference/graphql-server/openreader/queries.md renamed: docs/sdk/reference/openreader/resolve-union-types-interfaces.md -> docs/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces.md renamed: docs/sdk/reference/openreader/sorting.md -> docs/sdk/reference/graphql-server/openreader/sorting.md renamed: docs/sdk/resources/graphql-server/overview.md -> docs/sdk/reference/graphql-server/overview.md deleted: docs/sdk/reference/openreader/_category_.json renamed: docs/sdk/resources/graphql-server/database-creds.png -> docs/sdk/resources/basics/serving-graphql-database-creds.png renamed: docs/sdk/resources/graphql-server/alternatives.md -> docs/sdk/resources/basics/serving-graphql.md --- .../graphql-server/_category_.json | 6 +++--- .../graphql-server/configuration/_category_.json | 12 ++++++++++++ .../graphql-server/configuration}/authorization.md | 0 .../graphql-server/configuration}/caching.md | 0 .../configuration}/custom-resolvers.md | 0 .../graphql-server/configuration}/dos-protection.md | 0 .../graphql-server/configuration}/subscriptions.md | 0 .../graphql-server/openreader/_category_.json | 12 ++++++++++++ .../openreader/and-or-filters.md | 0 .../openreader/cross-relation-field-queries.md | 0 .../{ => graphql-server}/openreader/intro.md | 0 .../{ => graphql-server}/openreader/json-queries.md | 0 .../openreader/nested-field-queries.md | 0 .../openreader/paginate-query-results.md | 0 .../{ => graphql-server}/openreader/queries.md | 0 .../openreader/resolve-union-types-interfaces.md | 0 .../{ => graphql-server}/openreader/sorting.md | 0 .../graphql-server/overview.md | 0 docs/sdk/reference/openreader/_category_.json | 12 ------------ .../serving-graphql-database-creds.png} | Bin .../alternatives.md => basics/serving-graphql.md} | 10 +++++----- 21 files changed, 32 insertions(+), 20 deletions(-) rename docs/sdk/{resources => reference}/graphql-server/_category_.json (56%) create mode 100644 docs/sdk/reference/graphql-server/configuration/_category_.json rename docs/sdk/{resources/graphql-server => reference/graphql-server/configuration}/authorization.md (100%) rename docs/sdk/{resources/graphql-server => reference/graphql-server/configuration}/caching.md (100%) rename docs/sdk/{resources/graphql-server => reference/graphql-server/configuration}/custom-resolvers.md (100%) rename docs/sdk/{resources/graphql-server => reference/graphql-server/configuration}/dos-protection.md (100%) rename docs/sdk/{resources/graphql-server => reference/graphql-server/configuration}/subscriptions.md (100%) create mode 100644 docs/sdk/reference/graphql-server/openreader/_category_.json rename docs/sdk/reference/{ => graphql-server}/openreader/and-or-filters.md (100%) rename docs/sdk/reference/{ => graphql-server}/openreader/cross-relation-field-queries.md (100%) rename docs/sdk/reference/{ => graphql-server}/openreader/intro.md (100%) rename docs/sdk/reference/{ => graphql-server}/openreader/json-queries.md (100%) rename docs/sdk/reference/{ => graphql-server}/openreader/nested-field-queries.md (100%) rename docs/sdk/reference/{ => graphql-server}/openreader/paginate-query-results.md (100%) rename docs/sdk/reference/{ => graphql-server}/openreader/queries.md (100%) rename docs/sdk/reference/{ => graphql-server}/openreader/resolve-union-types-interfaces.md (100%) rename docs/sdk/reference/{ => graphql-server}/openreader/sorting.md (100%) rename docs/sdk/{resources => reference}/graphql-server/overview.md (100%) delete mode 100644 docs/sdk/reference/openreader/_category_.json rename docs/sdk/resources/{graphql-server/database-creds.png => basics/serving-graphql-database-creds.png} (100%) rename docs/sdk/resources/{graphql-server/alternatives.md => basics/serving-graphql.md} (89%) diff --git a/docs/sdk/resources/graphql-server/_category_.json b/docs/sdk/reference/graphql-server/_category_.json similarity index 56% rename from docs/sdk/resources/graphql-server/_category_.json rename to docs/sdk/reference/graphql-server/_category_.json index 282d8113..7b140c91 100644 --- a/docs/sdk/resources/graphql-server/_category_.json +++ b/docs/sdk/reference/graphql-server/_category_.json @@ -1,12 +1,12 @@ { - "position": 11, + "position": 80, "label": "GraphQL server", "collapsible": true, "collapsed": true, "className": "red", "link": { "type": "generated-index", - "slug": "/sdk/resources/graphql-server", - "title": "GraphQL API server for squid data" + "slug": "/sdk/reference/graphql-server", + "title": "The SQD GraphQL server, built in-house" } } diff --git a/docs/sdk/reference/graphql-server/configuration/_category_.json b/docs/sdk/reference/graphql-server/configuration/_category_.json new file mode 100644 index 00000000..ea4bd71a --- /dev/null +++ b/docs/sdk/reference/graphql-server/configuration/_category_.json @@ -0,0 +1,12 @@ +{ + "position": 20, + "label": "Configuration", + "collapsible": true, + "collapsed": true, + "className": "red", + "link": { + "type": "generated-index", + "slug": "/sdk/reference/graphql-server/configuration", + "title": "Configuring and extending the server" + } +} diff --git a/docs/sdk/resources/graphql-server/authorization.md b/docs/sdk/reference/graphql-server/configuration/authorization.md similarity index 100% rename from docs/sdk/resources/graphql-server/authorization.md rename to docs/sdk/reference/graphql-server/configuration/authorization.md diff --git a/docs/sdk/resources/graphql-server/caching.md b/docs/sdk/reference/graphql-server/configuration/caching.md similarity index 100% rename from docs/sdk/resources/graphql-server/caching.md rename to docs/sdk/reference/graphql-server/configuration/caching.md diff --git a/docs/sdk/resources/graphql-server/custom-resolvers.md b/docs/sdk/reference/graphql-server/configuration/custom-resolvers.md similarity index 100% rename from docs/sdk/resources/graphql-server/custom-resolvers.md rename to docs/sdk/reference/graphql-server/configuration/custom-resolvers.md diff --git a/docs/sdk/resources/graphql-server/dos-protection.md b/docs/sdk/reference/graphql-server/configuration/dos-protection.md similarity index 100% rename from docs/sdk/resources/graphql-server/dos-protection.md rename to docs/sdk/reference/graphql-server/configuration/dos-protection.md diff --git a/docs/sdk/resources/graphql-server/subscriptions.md b/docs/sdk/reference/graphql-server/configuration/subscriptions.md similarity index 100% rename from docs/sdk/resources/graphql-server/subscriptions.md rename to docs/sdk/reference/graphql-server/configuration/subscriptions.md diff --git a/docs/sdk/reference/graphql-server/openreader/_category_.json b/docs/sdk/reference/graphql-server/openreader/_category_.json new file mode 100644 index 00000000..e4fed209 --- /dev/null +++ b/docs/sdk/reference/graphql-server/openreader/_category_.json @@ -0,0 +1,12 @@ +{ + "position": 30, + "label": "Core API", + "collapsible": true, + "collapsed": true, + "className": "red", + "link": { + "type": "generated-index", + "slug": "/sdk/reference/graphql-server/openreader", + "title": "Core queries exposed by the SQD GraphQL server API" + } +} diff --git a/docs/sdk/reference/openreader/and-or-filters.md b/docs/sdk/reference/graphql-server/openreader/and-or-filters.md similarity index 100% rename from docs/sdk/reference/openreader/and-or-filters.md rename to docs/sdk/reference/graphql-server/openreader/and-or-filters.md diff --git a/docs/sdk/reference/openreader/cross-relation-field-queries.md b/docs/sdk/reference/graphql-server/openreader/cross-relation-field-queries.md similarity index 100% rename from docs/sdk/reference/openreader/cross-relation-field-queries.md rename to docs/sdk/reference/graphql-server/openreader/cross-relation-field-queries.md diff --git a/docs/sdk/reference/openreader/intro.md b/docs/sdk/reference/graphql-server/openreader/intro.md similarity index 100% rename from docs/sdk/reference/openreader/intro.md rename to docs/sdk/reference/graphql-server/openreader/intro.md diff --git a/docs/sdk/reference/openreader/json-queries.md b/docs/sdk/reference/graphql-server/openreader/json-queries.md similarity index 100% rename from docs/sdk/reference/openreader/json-queries.md rename to docs/sdk/reference/graphql-server/openreader/json-queries.md diff --git a/docs/sdk/reference/openreader/nested-field-queries.md b/docs/sdk/reference/graphql-server/openreader/nested-field-queries.md similarity index 100% rename from docs/sdk/reference/openreader/nested-field-queries.md rename to docs/sdk/reference/graphql-server/openreader/nested-field-queries.md diff --git a/docs/sdk/reference/openreader/paginate-query-results.md b/docs/sdk/reference/graphql-server/openreader/paginate-query-results.md similarity index 100% rename from docs/sdk/reference/openreader/paginate-query-results.md rename to docs/sdk/reference/graphql-server/openreader/paginate-query-results.md diff --git a/docs/sdk/reference/openreader/queries.md b/docs/sdk/reference/graphql-server/openreader/queries.md similarity index 100% rename from docs/sdk/reference/openreader/queries.md rename to docs/sdk/reference/graphql-server/openreader/queries.md diff --git a/docs/sdk/reference/openreader/resolve-union-types-interfaces.md b/docs/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces.md similarity index 100% rename from docs/sdk/reference/openreader/resolve-union-types-interfaces.md rename to docs/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces.md diff --git a/docs/sdk/reference/openreader/sorting.md b/docs/sdk/reference/graphql-server/openreader/sorting.md similarity index 100% rename from docs/sdk/reference/openreader/sorting.md rename to docs/sdk/reference/graphql-server/openreader/sorting.md diff --git a/docs/sdk/resources/graphql-server/overview.md b/docs/sdk/reference/graphql-server/overview.md similarity index 100% rename from docs/sdk/resources/graphql-server/overview.md rename to docs/sdk/reference/graphql-server/overview.md diff --git a/docs/sdk/reference/openreader/_category_.json b/docs/sdk/reference/openreader/_category_.json deleted file mode 100644 index 45d1c4d1..00000000 --- a/docs/sdk/reference/openreader/_category_.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "position": 80, - "label": "Core GraphQL API", - "collapsible": true, - "collapsed": true, - "className": "red", - "link": { - "type": "generated-index", - "slug": "/sdk/reference/openreader", - "title": "Core queries exposed by the squid GraphQL API" - } -} diff --git a/docs/sdk/resources/graphql-server/database-creds.png b/docs/sdk/resources/basics/serving-graphql-database-creds.png similarity index 100% rename from docs/sdk/resources/graphql-server/database-creds.png rename to docs/sdk/resources/basics/serving-graphql-database-creds.png diff --git a/docs/sdk/resources/graphql-server/alternatives.md b/docs/sdk/resources/basics/serving-graphql.md similarity index 89% rename from docs/sdk/resources/graphql-server/alternatives.md rename to docs/sdk/resources/basics/serving-graphql.md index 1e07b476..30ccc9d7 100644 --- a/docs/sdk/resources/graphql-server/alternatives.md +++ b/docs/sdk/resources/basics/serving-graphql.md @@ -1,10 +1,10 @@ --- -sidebar_position: 90 -title: Alternatives -description: Using Squid SDK with PostGraphile or Hasura +sidebar_position: 80 +title: Serving GraphQL +description: Options available for serving GraphQL APIs --- -# Alternatives to the SDK GraphQL server +# Options available for serving GraphQL APIs We encourage using squids with third-party GraphQL tools like [PostGraphile](https://www.graphile.org/postgraphile/) and [Hasura](https://hasura.io). No special configuration is required and there aren't any constraints on running them in [Subsquid Cloud](/cloud). @@ -22,4 +22,4 @@ If you want to run Hasura in [Subsquid Cloud](/cloud), visit the [`hasura` addon When running it elsewhere, simply supply database credentials in your Hasura configuration. For squids running in Subsquid Cloud you can find the credentials in [the Cloud app](https://app.subsquid.io/squids). -![database creds](database-creds.png) +![database creds](serving-graphql-database-creds.png) From 729fbc3b73721a23db0d74a80a22da34486d4225 Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Thu, 5 Sep 2024 08:05:09 +0900 Subject: [PATCH 02/16] Coarse-grained content changes Extending the /sdk/resources/basics/serving-graphql, rewriting the old GraphQL server pages appropriately. modified: docs/sdk/reference/graphql-server/configuration/subscriptions.md modified: docs/sdk/reference/graphql-server/overview.md modified: docs/sdk/resources/basics/serving-graphql.md --- .../configuration/subscriptions.md | 6 +++- docs/sdk/reference/graphql-server/overview.md | 26 ++++++++------ docs/sdk/resources/basics/serving-graphql.md | 35 ++++++++++++++----- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/docs/sdk/reference/graphql-server/configuration/subscriptions.md b/docs/sdk/reference/graphql-server/configuration/subscriptions.md index e38a40fb..15e2c5b2 100644 --- a/docs/sdk/reference/graphql-server/configuration/subscriptions.md +++ b/docs/sdk/reference/graphql-server/configuration/subscriptions.md @@ -4,7 +4,11 @@ title: Subscriptions description: Subscribe to updates over a websocket --- -# Query subscriptions +# Subscriptions + +:::danger +Implementation of subscriptions by the SQD GraphQL server [leaks memory under load](/sdk/reference/graphql-server/overview/#known-issues). Do not use it in scenarios where more than a few users simultaneously maintain connections to the server. This includes most production usage scenarios. +::: OpenReader supports [GraphQL subscriptions](https://www.apollographql.com/docs/react/data/subscriptions/) via live queries. To use these, a client opens a websocket connection to the server and sends a `subscription` query there. The query body is then repeatedly executed (every 5 seconds by default) and the results are sent to the client whenever they change. diff --git a/docs/sdk/reference/graphql-server/overview.md b/docs/sdk/reference/graphql-server/overview.md index 596f8d1e..f623bb83 100644 --- a/docs/sdk/reference/graphql-server/overview.md +++ b/docs/sdk/reference/graphql-server/overview.md @@ -1,27 +1,27 @@ --- sidebar_position: 10 -description: Zero-config GraphQL server +description: The SQD GraphQL server, built in-house --- # Overview -The data indexed by a squid into a Postgres database can be automatically presented with a GraphQL API service powered by the [OpenReader](https://github.com/subsquid/squid-sdk/tree/master/graphql/openreader) lib of the Squid SDK. The OpenReader GraphQL server takes [the schema file](/sdk/reference/schema-file) as an input and serves a GraphQL API supporting [OpenCRUD](https://www.opencrud.org/) queries for the entities defined in the schema. +:::info +SQD GraphQL server is no longer recommended for use in new squid projects [relying on PostgreSQL](/sdk/resources/persisting-data/typeorm). See [Serving GraphQL](/resources/basics/serving-graphql) to learn about the new options and the [Known issues](#known-issues) section to understand our motivation. +::: -To start the API server based on the `schema.graphql` run in the squid project root: -```bash -npx squid-graphql-server -``` -or, for more options, +The data indexed by a squid into a Postgres database can be automatically presented with a GraphQL API service powered by the [OpenReader](https://github.com/subsquid/squid-sdk/tree/master/graphql/openreader) lib of the Squid SDK. The OpenReader GraphQL server takes [schema file](/sdk/reference/schema-file) as an input and serves a GraphQL API supporting [OpenCRUD](https://www.opencrud.org/) queries for the entities defined in the schema. + +To start the API server based on `schema.graphql` install `@subsquid/graphql-server` and run the following in the squid project root: ```bash npx squid-graphql-server ``` -The `squid-graphql-server` binary supports multiple optional flags to enable caching, subscriptions, DoS protection etc. Its features are covered in the next sections. +The `squid-graphql-server` executable supports multiple optional flags to enable [caching](/sdk/reference/graphql-server/configuration/caching), [subscriptions](/sdk/reference/graphql-server/configuration/subscriptions), [DoS protection](/sdk/reference/graphql-server/configuration/dos-protection) etc. Its features are covered in the next sections. -The API server listens at port defined by `GQL_PORT` (defaults to `4350`). The database connection is configured with the env variables `DB_NAME`, `DB_USER`, `DB_PASS`, `DB_HOST`, `DB_PORT`. +The API server listens at port defined by the `GQL_PORT` environment variable (defaults to `4350`). The database connection is configured with the env variables `DB_NAME`, `DB_USER`, `DB_PASS`, `DB_HOST`, `DB_PORT`. The GraphQL API is enabled by the `api:` service in the `deploy` section of [squid.yaml](/cloud/reference/manifest) for Subsquid Cloud deployments. -## Supported Queries +## Supported queries The details of the supported OpenReader queries can be found in a separate section [Query a Squid](/sdk/reference/openreader). Here is a brief overview of the queries generated by OpenReader for each entity defined in the schema file: @@ -41,3 +41,9 @@ The OpenReader GraphQL API defines the following custom scalar types: - `DateTime` entity field values are presented in the ISO format - `Bytes` entity field values are presented as hex-encoded strings prefixed with `0x` - `BigInt` entity field values are presented as strings + +## Known issues + +- [Subscriptions](/sdk/reference/graphql-server/configuration/subscriptions) leak memory under load and are thus unsuitable for use in production. +- Setting up custom resolvers for subscriptions is unreasonably hard. +- `@subsquid/graphql-server` depends on the deprecated Apollo Server v3. diff --git a/docs/sdk/resources/basics/serving-graphql.md b/docs/sdk/resources/basics/serving-graphql.md index 30ccc9d7..42a28526 100644 --- a/docs/sdk/resources/basics/serving-graphql.md +++ b/docs/sdk/resources/basics/serving-graphql.md @@ -1,25 +1,42 @@ --- sidebar_position: 80 title: Serving GraphQL -description: Options available for serving GraphQL APIs +description: GraphQL servers commonly used in squids --- -# Options available for serving GraphQL APIs +# Serving GraphQL -We encourage using squids with third-party GraphQL tools like [PostGraphile](https://www.graphile.org/postgraphile/) and [Hasura](https://hasura.io). No special configuration is required and there aren't any constraints on running them in [Subsquid Cloud](/cloud). +It is common (although not required) for squids to serve GraphQL APIs. Historically, the most common way to do that was to [persist the squid data to PostgreSQL](/sdk/resources/persisting-data/typeorm), then attach the [SQD GraphQL server](#the-sqd-graphql-server) to it. Although this is still supported, we encourage using [PostGraphile](#postgraphile) or [Hasura](#hasura) in new PostgreSQD-based projects. See [SQD GraphQL server known issues](/sdk/reference/graphql-server/overview/#known-issues) if you're curious about our motivation. ## PostGraphile -Here we cover one possible way of integrating PostGraphile into a squid project ([full example](https://github.com/subsquid-labs/squid-postgraphile-example/)). Note the following: +[PostGraphile](https://www.graphile.org/postgraphile/) is an open-source tool that builds powerful, extensible and performant GraphQL APIs from PostgreSQL schemas. -* There is a dedicated entry point for PostGraphile (`src/api.ts`). It is complemented by an [`sqd` command](https://github.com/subsquid-labs/squid-postgraphile-example/blob/f1fd1691eb59da2c9d57c475a71d0ed44cfed891/commands.json#L58) and a [manifest entry](https://github.com/subsquid-labs/squid-postgraphile-example/blob/f1fd1691eb59da2c9d57c475a71d0ed44cfed891/squid.yaml#L15). This makes it easier to run the squid both locally (with [`sqd run`](/squid-cli/run)) and in [Cloud](/cloud). +The recommended way of integrating PostGraphile into squid projects is by making a dedicated entry point at `src/api.ts`. A complete example squid implementing this approach is available in [this repository](https://github.com/subsquid-labs/squid-postgraphile-example/). -* As per usual with PostGraphile installations, you can freely extend it with plugins, including your own. Here is an [example plugin for serving the `_squidStatus` queries](https://github.com/subsquid-labs/squid-postgraphile-example/blob/f1fd1691eb59da2c9d57c475a71d0ed44cfed891/src/api.ts#L11) from the standard Squid SDK GraphQL server schema. +With this entry point in place, we [create a `sqd` command](https://github.com/subsquid-labs/squid-postgraphile-example/blob/f1fd1691eb59da2c9d57c475a71d0ed44cfed891/commands.json#L58) for running PostGraphile with [`commands.json`](/squid-cli/commands-json), then use it in the [`deploy.api` entry](https://github.com/subsquid-labs/squid-postgraphile-example/blob/f1fd1691eb59da2c9d57c475a71d0ed44cfed891/squid.yaml#L15) of [Squid manifest](/cloud/reference/manifest). Although none of this is required, this makes it easier to run the squid both locally (with [`sqd run`](/squid-cli/run)) and in the [Cloud](/cloud). + +As per usual with PostGraphile installations, you can freely extend it with plugins, including your own. Here is an [example plugin for serving the `_squidStatus` queries](https://github.com/subsquid-labs/squid-postgraphile-example/blob/f1fd1691eb59da2c9d57c475a71d0ed44cfed891/src/api.ts#L11) from the standard Squid SDK GraphQL server schema. A plugin for making PostGraphile API fully compatible with old APIs served by the SQD GraphQL server will be made available soon. ## Hasura -If you want to run Hasura in [Subsquid Cloud](/cloud), visit the [`hasura` addon page](/cloud/reference/hasura). +[Hasura](https://hasura.io) is a powerful open-source GraphQL engine geared towards exposing multiple data sources via a single GraphQL API. You can integrate it with your squid in two ways: +1. **Use Hasura to gather data from multiple sources, including your squid.** + + For this scenario we recommend separating your Hasura instance from your squid, which should consist of just one service, [the processor](/sdk/reference/processors/architecture), plus the database. Supply your database credentials to Hasura, then configure it to produce the desired API. + + If you run your squid in our [Cloud](/cloud) you can find database credentials in [the app](https://app.subsquid.io/squids): + + ![database creds](serving-graphql-database-creds.png) + +2. **Run a dedicated Hasura instance for serving the data just from your squid.** + + A complete example implementing this approach is available in [this repository](https://github.com/subsquid-labs/squid-hasura-example). More TBA. + + + +## The SQD GraphQL server -When running it elsewhere, simply supply database credentials in your Hasura configuration. For squids running in Subsquid Cloud you can find the credentials in [the Cloud app](https://app.subsquid.io/squids). +The [SQD GraphQL server](/sdk/reference/graphql-server) is a GraphQL server developed by the SQD team. Although still supported, it's not recommeded for new PostgreSQL-powered projects due to its [known issues](/sdk/reference/graphql-server/overview/#known-issues), especially for APIs implementing GraphQL subscriptions. -![database creds](serving-graphql-database-creds.png) +The server uses the [schema file](/sdk/reference/schema-file) to produce its [core API](/sdk/reference/graphql-server/openreader) that can be extended with [custom resolvers](/sdk/reference/graphql-server/configuration/custom-resolvers). Extra features include [DoS protection](/sdk/reference/graphql-server/configuration/dos-protection). From 30372f6d464ea96ac52e861bc8188be7dfbeb8b0 Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Thu, 5 Sep 2024 23:56:49 +0900 Subject: [PATCH 03/16] Updating the EVM networks list modified: docs/subsquid-network/reference/evm-networks.mdx --- docs/subsquid-network/reference/evm-networks.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/subsquid-network/reference/evm-networks.mdx b/docs/subsquid-network/reference/evm-networks.mdx index cf9106da..6212c16c 100644 --- a/docs/subsquid-network/reference/evm-networks.mdx +++ b/docs/subsquid-network/reference/evm-networks.mdx @@ -129,6 +129,7 @@ const processor = new EvmBatchProcessor() | Shiden (*) | 336 | | | https://v2.archive.subsquid.io/network/shiden-mainnet | | Skale Nebula | 1482601649 | | | https://v2.archive.subsquid.io/network/skale-nebula | | StratoVM Sepolia | 93747 | ✓ | ✓ | https://v2.archive.subsquid.io/network/stratovm-sepolia | +| Superseed Sepolia | 53302 | | | https://v2.archive.subsquid.io/network/superseed-sepolia | | Taiko Mainnet | 167000 | | | https://v2.archive.subsquid.io/network/taiko-mainnet | | Tanssi | 5678 | | | https://v2.archive.subsquid.io/network/tanssi | | X1 Testnet | 195 | | | https://v2.archive.subsquid.io/network/x1-testnet | From e99993d109a9b31a8b7d320769b7800f7d4238d2 Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Fri, 6 Sep 2024 04:02:59 +0900 Subject: [PATCH 04/16] Updating the references modified: docs/cloud/resources/best-practices.md modified: docs/glossary.md modified: docs/overview.mdx modified: docs/sdk/faq.md modified: docs/sdk/how-to-start/layout.md modified: docs/sdk/how-to-start/squid-development.mdx modified: docs/sdk/overview.mdx modified: docs/sdk/reference/graphql-server/configuration/authorization.md modified: docs/sdk/reference/graphql-server/configuration/dos-protection.md modified: docs/sdk/reference/graphql-server/configuration/subscriptions.md modified: docs/sdk/reference/graphql-server/openreader/and-or-filters.md modified: docs/sdk/reference/graphql-server/openreader/cross-relation-field-queries.md modified: docs/sdk/reference/graphql-server/openreader/intro.md modified: docs/sdk/reference/graphql-server/openreader/nested-field-queries.md modified: docs/sdk/reference/graphql-server/openreader/paginate-query-results.md modified: docs/sdk/reference/graphql-server/openreader/queries.md modified: docs/sdk/reference/graphql-server/overview.md modified: docs/sdk/reference/schema-file/entity-relations.md modified: docs/sdk/reference/schema-file/interfaces.md modified: docs/sdk/reference/schema-file/intro.md modified: docs/sdk/resources/basics/multichain.md modified: docs/sdk/resources/migrate/migrate-subgraph.md modified: docs/sdk/troubleshooting.mdx --- docs/cloud/resources/best-practices.md | 8 +++++--- docs/glossary.md | 9 ++++++--- docs/overview.mdx | 4 ++-- docs/sdk/faq.md | 2 +- docs/sdk/how-to-start/layout.md | 4 ++-- docs/sdk/how-to-start/squid-development.mdx | 10 +++++----- docs/sdk/overview.mdx | 4 ++-- .../graphql-server/configuration/authorization.md | 4 ++-- .../graphql-server/configuration/dos-protection.md | 2 +- .../graphql-server/configuration/subscriptions.md | 2 +- .../graphql-server/openreader/and-or-filters.md | 4 ++-- .../openreader/cross-relation-field-queries.md | 2 +- docs/sdk/reference/graphql-server/openreader/intro.md | 6 +++--- .../graphql-server/openreader/nested-field-queries.md | 2 +- .../openreader/paginate-query-results.md | 2 +- .../sdk/reference/graphql-server/openreader/queries.md | 2 +- docs/sdk/reference/graphql-server/overview.md | 8 ++++---- docs/sdk/reference/schema-file/entity-relations.md | 2 +- docs/sdk/reference/schema-file/interfaces.md | 6 +++--- docs/sdk/reference/schema-file/intro.md | 2 +- docs/sdk/resources/basics/multichain.md | 6 +++--- docs/sdk/resources/migrate/migrate-subgraph.md | 6 +++--- docs/sdk/troubleshooting.mdx | 4 ++-- 23 files changed, 53 insertions(+), 48 deletions(-) diff --git a/docs/cloud/resources/best-practices.md b/docs/cloud/resources/best-practices.md index 65b769d7..8c65236c 100644 --- a/docs/cloud/resources/best-practices.md +++ b/docs/cloud/resources/best-practices.md @@ -18,9 +18,11 @@ Batch handler data filtering used to be compulsory before the release of `@subsq * If your squid [saves its data to a database](/sdk/resources/persisting-data/typeorm), make sure your [schema](/sdk/reference/schema-file) has [`@index` decorators](/sdk/reference/schema-file/indexes-and-constraints) for all entities that will be looked up frequently. -* If your squid serves a [GraphQL API](/sdk/resources/graphql-server), consider: - 1. configuring the built-in [DoS protection](/sdk/resources/graphql-server/dos-protection) against heavy queries; - 2. configuring [caching](/sdk/resources/graphql-server/caching). +* If your squid serves a [GraphQL API](/sdk/resources/basics/serving-graphql) + 1. Do not use the [SQD GraphQL server](/sdk/resources/basics/serving-graphql/#the-sqd-graphql-server) if your application uses subscriptions. Instead, use [PostGraphile](/sdk/resources/basics/serving-graphql/#postgraphile) or [Hasura](/sdk/resources/basics/serving-graphql/#hasura). + 2. If you do use the SQD GraphQL server: + - configure the built-in [DoS protection](/sdk/reference/graphql-server/configuration/dos-protection) against heavy queries; + - configure [caching](/sdk/reference/graphql-server/configuration/caching). * If you deploy your squid to Subsquid Cloud: 1. Deploy your squid to a [Professional organization](/cloud/resources/organizations/#professional-organizations). diff --git a/docs/glossary.md b/docs/glossary.md index 675544c4..29e802aa 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -70,11 +70,14 @@ An SDK (software development kit) and a smart-contract language for developing W ### OpenReader -An open-source GraphQL server that automatically generates an expressive API from an input schema file. +The GraphQL schema generation library at the heart of the open-source [SQD GraphQL server](/sdk/reference/graphql-server). + * [GitHub repo](https://github.com/subsquid/squid-sdk/tree/master/graphql/openreader) -* [Server documentation](/sdk/resources/graphql-server) +* [Server documentation](/sdk/reference/graphql-server/overview) * [Schema dialect reference](/sdk/reference/schema-file) -* [GraphQL API reference](/sdk/reference/openreader) +* [GraphQL API reference](/sdk/reference/graphql-server/openreader) + +See [Serving GraphQL](/sdk/resources/basics/serving-graphql) to learn more. ### Pallet diff --git a/docs/overview.mdx b/docs/overview.mdx index a275b9f7..6ec94feb 100644 --- a/docs/overview.mdx +++ b/docs/overview.mdx @@ -51,7 +51,7 @@ For real-time use cases such as app-specific APIs use [Squid SDK](/sdk): it'll u - [High-level libraries](/sdk/reference/processors) for extracting and filtering the Subsquid Network data in what can be though of as Extract-Transform-Load (ETL) pipelines - [Ergonomic tools](/sdk/resources/tools/typegen) for decoding and normalizing raw data and efficiently accessing [network state](/sdk/resources/tools/typegen/state-queries) - Pluggable [data sinks](/sdk/reference/store) to save data into Postgres, files (local or s3) or BigQuery -- Expressive [GraphQL server](/sdk/resources/graphql-server) with a schema-based [config](/sdk/reference/schema-file) +- An expressive [GraphQL server](/sdk/resources/basics/serving-graphql#the-sqd-graphql-server) with a schema-based [config](/sdk/reference/schema-file) - Seamless handling of [unfinalized blocks and chain reorganizations](/sdk/resources/basics/unfinalized-blocks) for real-time data ingestion - rapid data extraction and decoding [for local analytics](/sdk/tutorials/file-csv) @@ -81,7 +81,7 @@ A Platform-as-a-Service for deploying Squid SDK indexers, featuring - Learn about [squid components](/sdk/overview), [combining them](/sdk/how-to-start/squid-from-scratch) or follow the [end-to-end development guide](/sdk/how-to-start/squid-development) - Explore [tutorials](/sdk/tutorials) or [examples](/sdk/examples) - Learn how to [migrate from The Graph](/sdk/resources/migrate/migrate-subgraph) -- Explore the [GraphQL server options](/sdk/resources/graphql-server) including custom extensions, caching and DoS protection in production +- Explore the [GraphQL server options](/sdk/resources/basics/serving-graphql) ```mdx-code-block diff --git a/docs/sdk/faq.md b/docs/sdk/faq.md index bddf2137..45790e45 100644 --- a/docs/sdk/faq.md +++ b/docs/sdk/faq.md @@ -24,7 +24,7 @@ Since the ArrowSquid release, the Squid SDK has the option to ingest unfinalized ### How do I enable GraphQL subscriptions for local runs? -Add `--subscription` flag to the `serve` command defined in `commands.json`. See [Subscriptions](/sdk/resources/graphql-server/subscriptions) for details. +Add `--subscription` flag to the `serve` command defined in `commands.json`. See [Subscriptions](/sdk/reference/graphql-server/configuration/subscriptions) for details. ### How do squids keep track of their sync progress? diff --git a/docs/sdk/how-to-start/layout.md b/docs/sdk/how-to-start/layout.md index a8608965..1f58a7b2 100644 --- a/docs/sdk/how-to-start/layout.md +++ b/docs/sdk/how-to-start/layout.md @@ -13,13 +13,13 @@ All files and folders except `package.json` are optional. - `tsconfig.json` -- Configuration of `tsc`. Required for most squids. - [Deployment manifest](/cloud/reference/manifest) (`squid.yaml` by default) -- Definitions of squid services used for running it locally with [`sqd run`](/squid-cli/run) and deploying to [Subsquid Cloud](/cloud). - `.squidignore` -- Files and patterns to be excluded when sending the squid code to the [Cloud](/cloud). When not supplied, some files will still be omitted: see the [reference page](/cloud/reference/squidignore) for details. -- `schema.graphql` -- [The schema definition file](/sdk/reference/schema-file). Required if your squid uses the [built-in GraphQL server](/sdk/resources/graphql-server). +- `schema.graphql` -- [The schema definition file](/sdk/reference/schema-file). Required if your squid [stores its data in PostgreSQL](/sdk/resources/persisting-data/typeorm). - `/src` -- The TypeScript source code folder for the squid processor. + `/src/main.ts` -- The entry point of the squid processor process. Typically, contains a `processor.run()` call. + `/src/processor.ts` -- Processor object ([EVM](/sdk/reference/processors/evm-batch) or [Substrate](/sdk/reference/processors/substrate-batch)) definition and configuration. + `/src/model/generated` -- The folder for the TypeORM entities generated from `schema.graphql`. + `/src/model` -- The module exporting the entity classes. - + `/src/server-extension/resolvers` -- A folder for [user-defined GraphQL resolvers](/sdk/resources/graphql-server/custom-resolvers). + + `/src/server-extension/resolvers` -- A folder for [user-defined GraphQL resolvers](/sdk/reference/graphql-server/configuration/custom-resolvers) used by the [SQD GraphQL server](/sdk/reference/graphql-server). + `/src/types` -- A folder for types generated by the Substrate [typegen](/sdk/resources/tools/typegen/) tool for use in data decoding. + `/src/abi` -- A folder for modules generated by the EVM [typegen](/sdk/resources/tools/typegen/) tool containing type definitions and data decoding boilerplate code. - `/db` -- The designated folder with the [database migrations](/sdk/resources/persisting-data/typeorm). diff --git a/docs/sdk/how-to-start/squid-development.mdx b/docs/sdk/how-to-start/squid-development.mdx index 5f1189d6..abc38f4e 100644 --- a/docs/sdk/how-to-start/squid-development.mdx +++ b/docs/sdk/how-to-start/squid-development.mdx @@ -27,7 +27,7 @@ See also the [Environment set up](/sdk/how-to-start/development-environment-set- Consider your business requirements and find out 1. How the data should be delivered. Options: - - [PostgreSQL](/sdk/resources/persisting-data/typeorm) with an optional [GraphQL API](/sdk/resources/graphql-server) - can be real-time + - [PostgreSQL](/sdk/resources/persisting-data/typeorm) with an optional [GraphQL API](/sdk/resources/basics/serving-graphql) - can be real-time - [file-based dataset](/sdk/resources/persisting-data/file) - local or on S3 - [Google BigQuery](/sdk/resources/persisting-data/bigquery/) 2. What data should be delivered @@ -57,10 +57,10 @@ Suppose you want to train a prototype ML model on all trades done on Uniswap Pol
NFT ownership on Ethereum -Suppose you want to make a website that shows the image and ownership history for ERC721 NFTs from a certain Polygon contract. +Suppose you want to make a website that shows the image and ownership history for ERC721 NFTs from a certain Ethereum contract. 1. For this application it makes sense to deliver a GraphQL API. -2. Output data might have `Token`, `Owner` and `Transfer` [entities](/sdk/reference/openreader/queries), with e.g. `Token` supplying all the fields necessary to show ownership history and the image. +2. Output data might have `Token`, `Owner` and `Transfer` database tables / [entities](/sdk/reference/schema-file/entities), with e.g. `Token` supplying all the fields necessary to show ownership history and the image. 3. Ethereum is an EVM chain. 4. Data on token mints and ownership history can be derived from `Transfer(address,address,uint256)` EVM event logs emitted by the contract. To render images, you will also need token metadata URLs that are only available by [querying the contract state](/sdk/resources/tools/typegen/state-queries) with the `tokenURI(uint256)` function. 5. You'll need to retrieve the off-chain token metadata (usually from IPFS). @@ -464,7 +464,7 @@ At `src/main.ts`, change the [`Database`](/sdk/resources/persisting-data/overvie ``` -1. Define the schema of the database (and the [core schema of the GraphQL API](/sdk/reference/openreader) if it is used) at [`schema.graphql`](/sdk/reference/schema-file). +1. Define the schema of the database (and the [core schema of the GraphQL API](/sdk/reference/graphql-server/openreader) if it is used) at [`schema.graphql`](/sdk/reference/schema-file). 2. Regenerate the TypeORM model classes with ```bash @@ -641,4 +641,4 @@ For complete examples of complex squids take a look at the [Giant Squid Explorer ## Next steps * Deploy your squid [on own infrastructure](/sdk/resources/basics/self-hosting) or to [Subsquid Cloud](/cloud) -* If your squid serves a GraphQL API, consult the [Core GraphQL API reference](/sdk/reference/openreader) while writing your frontend +* If your squid serves a [SQD GraphQL server](/sdk/reference/graphql-server/)-compatible API, consult the [core GraphQL API reference](/sdk/reference/graphql-server/openreader) while writing your frontend application. diff --git a/docs/sdk/overview.mdx b/docs/sdk/overview.mdx index 9ace965a..41513324 100644 --- a/docs/sdk/overview.mdx +++ b/docs/sdk/overview.mdx @@ -75,9 +75,9 @@ Install these with `--save-dev`. ### GraphQL server -Squids that store their data in PostgreSQL can subsequently make it available as a GraphQL API. To use this functionality, install [`@subsquid/graphql-server`](https://www.npmjs.com/package/@subsquid/graphql-server). +Squids that store their data in PostgreSQL can subsequently make it available as a GraphQL API via a variety of supported servers. See [Serving GraphQL](/sdk/resources/basics/serving-graphql). -The [server](/sdk/resources/graphql-server) runs as a separate process. [Core API](/sdk/reference/openreader) is automatically derived from the database schema; it is possible to extend it with [custom queries](/sdk/resources/graphql-server/custom-resolvers) and [basic access control](/sdk/resources/graphql-server/authorization). +Among other alternatives, SQD provides its own server via the [`@subsquid/graphql-server`](https://www.npmjs.com/package/@subsquid/graphql-server) package. The server runs as a separate process. [Core API](/sdk/reference/graphql-server/openreader) is automatically derived from the schema file; it is possible to extend it with [custom queries](/sdk/reference/graphql-server/configuration/custom-resolvers) and [basic access control](/sdk/reference/graphql-server/configuration/authorization). ### Misc utilities diff --git a/docs/sdk/reference/graphql-server/configuration/authorization.md b/docs/sdk/reference/graphql-server/configuration/authorization.md index 033dd8fd..d92d554c 100644 --- a/docs/sdk/reference/graphql-server/configuration/authorization.md +++ b/docs/sdk/reference/graphql-server/configuration/authorization.md @@ -48,7 +48,7 @@ Here, ## Sending user data to resolvers -Authentication data such as user name can be passed from `requestCheck()` to a [custom resolver](/sdk/resources/graphql-server/custom-resolvers/) through Openreader context: +Authentication data such as user name can be passed from `requestCheck()` to a [custom resolver](/sdk/reference/graphql-server/configuration/custom-resolvers/) through Openreader context: ```typescript export async function requestCheck(req: RequestCheckContext): Promise { ... @@ -100,7 +100,7 @@ export class UserCommentResolver { ``` See full code in [this branch](https://github.com/subsquid-labs/access-control-example/tree/interacting-with-resolver). -This approach does not work with [subscriptions](/sdk/resources/graphql-server/subscriptions/). +This approach does not work with [subscriptions](/sdk/reference/graphql-server/configuration/subscriptions/). ## Examples diff --git a/docs/sdk/reference/graphql-server/configuration/dos-protection.md b/docs/sdk/reference/graphql-server/configuration/dos-protection.md index 63586be7..2b78377e 100644 --- a/docs/sdk/reference/graphql-server/configuration/dos-protection.md +++ b/docs/sdk/reference/graphql-server/configuration/dos-protection.md @@ -65,7 +65,7 @@ In a nutshell, assuming that the schema file is properly decorated with `@cardin **`--subscription-max-response-size `** -Same as `--max-response-size` but for live query [subscriptions](/sdk/resources/graphql-server/subscriptions). +Same as `--max-response-size` but for live query [subscriptions](/sdk/reference/graphql-server/configuration/subscriptions). #### Example diff --git a/docs/sdk/reference/graphql-server/configuration/subscriptions.md b/docs/sdk/reference/graphql-server/configuration/subscriptions.md index 15e2c5b2..8fb32236 100644 --- a/docs/sdk/reference/graphql-server/configuration/subscriptions.md +++ b/docs/sdk/reference/graphql-server/configuration/subscriptions.md @@ -20,7 +20,7 @@ npx squid-graphql-server --help For each entity types, the following queries are supported for subscriptions: - `${EntityName}ById` -- query a single entity - `${EntityName}s` -- query multiple entities with a `where` filter -Note that despite being [deprecated](/sdk/resources/graphql-server/overview/#supported-queries) from the regular query set, `${EntityName}s` queries will continue to be available for subscriptions going forward. +Note that despite being [deprecated](/sdk/resources/basics/serving-graphql/#supported-queries) from the regular query set, `${EntityName}s` queries will continue to be available for subscriptions going forward. ## Local runs diff --git a/docs/sdk/reference/graphql-server/openreader/and-or-filters.md b/docs/sdk/reference/graphql-server/openreader/and-or-filters.md index 25405b1b..0ccdd4ee 100644 --- a/docs/sdk/reference/graphql-server/openreader/and-or-filters.md +++ b/docs/sdk/reference/graphql-server/openreader/and-or-filters.md @@ -9,11 +9,11 @@ description: >- ## Overview -Our GraphQL implementation offers a vast selection of tools to filter and section results. One of these is the `where` clause, very common in most database query languages and [explained here](/sdk/reference/openreader/queries/#filter-query-results--search-queries) in detail. +Our GraphQL implementation offers a vast selection of tools to filter and section results. One of these is the `where` clause, very common in most database query languages and [explained here](/sdk/reference/graphql-server/openreader/queries/#filter-query-results--search-queries) in detail. In our GraphQL server implementation, we included logical operators to be used in the `where` clause, allowing to group multiple parameters in the same `where` argument using the `AND` and `OR` operators to filter results based on more than one criteria. -Note that the [newer](/sdk/resources/graphql-server/overview/#supported-queries) and [more advanced](/sdk/reference/openreader/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. +Note that the [newer](/sdk/resources/basics/serving-graphql/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. ### Example of an `OR` clause: diff --git a/docs/sdk/reference/graphql-server/openreader/cross-relation-field-queries.md b/docs/sdk/reference/graphql-server/openreader/cross-relation-field-queries.md index 1142d451..c6f846e3 100644 --- a/docs/sdk/reference/graphql-server/openreader/cross-relation-field-queries.md +++ b/docs/sdk/reference/graphql-server/openreader/cross-relation-field-queries.md @@ -9,7 +9,7 @@ description: >- ## Introduction -The [previous section](/sdk/reference/openreader/nested-field-queries) has already demonstrated that queries can return not just scalars such as a String, but also fields that refer to object or entity types. What's even more interesting is that queries can leverage fields of related objects to filter results. +The [previous section](/sdk/reference/graphql-server/openreader/nested-field-queries) has already demonstrated that queries can return not just scalars such as a String, but also fields that refer to object or entity types. What's even more interesting is that queries can leverage fields of related objects to filter results. Let's take this sample schema with two entity types and a one-to-many relationship between them: diff --git a/docs/sdk/reference/graphql-server/openreader/intro.md b/docs/sdk/reference/graphql-server/openreader/intro.md index 585ed764..914cc007 100644 --- a/docs/sdk/reference/graphql-server/openreader/intro.md +++ b/docs/sdk/reference/graphql-server/openreader/intro.md @@ -6,14 +6,14 @@ description: >- --- :::info -At the moment, [Squid SDK GraphQL server](/sdk/resources/graphql-server) can only be used with squids that use Postgres as their target database. +At the moment, [Squid SDK GraphQL server](/sdk/resources/basics/serving-graphql) can only be used with squids that use Postgres as their target database. ::: GraphQL is an API query language, and a server-side runtime for executing queries using a custom type system. Head over to the [official documentation website](https://graphql.org/learn/) for more info. -A GraphQL API served by the [GraphQL server](/sdk/resources/graphql-server) has two components: +A GraphQL API served by the [GraphQL server](/sdk/resources/basics/serving-graphql) has two components: 1. Core API is defined by the [schema file](/sdk/reference/schema-file). -2. Extensions added via [custom resolvers](/sdk/resources/graphql-server/custom-resolvers). +2. Extensions added via [custom resolvers](/sdk/reference/graphql-server/configuration/custom-resolvers). In this section we cover the core GraphQL API, with short explanations on how to perform GraphQL queries, how to paginate and sort results. This functionality is supported via [OpenReader](https://github.com/subsquid/squid-sdk/tree/master/graphql/openreader), Subsquid's own implementation of [OpenCRUD](https://www.opencrud.org). diff --git a/docs/sdk/reference/graphql-server/openreader/nested-field-queries.md b/docs/sdk/reference/graphql-server/openreader/nested-field-queries.md index 79ae0156..740f334e 100644 --- a/docs/sdk/reference/graphql-server/openreader/nested-field-queries.md +++ b/docs/sdk/reference/graphql-server/openreader/nested-field-queries.md @@ -44,4 +44,4 @@ query { } ``` -Note that the [newer](/sdk/resources/graphql-server/overview/#supported-queries) and [more advanced](/sdk/reference/openreader/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. +Note that the [newer](/sdk/resources/basics/serving-graphql/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. diff --git a/docs/sdk/reference/graphql-server/openreader/paginate-query-results.md b/docs/sdk/reference/graphql-server/openreader/paginate-query-results.md index 954b097a..1a1cdde6 100644 --- a/docs/sdk/reference/graphql-server/openreader/paginate-query-results.md +++ b/docs/sdk/reference/graphql-server/openreader/paginate-query-results.md @@ -15,7 +15,7 @@ Cursors are used to traverse across entities of an entity set. They work by retu Currently, only forward pagination is supported. If your use case requires bidirectional pagination please let us know at our [Telegram channel](https://t.me/HydraDevs). -In Subsquid GraphQL server, cursor based pagination is implemented with `{entityName}sConnection` queries available for every entity in the input schema. These queries require an explicitly supplied [`orderBy` argument](/sdk/reference/openreader/sorting), and *the field that is used for ordering must also be requested by the query itself*. Check out [this section](/sdk/reference/openreader/paginate-query-results/#important-note-on-orderby) for a valid query template. +In Subsquid GraphQL server, cursor based pagination is implemented with `{entityName}sConnection` queries available for every entity in the input schema. These queries require an explicitly supplied [`orderBy` argument](/sdk/reference/graphql-server/openreader/sorting), and *the field that is used for ordering must also be requested by the query itself*. Check out [this section](/sdk/reference/graphql-server/openreader/paginate-query-results/#important-note-on-orderby) for a valid query template. Example: this query fetches a list of videos where `isExplicit` is true and gets their count. diff --git a/docs/sdk/reference/graphql-server/openreader/queries.md b/docs/sdk/reference/graphql-server/openreader/queries.md index 69cd321f..7da741c0 100644 --- a/docs/sdk/reference/graphql-server/openreader/queries.md +++ b/docs/sdk/reference/graphql-server/openreader/queries.md @@ -29,7 +29,7 @@ query { } } ``` -or, using a [newer](/sdk/resources/graphql-server/overview/#supported-queries) and [more advanced](/sdk/reference/openreader/paginate-query-results) `{entityName}sConnection` query +or, using a [newer](/sdk/resources/basics/serving-graphql/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` query ```graphql query { diff --git a/docs/sdk/reference/graphql-server/overview.md b/docs/sdk/reference/graphql-server/overview.md index f623bb83..6a38798f 100644 --- a/docs/sdk/reference/graphql-server/overview.md +++ b/docs/sdk/reference/graphql-server/overview.md @@ -23,16 +23,16 @@ The GraphQL API is enabled by the `api:` service in the `deploy` section of [squ ## Supported queries -The details of the supported OpenReader queries can be found in a separate section [Query a Squid](/sdk/reference/openreader). Here is a brief overview of the queries generated by OpenReader for each entity defined in the schema file: +The details of the supported OpenReader queries can be found in a separate section [Query a Squid](/sdk/reference/graphql-server/openreader). Here is a brief overview of the queries generated by OpenReader for each entity defined in the schema file: - the squid last processed block is available with `squidStatus { height }` query - a "get one by ID" query with the name `{entityName}ById` for each [entity](/sdk/reference/schema-file/entities) defined in the schema file - a "get one" query for [`@unique` fields](/sdk/reference/schema-file/indexes-and-constraints), with the name `{entityName}ByUniqueInput` -- Entity queries named `{entityName}sConnection`. Each query supports rich filtering support, including [field-level filters](/sdk/reference/openreader/queries), composite [`AND` and `OR` filters](/sdk/reference/openreader/and-or-filters), [nested queries](/sdk/reference/openreader/nested-field-queries), [cross-relation queries](/sdk/reference/openreader/cross-relation-field-queries) and [Relay-compatible](https://relay.dev/graphql/connections.htm) cursor-based [pagination](/sdk/reference/openreader/paginate-query-results). -- [Subsriptions](/sdk/resources/graphql-server/subscriptions) via live queries +- Entity queries named `{entityName}sConnection`. Each query supports rich filtering support, including [field-level filters](/sdk/reference/graphql-server/openreader/queries), composite [`AND` and `OR` filters](/sdk/reference/graphql-server/openreader/and-or-filters), [nested queries](/sdk/reference/graphql-server/openreader/nested-field-queries), [cross-relation queries](/sdk/reference/graphql-server/openreader/cross-relation-field-queries) and [Relay-compatible](https://relay.dev/graphql/connections.htm) cursor-based [pagination](/sdk/reference/graphql-server/openreader/paginate-query-results). +- [Subsriptions](/sdk/reference/graphql-server/configuration/subscriptions) via live queries - (Deprecated in favor of Relay connections) Lookup queries with the name `{entityName}s`. -[Union and typed JSON types](/sdk/reference/schema-file/unions-and-typed-json) are mapped into [GraphQL Union Types](https://graphql.org/learn/schema/#union-types) with a [proper type resolution](/sdk/reference/openreader/resolve-union-types-interfaces) with `__typename`. +[Union and typed JSON types](/sdk/reference/schema-file/unions-and-typed-json) are mapped into [GraphQL Union Types](https://graphql.org/learn/schema/#union-types) with a [proper type resolution](/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces) with `__typename`. ## Built-in custom scalar types diff --git a/docs/sdk/reference/schema-file/entity-relations.md b/docs/sdk/reference/schema-file/entity-relations.md index 6cacae57..aeca917d 100644 --- a/docs/sdk/reference/schema-file/entity-relations.md +++ b/docs/sdk/reference/schema-file/entity-relations.md @@ -10,7 +10,7 @@ The term "entity relation" refers to the situation when an entity instance conta [One-to-one](https://github.com/typeorm/typeorm/blob/master/docs/one-to-one-relations.md) and [one-to-many](https://github.com/typeorm/typeorm/blob/master/docs/many-to-one-one-to-many-relations.md) relations are supported by Typeorm. The "many" side of the one-to-many relations is always the owning side. Many-to-many relations are modeled as [two one-to-many relations with an explicit join table](#many-to-many-relations). -An entity relation is always unidirectional, but it is possible to request the data on the owning entity from the non-owning one. To do so, define a field decorated `@derivedFrom` in the schema. Doing so will cause the Typeorm code generated by [`squid-typeorm-codegen`](/sdk/resources/persisting-data/typeorm) and the GraphQL API served by [`squid-graphql-server`](/sdk/resources/graphql-server/overview/) to show a virtual (that is, **not mapping to a database column**) field populated via inverse lookup queries. +An entity relation is always unidirectional, but it is possible to request the data on the owning entity from the non-owning one. To do so, define a field decorated `@derivedFrom` in the schema. Doing so will cause the Typeorm code generated by [`squid-typeorm-codegen`](/sdk/resources/persisting-data/typeorm) and the GraphQL API served by [`squid-graphql-server`](/sdk/reference/graphql-server/overview) to show a virtual (that is, **not mapping to a database column**) field populated via inverse lookup queries. The following examples illustrate the concepts. diff --git a/docs/sdk/reference/schema-file/interfaces.md b/docs/sdk/reference/schema-file/interfaces.md index 26aadd9f..c95baead 100644 --- a/docs/sdk/reference/schema-file/interfaces.md +++ b/docs/sdk/reference/schema-file/interfaces.md @@ -6,7 +6,7 @@ description: Queriable interfaces # Interfaces -The schema file supports [GraphQL Interfaces](https://graphql.org/learn/schema/#interfaces) for modelling complex types sharing common traits. Interfaces are annotated with `@query` at the type level and do not affect the backing database schema, only enriching the [GraphQL API queries](/sdk/resources/graphql-server) with [inline fragments](https://graphql.org/learn/queries/#inline-fragments). +The schema file supports [GraphQL Interfaces](https://graphql.org/learn/schema/#interfaces) for modelling complex types sharing common traits. Interfaces are annotated with `@query` at the type level and do not affect the database schema, only enriching the [API queries](/sdk/reference/graphql-server/openreader) of the [SQD GraphQL server](/sdk/reference/graphql-server) with [inline fragments](https://graphql.org/learn/queries/#inline-fragments). ### Examples @@ -47,7 +47,7 @@ type Baz implements MyEntity @entity { } ``` -The `MyEntity` interface above enables `myEntities` and `myEntitiesConnection` [GraphQL API queries](/sdk/resources/graphql-server) with inline fragments and the `_type`, `__typename` [meta fields](https://graphql.org/learn/queries/#meta-fields): +The `MyEntity` interface above enables `myEntities` and `myEntitiesConnection` [GraphQL API queries](/sdk/reference/graphql-server/openreader) with inline fragments and the `_type`, `__typename` [meta fields](https://graphql.org/learn/queries/#meta-fields): ```graphql query { @@ -64,4 +64,4 @@ query { ... on Baz { baz } } } -``` \ No newline at end of file +``` diff --git a/docs/sdk/reference/schema-file/intro.md b/docs/sdk/reference/schema-file/intro.md index c75046a2..85631dd1 100644 --- a/docs/sdk/reference/schema-file/intro.md +++ b/docs/sdk/reference/schema-file/intro.md @@ -10,7 +10,7 @@ description: >- The schema file `schema.graphql` uses a GraphQL dialect to model the target entities and entity relations. The tooling around the schema file is then used to: - Generate TypeORM entities (with `squid-typeorm-codegen(1)`, see below) - Generate the database schema from the TypeORM entities (see [db migrations](/sdk/resources/persisting-data/typeorm)) -- Present the target data with a rich API served by a built-in [GraphQL Server](/sdk/resources/graphql-server). A full API reference is covered in the [Query a Squid](/sdk/reference/openreader) section. +- Optionally, the schema can be used to present the target data with a [GraphQL API](/sdk/resources/basics/serving-graphql). The schema file format is loosely compatible with the [subgraph schema](https://thegraph.com/docs/en/developing/creating-a-subgraph/) file, see [Migrate from subgraph](/sdk/resources/migrate/migrate-subgraph) section for details. diff --git a/docs/sdk/resources/basics/multichain.md b/docs/sdk/resources/basics/multichain.md index bf93a065..f8342178 100644 --- a/docs/sdk/resources/basics/multichain.md +++ b/docs/sdk/resources/basics/multichain.md @@ -6,7 +6,7 @@ description: Combine data from multiple chains # Multichain indexing -Squids can extract data from multiple chains into a shared data sink. If the data is [stored to Postgres](/sdk/resources/persisting-data/typeorm) it can then be served as a unified multichain [GraphQL API](/sdk/resources/graphql-server). +Squids can extract data from multiple chains into a shared data sink. If the data is [stored to Postgres](/sdk/resources/persisting-data/typeorm) it can then be served as a unified multichain [GraphQL API](/sdk/resources/basics/serving-graphql). To do this, run one [processor](/sdk/overview) per source network: @@ -69,7 +69,7 @@ Also ensure that async (ctx) => { // ... ``` -2. [Schema](/sdk/reference/schema-file) and [GraphQL API](/sdk/resources/graphql-server) are shared among the processors. +2. [Schema](/sdk/reference/schema-file) and [GraphQL API](/sdk/resources/basics/serving-graphql) are shared among the processors. ### Handling concurrency @@ -79,7 +79,7 @@ Also ensure that - To avoid cross-chain data dependencies, use per-chain records for volatile data. E.g. if you track account balances across multiple chains you can avoid overlaps by storing the balance for each chain in a different table row. - When you need to combine the records (e.g. get a total of all balaces across chains) use a [custom resolver](/sdk/resources/graphql-server/custom-resolvers) to do it on the GraphQL server side. + When you need to combine the records (e.g. get a total of all balaces across chains) use a [custom resolver](/sdk/reference/graphql-server/configuration/custom-resolvers) to do it on the GraphQL server side. - It is OK to use cross-chain [entities](/sdk/reference/schema-file/entities) to simplify aggregation. Just don't store any data in them: ```graphql diff --git a/docs/sdk/resources/migrate/migrate-subgraph.md b/docs/sdk/resources/migrate/migrate-subgraph.md index fb1b818b..67d80ca2 100644 --- a/docs/sdk/resources/migrate/migrate-subgraph.md +++ b/docs/sdk/resources/migrate/migrate-subgraph.md @@ -14,7 +14,7 @@ git clone https://github.com/subsquid-labs/gravatar-squid.git `EvmBatchProcessor` provided by the Squid SDK defines a single handler that indexes EVM logs and transaction data in batches. It differs from the programming model of subgraph mappings that defines a separate data handler for each EVM log topic to be indexed. Due to significantly less frequent database hits (once per batch compared to once per log) the batch-based handling model shows up to a 10x increase in the indexing speed. -At the same time, concepts of the [schema file](/sdk/reference/schema-file), [code generation from the schema file](/sdk/reference/schema-file/intro/#typeorm-codegen) and [auto-generated GraphQL API](/sdk/resources/graphql-server) should be familiar to subgraph developers. In most cases the schema file of a subgraph can be imported into a squid as is. +At the same time, concepts of the [schema file](/sdk/reference/schema-file), [code generation from the schema file](/sdk/reference/schema-file/intro/#typeorm-codegen) and [auto-generated GraphQL API](/sdk/resources/basics/serving-graphql) should be familiar to subgraph developers. In most cases the schema file of a subgraph can be imported into a squid as is. There are some known limitations: - Many-to-Many entity relations should be [modeled explicitly](/sdk/reference/schema-file/entity-relations/#many-to-many-relations) as two many-to-one relations @@ -24,10 +24,10 @@ On top of the features provided by subgraphs, Squid SDK and Subsquid Cloud offer - Full control over the target database (Postgres), including custom migrations and ad-hoc queries in the handler - Custom target databases and data formats (e.g. CSV) - Arbitrary code execution in the data handler -- [Extension of the GraphQL API](/sdk/resources/graphql-server/custom-resolvers) with arbitrary SQL +- [Extension of the GraphQL API](/sdk/reference/graphql-server/configuration/custom-resolvers) with arbitrary SQL - [Secret environment variables](/cloud/resources/env-variables), allowing to seamlessly use private third-party JSON-RPC endpoints and integrate with external APIs - [API versioning and aliasing](/cloud/resources/production-alias) -- [API caching](/sdk/resources/graphql-server/caching) +- [API caching](/sdk/reference/graphql-server/configuration/caching) For a full feature set comparison, see [Subsquid vs The Graph](/sdk/subsquid-vs-thegraph). diff --git a/docs/sdk/troubleshooting.mdx b/docs/sdk/troubleshooting.mdx index c79aa4dc..20f0494d 100644 --- a/docs/sdk/troubleshooting.mdx +++ b/docs/sdk/troubleshooting.mdx @@ -69,13 +69,13 @@ PostgreSQL doesn't support storing `NULL (\0x00)` characters in text fields. Usu API queries are too slow - Make sure all the necessary fields are [indexed](/sdk/reference/schema-file/indexes-and-constraints/) -- Annotate the schema and [set reasonable limits](/sdk/resources/graphql-server/dos-protection/) for the incoming queries to protect against DoS attacks +- Annotate the schema and [set reasonable limits](/sdk/reference/graphql-server/configuration/dos-protection/) for the incoming queries to protect against DoS attacks
`response might exceed the size limit` -Make sure the input query has limits set or the entities are decorated with `@cardinality`. We recommend using `XXXConnection` queries for pagination. For configuring limits and max response sizes, see [DoS protection](/sdk/resources/graphql-server/dos-protection/). +Make sure the input query has limits set or the entities are decorated with `@cardinality`. We recommend using `XXXConnection` queries for pagination. For configuring limits and max response sizes, see [DoS protection](/sdk/reference/graphql-server/configuration/dos-protection/).
From 59f44dd38d2f74f3af5d1e36dd1f42c686dd7a9b Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Fri, 6 Sep 2024 04:31:00 +0900 Subject: [PATCH 05/16] More link fixes modified: docs/sdk/reference/graphql-server/configuration/subscriptions.md modified: docs/sdk/reference/graphql-server/openreader/and-or-filters.md modified: docs/sdk/reference/graphql-server/openreader/intro.md modified: docs/sdk/reference/graphql-server/openreader/nested-field-queries.md modified: docs/sdk/reference/graphql-server/openreader/queries.md modified: docs/sdk/reference/graphql-server/overview.md --- .../reference/graphql-server/configuration/subscriptions.md | 2 +- .../sdk/reference/graphql-server/openreader/and-or-filters.md | 2 +- docs/sdk/reference/graphql-server/openreader/intro.md | 4 ++-- .../graphql-server/openreader/nested-field-queries.md | 2 +- docs/sdk/reference/graphql-server/openreader/queries.md | 2 +- docs/sdk/reference/graphql-server/overview.md | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/sdk/reference/graphql-server/configuration/subscriptions.md b/docs/sdk/reference/graphql-server/configuration/subscriptions.md index 8fb32236..04279e00 100644 --- a/docs/sdk/reference/graphql-server/configuration/subscriptions.md +++ b/docs/sdk/reference/graphql-server/configuration/subscriptions.md @@ -20,7 +20,7 @@ npx squid-graphql-server --help For each entity types, the following queries are supported for subscriptions: - `${EntityName}ById` -- query a single entity - `${EntityName}s` -- query multiple entities with a `where` filter -Note that despite being [deprecated](/sdk/resources/basics/serving-graphql/#supported-queries) from the regular query set, `${EntityName}s` queries will continue to be available for subscriptions going forward. +Note that despite being [deprecated](/sdk/reference/graphql-server/overview/#supported-queries) from the regular query set, `${EntityName}s` queries will continue to be available for subscriptions going forward. ## Local runs diff --git a/docs/sdk/reference/graphql-server/openreader/and-or-filters.md b/docs/sdk/reference/graphql-server/openreader/and-or-filters.md index 0ccdd4ee..5141d303 100644 --- a/docs/sdk/reference/graphql-server/openreader/and-or-filters.md +++ b/docs/sdk/reference/graphql-server/openreader/and-or-filters.md @@ -13,7 +13,7 @@ Our GraphQL implementation offers a vast selection of tools to filter and sectio In our GraphQL server implementation, we included logical operators to be used in the `where` clause, allowing to group multiple parameters in the same `where` argument using the `AND` and `OR` operators to filter results based on more than one criteria. -Note that the [newer](/sdk/resources/basics/serving-graphql/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. +Note that the [newer](/sdk/reference/graphql-server/overview/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. ### Example of an `OR` clause: diff --git a/docs/sdk/reference/graphql-server/openreader/intro.md b/docs/sdk/reference/graphql-server/openreader/intro.md index 914cc007..2a769356 100644 --- a/docs/sdk/reference/graphql-server/openreader/intro.md +++ b/docs/sdk/reference/graphql-server/openreader/intro.md @@ -6,12 +6,12 @@ description: >- --- :::info -At the moment, [Squid SDK GraphQL server](/sdk/resources/basics/serving-graphql) can only be used with squids that use Postgres as their target database. +At the moment, [Squid SDK GraphQL server](/sdk/reference/graphql-server) can only be used with squids that use Postgres as their target database. ::: GraphQL is an API query language, and a server-side runtime for executing queries using a custom type system. Head over to the [official documentation website](https://graphql.org/learn/) for more info. -A GraphQL API served by the [GraphQL server](/sdk/resources/basics/serving-graphql) has two components: +A GraphQL API served by the [GraphQL server](/sdk/reference/graphql-server) has two components: 1. Core API is defined by the [schema file](/sdk/reference/schema-file). 2. Extensions added via [custom resolvers](/sdk/reference/graphql-server/configuration/custom-resolvers). diff --git a/docs/sdk/reference/graphql-server/openreader/nested-field-queries.md b/docs/sdk/reference/graphql-server/openreader/nested-field-queries.md index 740f334e..eb74dc9a 100644 --- a/docs/sdk/reference/graphql-server/openreader/nested-field-queries.md +++ b/docs/sdk/reference/graphql-server/openreader/nested-field-queries.md @@ -44,4 +44,4 @@ query { } ``` -Note that the [newer](/sdk/resources/basics/serving-graphql/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. +Note that the [newer](/sdk/reference/graphql-server/overview/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. diff --git a/docs/sdk/reference/graphql-server/openreader/queries.md b/docs/sdk/reference/graphql-server/openreader/queries.md index 7da741c0..e4832598 100644 --- a/docs/sdk/reference/graphql-server/openreader/queries.md +++ b/docs/sdk/reference/graphql-server/openreader/queries.md @@ -29,7 +29,7 @@ query { } } ``` -or, using a [newer](/sdk/resources/basics/serving-graphql/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` query +or, using a [newer](/sdk/reference/graphql-server/overview/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` query ```graphql query { diff --git a/docs/sdk/reference/graphql-server/overview.md b/docs/sdk/reference/graphql-server/overview.md index 6a38798f..73536e5e 100644 --- a/docs/sdk/reference/graphql-server/overview.md +++ b/docs/sdk/reference/graphql-server/overview.md @@ -6,7 +6,7 @@ description: The SQD GraphQL server, built in-house # Overview :::info -SQD GraphQL server is no longer recommended for use in new squid projects [relying on PostgreSQL](/sdk/resources/persisting-data/typeorm). See [Serving GraphQL](/resources/basics/serving-graphql) to learn about the new options and the [Known issues](#known-issues) section to understand our motivation. +SQD GraphQL server is no longer recommended for use in new squid projects [relying on PostgreSQL](/sdk/resources/persisting-data/typeorm). See [Serving GraphQL](/sdk/resources/basics/serving-graphql) to learn about the new options and the [Known issues](#known-issues) section to understand our motivation. ::: The data indexed by a squid into a Postgres database can be automatically presented with a GraphQL API service powered by the [OpenReader](https://github.com/subsquid/squid-sdk/tree/master/graphql/openreader) lib of the Squid SDK. The OpenReader GraphQL server takes [schema file](/sdk/reference/schema-file) as an input and serves a GraphQL API supporting [OpenCRUD](https://www.opencrud.org/) queries for the entities defined in the schema. From 5c9bf8b64289869e866e7da218d984e699c3027d Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Fri, 6 Sep 2024 04:31:33 +0900 Subject: [PATCH 06/16] Updating the redirect rules modified: redirectRules.js --- redirectRules.js | 108 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 18 deletions(-) diff --git a/redirectRules.js b/redirectRules.js index 4ca83c04..cfd28ad1 100644 --- a/redirectRules.js +++ b/redirectRules.js @@ -25,7 +25,7 @@ const urlList = [ }, { "from": "/develop-a-squid/graphql-api", - "to": "/sdk/resources/graphql-server" + "to": "/sdk/resources/basics/serving-graphql" }, { "from": "/develop-a-squid/typegen/squid-substrate-typegen", @@ -409,31 +409,31 @@ const urlList = [ }, { "from": "/graphql-api/authorization", - "to": "/sdk/resources/graphql-server/authorization" + "to": "/sdk/reference/graphql-server/configuration/authorization" }, { "from": "/graphql-api/caching", - "to": "/sdk/resources/graphql-server/caching" + "to": "/sdk/reference/graphql-server/configuration/caching" }, { "from": "/graphql-api/custom-resolvers", - "to": "/sdk/resources/graphql-server/custom-resolvers" + "to": "/sdk/reference/graphql-server/configuration/custom-resolvers" }, { "from": "/graphql-api/dos-protection", - "to": "/sdk/resources/graphql-server/dos-protection" + "to": "/sdk/reference/graphql-server/configuration/dos-protection" }, { "from": "/graphql-api/overview", - "to": "/sdk/resources/graphql-server/overview" + "to": "/sdk/resources/basics/serving-graphql" }, { "from": "/graphql-api/subscriptions", - "to": "/sdk/resources/graphql-server/subscriptions" + "to": "/sdk/reference/graphql-server/configuration/subscriptions" }, { "from": "/graphql-api", - "to": "/sdk/resources/graphql-server" + "to": "/sdk/resources/basics/serving-graphql" }, { "from": "/migrate/subsquid-vs-thegraph", @@ -457,43 +457,43 @@ const urlList = [ }, { "from": "/query-squid/nested-field-queries", - "to": "/sdk/reference/openreader/nested-field-queries" + "to": "/sdk/reference/graphql-server/openreader/nested-field-queries" }, { "from": "/query-squid/sorting", - "to": "/sdk/reference/openreader/sorting" + "to": "/sdk/reference/graphql-server/openreader/sorting" }, { "from": "/query-squid/intro", - "to": "/sdk/reference/openreader/intro" + "to": "/sdk/reference/graphql-server/openreader/intro" }, { "from": "/query-squid/and-or-filters", - "to": "/sdk/reference/openreader/and-or-filters" + "to": "/sdk/reference/graphql-server/openreader/and-or-filters" }, { "from": "/query-squid/resolve-union-types-interfaces", - "to": "/sdk/reference/openreader/resolve-union-types-interfaces" + "to": "/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces" }, { "from": "/query-squid/cross-relation-field-queries", - "to": "/sdk/reference/openreader/cross-relation-field-queries" + "to": "/sdk/reference/graphql-server/openreader/cross-relation-field-queries" }, { "from": "/query-squid/json-queries", - "to": "/sdk/reference/openreader/json-queries" + "to": "/sdk/reference/graphql-server/openreader/json-queries" }, { "from": "/query-squid/queries", - "to": "/sdk/reference/openreader/queries" + "to": "/sdk/reference/graphql-server/openreader/queries" }, { "from": "/query-squid/paginate-query-results", - "to": "/sdk/reference/openreader/paginate-query-results" + "to": "/sdk/reference/graphql-server/openreader/paginate-query-results" }, { "from": "/query-squid", - "to": "/sdk/reference/openreader" + "to": "/sdk/reference/graphql-server/openreader" }, { "from": "/quickstart/quickstart-substrate", @@ -746,6 +746,78 @@ const urlList = [ { "from": "/subsquid-network/public", "to": "/subsquid-network/faq" + }, + { + "from": "/sdk/resources/graphql-server/alternatives", + "to": "/sdk/resources/basics/serving-graphql" + }, + { + "from": "/sdk/resources/graphql-server/overview", + "to": "/sdk/resources/basics/serving-graphql" + }, + { + "from": "/sdk/resources/graphql-server", + "to": "/sdk/resources/basics/serving-graphql" + }, + { + "from": "/sdk/resources/graphql-server/authorization", + "to": "/sdk/reference/graphql-server/configuration/authorization" + }, + { + "from": "/sdk/resources/graphql-server/caching", + "to": "/sdk/reference/graphql-server/configuration/caching" + }, + { + "from": "/sdk/resources/graphql-server/custom-resolvers", + "to": "/sdk/reference/graphql-server/configuration/custom-resolvers" + }, + { + "from": "/sdk/resources/graphql-server/dos-protection", + "to": "/sdk/reference/graphql-server/configuration/dos-protection" + }, + { + "from": "/sdk/resources/graphql-server/subscriptions", + "to": "/sdk/reference/graphql-server/configuration/subscriptions" + }, + { + "from": "/sdk/reference/openreader", + "to": "/sdk/reference/graphql-server/openreader" + }, + { + "from": "/sdk/reference/openreader/intro", + "to": "/sdk/reference/graphql-server/openreader/intro" + }, + { + "from": "/sdk/reference/openreader/and-or-filters", + "to": "/sdk/reference/graphql-server/openreader/and-or-filters" + }, + { + "from": "/sdk/reference/openreader/cross-relation-field-queries", + "to": "/sdk/reference/graphql-server/openreader/cross-relation-field-queries" + }, + { + "from": "/sdk/reference/openreader/json-queries", + "to": "/sdk/reference/graphql-server/openreader/json-queries" + }, + { + "from": "/sdk/reference/openreader/nested-field-queries", + "to": "/sdk/reference/graphql-server/openreader/nested-field-queries" + }, + { + "from": "/sdk/reference/openreader/paginate-query-results", + "to": "/sdk/reference/graphql-server/openreader/paginate-query-results" + }, + { + "from": "/sdk/reference/openreader/queries", + "to": "/sdk/reference/graphql-server/openreader/queries" + }, + { + "from": "/sdk/reference/openreader/resolve-union-types-interfaces", + "to": "/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces" + }, + { + "from": "/sdk/reference/openreader/sorting", + "to": "/sdk/reference/graphql-server/openreader/sorting" } ] From a43797997f5e54571d653bfdb13d49b29d8004d0 Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Fri, 6 Sep 2024 04:41:08 +0900 Subject: [PATCH 07/16] More precise wording for the subscriptions RAM issue modified: docs/sdk/reference/graphql-server/configuration/subscriptions.md modified: docs/sdk/reference/graphql-server/overview.md --- .../sdk/reference/graphql-server/configuration/subscriptions.md | 2 +- docs/sdk/reference/graphql-server/overview.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sdk/reference/graphql-server/configuration/subscriptions.md b/docs/sdk/reference/graphql-server/configuration/subscriptions.md index 04279e00..d09820ac 100644 --- a/docs/sdk/reference/graphql-server/configuration/subscriptions.md +++ b/docs/sdk/reference/graphql-server/configuration/subscriptions.md @@ -7,7 +7,7 @@ description: Subscribe to updates over a websocket # Subscriptions :::danger -Implementation of subscriptions by the SQD GraphQL server [leaks memory under load](/sdk/reference/graphql-server/overview/#known-issues). Do not use it in scenarios where more than a few users simultaneously maintain connections to the server. This includes most production usage scenarios. +RAM usage of subscriptions scales poorly under high load, making the feature unsuitable for most production uses. There are currently no plans to fix this issue. ::: OpenReader supports [GraphQL subscriptions](https://www.apollographql.com/docs/react/data/subscriptions/) via live queries. To use these, a client opens a websocket connection to the server and sends a `subscription` query there. The query body is then repeatedly executed (every 5 seconds by default) and the results are sent to the client whenever they change. diff --git a/docs/sdk/reference/graphql-server/overview.md b/docs/sdk/reference/graphql-server/overview.md index 73536e5e..76cb7dd7 100644 --- a/docs/sdk/reference/graphql-server/overview.md +++ b/docs/sdk/reference/graphql-server/overview.md @@ -44,6 +44,6 @@ The OpenReader GraphQL API defines the following custom scalar types: ## Known issues -- [Subscriptions](/sdk/reference/graphql-server/configuration/subscriptions) leak memory under load and are thus unsuitable for use in production. +- RAM usage of [subscriptions](/sdk/reference/graphql-server/configuration/subscriptions) scales poorly under high load, making the feature unsuitable for most production uses. There are currently no plans to fix this issue. - Setting up custom resolvers for subscriptions is unreasonably hard. - `@subsquid/graphql-server` depends on the deprecated Apollo Server v3. From fcf19f939e7fc043024d744c34403b547dccd97b Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Tue, 10 Sep 2024 18:38:59 +0900 Subject: [PATCH 08/16] Renaming Openreader-related folders renamed: docs/sdk/reference/graphql-server/_category_.json -> docs/sdk/reference/openreader-server/_category_.json renamed: docs/sdk/reference/graphql-server/openreader/_category_.json -> docs/sdk/reference/openreader-server/api/_category_.json renamed: docs/sdk/reference/graphql-server/openreader/and-or-filters.md -> docs/sdk/reference/openreader-server/api/and-or-filters.md renamed: docs/sdk/reference/graphql-server/openreader/cross-relation-field-queries.md -> docs/sdk/reference/openreader-server/api/cross-relation-field-queries.md renamed: docs/sdk/reference/graphql-server/openreader/intro.md -> docs/sdk/reference/openreader-server/api/intro.md renamed: docs/sdk/reference/graphql-server/openreader/json-queries.md -> docs/sdk/reference/openreader-server/api/json-queries.md renamed: docs/sdk/reference/graphql-server/openreader/nested-field-queries.md -> docs/sdk/reference/openreader-server/api/nested-field-queries.md renamed: docs/sdk/reference/graphql-server/openreader/paginate-query-results.md -> docs/sdk/reference/openreader-server/api/paginate-query-results.md renamed: docs/sdk/reference/graphql-server/openreader/queries.md -> docs/sdk/reference/openreader-server/api/queries.md renamed: docs/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces.md -> docs/sdk/reference/openreader-server/api/resolve-union-types-interfaces.md renamed: docs/sdk/reference/graphql-server/openreader/sorting.md -> docs/sdk/reference/openreader-server/api/sorting.md renamed: docs/sdk/reference/graphql-server/configuration/_category_.json -> docs/sdk/reference/openreader-server/configuration/_category_.json renamed: docs/sdk/reference/graphql-server/configuration/authorization.md -> docs/sdk/reference/openreader-server/configuration/authorization.md renamed: docs/sdk/reference/graphql-server/configuration/caching.md -> docs/sdk/reference/openreader-server/configuration/caching.md renamed: docs/sdk/reference/graphql-server/configuration/custom-resolvers.md -> docs/sdk/reference/openreader-server/configuration/custom-resolvers.md renamed: docs/sdk/reference/graphql-server/configuration/dos-protection.md -> docs/sdk/reference/openreader-server/configuration/dos-protection.md renamed: docs/sdk/reference/graphql-server/configuration/subscriptions.md -> docs/sdk/reference/openreader-server/configuration/subscriptions.md renamed: docs/sdk/reference/graphql-server/overview.md -> docs/sdk/reference/openreader-server/overview.md --- .../{graphql-server => openreader-server}/_category_.json | 2 +- .../openreader => openreader-server/api}/_category_.json | 2 +- .../openreader => openreader-server/api}/and-or-filters.md | 0 .../api}/cross-relation-field-queries.md | 0 .../openreader => openreader-server/api}/intro.md | 0 .../openreader => openreader-server/api}/json-queries.md | 0 .../api}/nested-field-queries.md | 0 .../api}/paginate-query-results.md | 0 .../openreader => openreader-server/api}/queries.md | 0 .../api}/resolve-union-types-interfaces.md | 0 .../openreader => openreader-server/api}/sorting.md | 0 .../configuration/_category_.json | 2 +- .../configuration/authorization.md | 0 .../configuration/caching.md | 0 .../configuration/custom-resolvers.md | 0 .../configuration/dos-protection.md | 0 .../configuration/subscriptions.md | 0 .../reference/{graphql-server => openreader-server}/overview.md | 0 18 files changed, 3 insertions(+), 3 deletions(-) rename docs/sdk/reference/{graphql-server => openreader-server}/_category_.json (82%) rename docs/sdk/reference/{graphql-server/openreader => openreader-server/api}/_category_.json (80%) rename docs/sdk/reference/{graphql-server/openreader => openreader-server/api}/and-or-filters.md (100%) rename docs/sdk/reference/{graphql-server/openreader => openreader-server/api}/cross-relation-field-queries.md (100%) rename docs/sdk/reference/{graphql-server/openreader => openreader-server/api}/intro.md (100%) rename docs/sdk/reference/{graphql-server/openreader => openreader-server/api}/json-queries.md (100%) rename docs/sdk/reference/{graphql-server/openreader => openreader-server/api}/nested-field-queries.md (100%) rename docs/sdk/reference/{graphql-server/openreader => openreader-server/api}/paginate-query-results.md (100%) rename docs/sdk/reference/{graphql-server/openreader => openreader-server/api}/queries.md (100%) rename docs/sdk/reference/{graphql-server/openreader => openreader-server/api}/resolve-union-types-interfaces.md (100%) rename docs/sdk/reference/{graphql-server/openreader => openreader-server/api}/sorting.md (100%) rename docs/sdk/reference/{graphql-server => openreader-server}/configuration/_category_.json (78%) rename docs/sdk/reference/{graphql-server => openreader-server}/configuration/authorization.md (100%) rename docs/sdk/reference/{graphql-server => openreader-server}/configuration/caching.md (100%) rename docs/sdk/reference/{graphql-server => openreader-server}/configuration/custom-resolvers.md (100%) rename docs/sdk/reference/{graphql-server => openreader-server}/configuration/dos-protection.md (100%) rename docs/sdk/reference/{graphql-server => openreader-server}/configuration/subscriptions.md (100%) rename docs/sdk/reference/{graphql-server => openreader-server}/overview.md (100%) diff --git a/docs/sdk/reference/graphql-server/_category_.json b/docs/sdk/reference/openreader-server/_category_.json similarity index 82% rename from docs/sdk/reference/graphql-server/_category_.json rename to docs/sdk/reference/openreader-server/_category_.json index 7b140c91..4c5f68f5 100644 --- a/docs/sdk/reference/graphql-server/_category_.json +++ b/docs/sdk/reference/openreader-server/_category_.json @@ -6,7 +6,7 @@ "className": "red", "link": { "type": "generated-index", - "slug": "/sdk/reference/graphql-server", + "slug": "/sdk/reference/openreader-server", "title": "The SQD GraphQL server, built in-house" } } diff --git a/docs/sdk/reference/graphql-server/openreader/_category_.json b/docs/sdk/reference/openreader-server/api/_category_.json similarity index 80% rename from docs/sdk/reference/graphql-server/openreader/_category_.json rename to docs/sdk/reference/openreader-server/api/_category_.json index e4fed209..ce752ef0 100644 --- a/docs/sdk/reference/graphql-server/openreader/_category_.json +++ b/docs/sdk/reference/openreader-server/api/_category_.json @@ -6,7 +6,7 @@ "className": "red", "link": { "type": "generated-index", - "slug": "/sdk/reference/graphql-server/openreader", + "slug": "/sdk/reference/openreader-server/api", "title": "Core queries exposed by the SQD GraphQL server API" } } diff --git a/docs/sdk/reference/graphql-server/openreader/and-or-filters.md b/docs/sdk/reference/openreader-server/api/and-or-filters.md similarity index 100% rename from docs/sdk/reference/graphql-server/openreader/and-or-filters.md rename to docs/sdk/reference/openreader-server/api/and-or-filters.md diff --git a/docs/sdk/reference/graphql-server/openreader/cross-relation-field-queries.md b/docs/sdk/reference/openreader-server/api/cross-relation-field-queries.md similarity index 100% rename from docs/sdk/reference/graphql-server/openreader/cross-relation-field-queries.md rename to docs/sdk/reference/openreader-server/api/cross-relation-field-queries.md diff --git a/docs/sdk/reference/graphql-server/openreader/intro.md b/docs/sdk/reference/openreader-server/api/intro.md similarity index 100% rename from docs/sdk/reference/graphql-server/openreader/intro.md rename to docs/sdk/reference/openreader-server/api/intro.md diff --git a/docs/sdk/reference/graphql-server/openreader/json-queries.md b/docs/sdk/reference/openreader-server/api/json-queries.md similarity index 100% rename from docs/sdk/reference/graphql-server/openreader/json-queries.md rename to docs/sdk/reference/openreader-server/api/json-queries.md diff --git a/docs/sdk/reference/graphql-server/openreader/nested-field-queries.md b/docs/sdk/reference/openreader-server/api/nested-field-queries.md similarity index 100% rename from docs/sdk/reference/graphql-server/openreader/nested-field-queries.md rename to docs/sdk/reference/openreader-server/api/nested-field-queries.md diff --git a/docs/sdk/reference/graphql-server/openreader/paginate-query-results.md b/docs/sdk/reference/openreader-server/api/paginate-query-results.md similarity index 100% rename from docs/sdk/reference/graphql-server/openreader/paginate-query-results.md rename to docs/sdk/reference/openreader-server/api/paginate-query-results.md diff --git a/docs/sdk/reference/graphql-server/openreader/queries.md b/docs/sdk/reference/openreader-server/api/queries.md similarity index 100% rename from docs/sdk/reference/graphql-server/openreader/queries.md rename to docs/sdk/reference/openreader-server/api/queries.md diff --git a/docs/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces.md b/docs/sdk/reference/openreader-server/api/resolve-union-types-interfaces.md similarity index 100% rename from docs/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces.md rename to docs/sdk/reference/openreader-server/api/resolve-union-types-interfaces.md diff --git a/docs/sdk/reference/graphql-server/openreader/sorting.md b/docs/sdk/reference/openreader-server/api/sorting.md similarity index 100% rename from docs/sdk/reference/graphql-server/openreader/sorting.md rename to docs/sdk/reference/openreader-server/api/sorting.md diff --git a/docs/sdk/reference/graphql-server/configuration/_category_.json b/docs/sdk/reference/openreader-server/configuration/_category_.json similarity index 78% rename from docs/sdk/reference/graphql-server/configuration/_category_.json rename to docs/sdk/reference/openreader-server/configuration/_category_.json index ea4bd71a..245fa956 100644 --- a/docs/sdk/reference/graphql-server/configuration/_category_.json +++ b/docs/sdk/reference/openreader-server/configuration/_category_.json @@ -6,7 +6,7 @@ "className": "red", "link": { "type": "generated-index", - "slug": "/sdk/reference/graphql-server/configuration", + "slug": "/sdk/reference/openreader-server/configuration", "title": "Configuring and extending the server" } } diff --git a/docs/sdk/reference/graphql-server/configuration/authorization.md b/docs/sdk/reference/openreader-server/configuration/authorization.md similarity index 100% rename from docs/sdk/reference/graphql-server/configuration/authorization.md rename to docs/sdk/reference/openreader-server/configuration/authorization.md diff --git a/docs/sdk/reference/graphql-server/configuration/caching.md b/docs/sdk/reference/openreader-server/configuration/caching.md similarity index 100% rename from docs/sdk/reference/graphql-server/configuration/caching.md rename to docs/sdk/reference/openreader-server/configuration/caching.md diff --git a/docs/sdk/reference/graphql-server/configuration/custom-resolvers.md b/docs/sdk/reference/openreader-server/configuration/custom-resolvers.md similarity index 100% rename from docs/sdk/reference/graphql-server/configuration/custom-resolvers.md rename to docs/sdk/reference/openreader-server/configuration/custom-resolvers.md diff --git a/docs/sdk/reference/graphql-server/configuration/dos-protection.md b/docs/sdk/reference/openreader-server/configuration/dos-protection.md similarity index 100% rename from docs/sdk/reference/graphql-server/configuration/dos-protection.md rename to docs/sdk/reference/openreader-server/configuration/dos-protection.md diff --git a/docs/sdk/reference/graphql-server/configuration/subscriptions.md b/docs/sdk/reference/openreader-server/configuration/subscriptions.md similarity index 100% rename from docs/sdk/reference/graphql-server/configuration/subscriptions.md rename to docs/sdk/reference/openreader-server/configuration/subscriptions.md diff --git a/docs/sdk/reference/graphql-server/overview.md b/docs/sdk/reference/openreader-server/overview.md similarity index 100% rename from docs/sdk/reference/graphql-server/overview.md rename to docs/sdk/reference/openreader-server/overview.md From 3d601db11cbaaa5ca52656917169886e2f2fb478 Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Tue, 10 Sep 2024 18:40:40 +0900 Subject: [PATCH 09/16] Moving the GraphQL guide to resources root renamed: docs/sdk/resources/basics/serving-graphql-database-creds.png -> docs/sdk/resources/serving-graphql-database-creds.png renamed: docs/sdk/resources/basics/serving-graphql.md -> docs/sdk/resources/serving-graphql.md --- .../{basics => }/serving-graphql-database-creds.png | Bin docs/sdk/resources/{basics => }/serving-graphql.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename docs/sdk/resources/{basics => }/serving-graphql-database-creds.png (100%) rename docs/sdk/resources/{basics => }/serving-graphql.md (100%) diff --git a/docs/sdk/resources/basics/serving-graphql-database-creds.png b/docs/sdk/resources/serving-graphql-database-creds.png similarity index 100% rename from docs/sdk/resources/basics/serving-graphql-database-creds.png rename to docs/sdk/resources/serving-graphql-database-creds.png diff --git a/docs/sdk/resources/basics/serving-graphql.md b/docs/sdk/resources/serving-graphql.md similarity index 100% rename from docs/sdk/resources/basics/serving-graphql.md rename to docs/sdk/resources/serving-graphql.md From 24246a24365fed2c3aa5907eb5d94ea39de2e69f Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Tue, 10 Sep 2024 18:44:22 +0900 Subject: [PATCH 10/16] Updating the redirect rules for new pages modified: redirectRules.js --- redirectRules.js | 72 ++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/redirectRules.js b/redirectRules.js index cfd28ad1..9cf7ef29 100644 --- a/redirectRules.js +++ b/redirectRules.js @@ -25,7 +25,7 @@ const urlList = [ }, { "from": "/develop-a-squid/graphql-api", - "to": "/sdk/resources/basics/serving-graphql" + "to": "/sdk/resources/serving-graphql" }, { "from": "/develop-a-squid/typegen/squid-substrate-typegen", @@ -409,31 +409,31 @@ const urlList = [ }, { "from": "/graphql-api/authorization", - "to": "/sdk/reference/graphql-server/configuration/authorization" + "to": "/sdk/reference/openreader-server/configuration/authorization" }, { "from": "/graphql-api/caching", - "to": "/sdk/reference/graphql-server/configuration/caching" + "to": "/sdk/reference/openreader-server/configuration/caching" }, { "from": "/graphql-api/custom-resolvers", - "to": "/sdk/reference/graphql-server/configuration/custom-resolvers" + "to": "/sdk/reference/openreader-server/configuration/custom-resolvers" }, { "from": "/graphql-api/dos-protection", - "to": "/sdk/reference/graphql-server/configuration/dos-protection" + "to": "/sdk/reference/openreader-server/configuration/dos-protection" }, { "from": "/graphql-api/overview", - "to": "/sdk/resources/basics/serving-graphql" + "to": "/sdk/resources/serving-graphql" }, { "from": "/graphql-api/subscriptions", - "to": "/sdk/reference/graphql-server/configuration/subscriptions" + "to": "/sdk/reference/openreader-server/configuration/subscriptions" }, { "from": "/graphql-api", - "to": "/sdk/resources/basics/serving-graphql" + "to": "/sdk/resources/serving-graphql" }, { "from": "/migrate/subsquid-vs-thegraph", @@ -457,43 +457,43 @@ const urlList = [ }, { "from": "/query-squid/nested-field-queries", - "to": "/sdk/reference/graphql-server/openreader/nested-field-queries" + "to": "/sdk/reference/openreader-server/api/nested-field-queries" }, { "from": "/query-squid/sorting", - "to": "/sdk/reference/graphql-server/openreader/sorting" + "to": "/sdk/reference/openreader-server/api/sorting" }, { "from": "/query-squid/intro", - "to": "/sdk/reference/graphql-server/openreader/intro" + "to": "/sdk/reference/openreader-server/api/intro" }, { "from": "/query-squid/and-or-filters", - "to": "/sdk/reference/graphql-server/openreader/and-or-filters" + "to": "/sdk/reference/openreader-server/api/and-or-filters" }, { "from": "/query-squid/resolve-union-types-interfaces", - "to": "/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces" + "to": "/sdk/reference/openreader-server/api/resolve-union-types-interfaces" }, { "from": "/query-squid/cross-relation-field-queries", - "to": "/sdk/reference/graphql-server/openreader/cross-relation-field-queries" + "to": "/sdk/reference/openreader-server/api/cross-relation-field-queries" }, { "from": "/query-squid/json-queries", - "to": "/sdk/reference/graphql-server/openreader/json-queries" + "to": "/sdk/reference/openreader-server/api/json-queries" }, { "from": "/query-squid/queries", - "to": "/sdk/reference/graphql-server/openreader/queries" + "to": "/sdk/reference/openreader-server/api/queries" }, { "from": "/query-squid/paginate-query-results", - "to": "/sdk/reference/graphql-server/openreader/paginate-query-results" + "to": "/sdk/reference/openreader-server/api/paginate-query-results" }, { "from": "/query-squid", - "to": "/sdk/reference/graphql-server/openreader" + "to": "/sdk/reference/openreader-server/api" }, { "from": "/quickstart/quickstart-substrate", @@ -749,75 +749,75 @@ const urlList = [ }, { "from": "/sdk/resources/graphql-server/alternatives", - "to": "/sdk/resources/basics/serving-graphql" + "to": "/sdk/resources/serving-graphql" }, { "from": "/sdk/resources/graphql-server/overview", - "to": "/sdk/resources/basics/serving-graphql" + "to": "/sdk/resources/serving-graphql" }, { "from": "/sdk/resources/graphql-server", - "to": "/sdk/resources/basics/serving-graphql" + "to": "/sdk/resources/serving-graphql" }, { "from": "/sdk/resources/graphql-server/authorization", - "to": "/sdk/reference/graphql-server/configuration/authorization" + "to": "/sdk/reference/openreader-server/configuration/authorization" }, { "from": "/sdk/resources/graphql-server/caching", - "to": "/sdk/reference/graphql-server/configuration/caching" + "to": "/sdk/reference/openreader-server/configuration/caching" }, { "from": "/sdk/resources/graphql-server/custom-resolvers", - "to": "/sdk/reference/graphql-server/configuration/custom-resolvers" + "to": "/sdk/reference/openreader-server/configuration/custom-resolvers" }, { "from": "/sdk/resources/graphql-server/dos-protection", - "to": "/sdk/reference/graphql-server/configuration/dos-protection" + "to": "/sdk/reference/openreader-server/configuration/dos-protection" }, { "from": "/sdk/resources/graphql-server/subscriptions", - "to": "/sdk/reference/graphql-server/configuration/subscriptions" + "to": "/sdk/reference/openreader-server/configuration/subscriptions" }, { "from": "/sdk/reference/openreader", - "to": "/sdk/reference/graphql-server/openreader" + "to": "/sdk/reference/openreader-server/api" }, { "from": "/sdk/reference/openreader/intro", - "to": "/sdk/reference/graphql-server/openreader/intro" + "to": "/sdk/reference/openreader-server/api/intro" }, { "from": "/sdk/reference/openreader/and-or-filters", - "to": "/sdk/reference/graphql-server/openreader/and-or-filters" + "to": "/sdk/reference/openreader-server/api/and-or-filters" }, { "from": "/sdk/reference/openreader/cross-relation-field-queries", - "to": "/sdk/reference/graphql-server/openreader/cross-relation-field-queries" + "to": "/sdk/reference/openreader-server/api/cross-relation-field-queries" }, { "from": "/sdk/reference/openreader/json-queries", - "to": "/sdk/reference/graphql-server/openreader/json-queries" + "to": "/sdk/reference/openreader-server/api/json-queries" }, { "from": "/sdk/reference/openreader/nested-field-queries", - "to": "/sdk/reference/graphql-server/openreader/nested-field-queries" + "to": "/sdk/reference/openreader-server/api/nested-field-queries" }, { "from": "/sdk/reference/openreader/paginate-query-results", - "to": "/sdk/reference/graphql-server/openreader/paginate-query-results" + "to": "/sdk/reference/openreader-server/api/paginate-query-results" }, { "from": "/sdk/reference/openreader/queries", - "to": "/sdk/reference/graphql-server/openreader/queries" + "to": "/sdk/reference/openreader-server/api/queries" }, { "from": "/sdk/reference/openreader/resolve-union-types-interfaces", - "to": "/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces" + "to": "/sdk/reference/openreader-server/api/resolve-union-types-interfaces" }, { "from": "/sdk/reference/openreader/sorting", - "to": "/sdk/reference/graphql-server/openreader/sorting" + "to": "/sdk/reference/openreader-server/api/sorting" } ] From 51da7c0db6bb37c9a48026d7c3c96b0d74b7d58c Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Tue, 10 Sep 2024 18:53:38 +0900 Subject: [PATCH 11/16] Moving the "Basics" guides to the resources root deleted: docs/sdk/resources/basics/_category_.json renamed: docs/sdk/resources/basics/batch-processing.md -> docs/sdk/resources/batch-processing.md modified: docs/sdk/resources/evm/_category_.json renamed: docs/sdk/resources/basics/external-api.md -> docs/sdk/resources/external-api.md modified: docs/sdk/resources/migrate/_category_.json renamed: docs/sdk/resources/basics/multichain.md -> docs/sdk/resources/multichain.md modified: docs/sdk/resources/persisting-data/_category_.json renamed: docs/sdk/resources/basics/self-hosting.md -> docs/sdk/resources/self-hosting.md modified: docs/sdk/resources/substrate/_category_.json modified: docs/sdk/resources/tools/_category_.json renamed: docs/sdk/resources/basics/unfinalized-blocks.mdx -> docs/sdk/resources/unfinalized-blocks.mdx --- docs/sdk/resources/basics/_category_.json | 12 ------------ docs/sdk/resources/{basics => }/batch-processing.md | 0 docs/sdk/resources/evm/_category_.json | 2 +- docs/sdk/resources/{basics => }/external-api.md | 0 docs/sdk/resources/migrate/_category_.json | 2 +- docs/sdk/resources/{basics => }/multichain.md | 0 docs/sdk/resources/persisting-data/_category_.json | 2 +- docs/sdk/resources/{basics => }/self-hosting.md | 0 docs/sdk/resources/substrate/_category_.json | 2 +- docs/sdk/resources/tools/_category_.json | 2 +- .../resources/{basics => }/unfinalized-blocks.mdx | 0 11 files changed, 5 insertions(+), 17 deletions(-) delete mode 100644 docs/sdk/resources/basics/_category_.json rename docs/sdk/resources/{basics => }/batch-processing.md (100%) rename docs/sdk/resources/{basics => }/external-api.md (100%) rename docs/sdk/resources/{basics => }/multichain.md (100%) rename docs/sdk/resources/{basics => }/self-hosting.md (100%) rename docs/sdk/resources/{basics => }/unfinalized-blocks.mdx (100%) diff --git a/docs/sdk/resources/basics/_category_.json b/docs/sdk/resources/basics/_category_.json deleted file mode 100644 index 0fe18207..00000000 --- a/docs/sdk/resources/basics/_category_.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "position": 9, - "label": "Basics", - "collapsible": true, - "collapsed": true, - "className": "red", - "link": { - "type": "generated-index", - "slug": "/sdk/resources/basics", - "title": "Basics of Squid SDK" - } -} diff --git a/docs/sdk/resources/basics/batch-processing.md b/docs/sdk/resources/batch-processing.md similarity index 100% rename from docs/sdk/resources/basics/batch-processing.md rename to docs/sdk/resources/batch-processing.md diff --git a/docs/sdk/resources/evm/_category_.json b/docs/sdk/resources/evm/_category_.json index 54c3174f..bad29ad4 100644 --- a/docs/sdk/resources/evm/_category_.json +++ b/docs/sdk/resources/evm/_category_.json @@ -1,5 +1,5 @@ { - "position": 30, + "position": 110, "label": "EVM-specific", "collapsible": true, "collapsed": true, diff --git a/docs/sdk/resources/basics/external-api.md b/docs/sdk/resources/external-api.md similarity index 100% rename from docs/sdk/resources/basics/external-api.md rename to docs/sdk/resources/external-api.md diff --git a/docs/sdk/resources/migrate/_category_.json b/docs/sdk/resources/migrate/_category_.json index f0706d59..a18b92c5 100644 --- a/docs/sdk/resources/migrate/_category_.json +++ b/docs/sdk/resources/migrate/_category_.json @@ -1,5 +1,5 @@ { - "position": 50, + "position": 140, "label": "Migration guides", "collapsible": true, "collapsed": true, diff --git a/docs/sdk/resources/basics/multichain.md b/docs/sdk/resources/multichain.md similarity index 100% rename from docs/sdk/resources/basics/multichain.md rename to docs/sdk/resources/multichain.md diff --git a/docs/sdk/resources/persisting-data/_category_.json b/docs/sdk/resources/persisting-data/_category_.json index ce7b1389..87714615 100644 --- a/docs/sdk/resources/persisting-data/_category_.json +++ b/docs/sdk/resources/persisting-data/_category_.json @@ -1,5 +1,5 @@ { - "position": 10, + "position": 100, "label": "Persisting data", "collapsible": true, "collapsed": true, diff --git a/docs/sdk/resources/basics/self-hosting.md b/docs/sdk/resources/self-hosting.md similarity index 100% rename from docs/sdk/resources/basics/self-hosting.md rename to docs/sdk/resources/self-hosting.md diff --git a/docs/sdk/resources/substrate/_category_.json b/docs/sdk/resources/substrate/_category_.json index bdd18e8a..cd56972e 100644 --- a/docs/sdk/resources/substrate/_category_.json +++ b/docs/sdk/resources/substrate/_category_.json @@ -1,5 +1,5 @@ { - "position": 31, + "position": 120, "label": "Substrate-specific", "collapsible": true, "collapsed": true, diff --git a/docs/sdk/resources/tools/_category_.json b/docs/sdk/resources/tools/_category_.json index e0774d18..4e4387dc 100644 --- a/docs/sdk/resources/tools/_category_.json +++ b/docs/sdk/resources/tools/_category_.json @@ -1,5 +1,5 @@ { - "position": 40, + "position": 130, "label": "Tools", "collapsible": true, "collapsed": true, diff --git a/docs/sdk/resources/basics/unfinalized-blocks.mdx b/docs/sdk/resources/unfinalized-blocks.mdx similarity index 100% rename from docs/sdk/resources/basics/unfinalized-blocks.mdx rename to docs/sdk/resources/unfinalized-blocks.mdx From 6179f9b4f08c723c62c360f201b05d257fe55310 Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Tue, 10 Sep 2024 18:57:08 +0900 Subject: [PATCH 12/16] Updating the redirect rules for the "Basics" pages modified: redirectRules.js --- redirectRules.js | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/redirectRules.js b/redirectRules.js index 9cf7ef29..29f872ed 100644 --- a/redirectRules.js +++ b/redirectRules.js @@ -97,11 +97,11 @@ const urlList = [ }, { "from": "/run-squid/run-in-docker", - "to": "/sdk/resources/basics/self-hosting" + "to": "/sdk/resources/self-hosting" }, { "from": "/run-squid/run-in-production", - "to": "/sdk/resources/basics/self-hosting" + "to": "/sdk/resources/self-hosting" }, { "from": "/basics/store/typeorm-store", @@ -221,15 +221,15 @@ const urlList = [ }, { "from": "/basics/batch-processing", - "to": "/sdk/resources/basics/batch-processing" + "to": "/sdk/resources/batch-processing" }, { "from": "/basics/external-api", - "to": "/sdk/resources/basics/external-api" + "to": "/sdk/resources/external-api" }, { "from": "/basics/multichain", - "to": "/sdk/resources/basics/multichain" + "to": "/sdk/resources/multichain" }, { "from": "/basics/logging", @@ -253,7 +253,7 @@ const urlList = [ }, { "from": "/basics/unfinalized-blocks", - "to": "/sdk/resources/basics/unfinalized-blocks" + "to": "/sdk/resources/unfinalized-blocks" }, { "from": "/deploy-squid/best-practices", @@ -309,7 +309,7 @@ const urlList = [ }, { "from": "/deploy-squid/self-hosting", - "to": "/sdk/resources/basics/self-hosting" + "to": "/sdk/resources/self-hosting" }, { "from": "/deploy-squid/troubleshooting", @@ -818,6 +818,34 @@ const urlList = [ { "from": "/sdk/reference/openreader/sorting", "to": "/sdk/reference/openreader-server/api/sorting" + }, + { + "from": "/sdk/resources/basics", + "to": "/sdk/resources" + }, + { + "from": "/sdk/resources/basics/serving-graphql", + "to": "/sdk/resources/serving-graphql" + }, + { + "from": "/sdk/resources/basics/batch-processing", + "to": "/sdk/resources/batch-processing" + }, + { + "from": "/sdk/resources/basics/external-api", + "to": "/sdk/resources/external-api" + }, + { + "from": "/sdk/resources/basics/multichain", + "to": "/sdk/resources/multichain" + }, + { + "from": "/sdk/resources/basics/self-hosting", + "to": "/sdk/resources/self-hosting" + }, + { + "from": "/sdk/resources/basics/unfinalized-blocks", + "to": "/sdk/resources/unfinalized-blocks" } ] From bcf11b0e01c2b75fe5a43e311878a0f31d716b3b Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Tue, 10 Sep 2024 20:33:55 +0900 Subject: [PATCH 13/16] Updating the links modified: docs/cloud/reference/manifest.mdx modified: docs/cloud/resources/best-practices.md modified: docs/cloud/resources/monitoring.md modified: docs/cloud/troubleshooting.md modified: docs/external-tools.md modified: docs/glossary.md modified: docs/overview.mdx modified: docs/sdk/faq.md modified: docs/sdk/how-to-start/layout.md modified: docs/sdk/how-to-start/squid-development.mdx modified: docs/sdk/overview.mdx modified: docs/sdk/reference/openreader-server/api/and-or-filters.md modified: docs/sdk/reference/openreader-server/api/cross-relation-field-queries.md modified: docs/sdk/reference/openreader-server/api/intro.md modified: docs/sdk/reference/openreader-server/api/nested-field-queries.md modified: docs/sdk/reference/openreader-server/api/paginate-query-results.md modified: docs/sdk/reference/openreader-server/api/queries.md modified: docs/sdk/reference/openreader-server/configuration/authorization.md modified: docs/sdk/reference/openreader-server/configuration/dos-protection.md modified: docs/sdk/reference/openreader-server/configuration/subscriptions.md modified: docs/sdk/reference/openreader-server/overview.md modified: docs/sdk/reference/processors/evm-batch/context-interfaces.md modified: docs/sdk/reference/processors/evm-batch/general.md modified: docs/sdk/reference/processors/evm-batch/state-diffs.md modified: docs/sdk/reference/processors/evm-batch/traces.md modified: docs/sdk/reference/processors/substrate-batch/context-interfaces.md modified: docs/sdk/reference/processors/substrate-batch/general.md modified: docs/sdk/reference/schema-file/entity-relations.md modified: docs/sdk/reference/schema-file/interfaces.md modified: docs/sdk/reference/schema-file/intro.md modified: docs/sdk/resources/migrate/migrate-subgraph.md modified: docs/sdk/resources/multichain.md modified: docs/sdk/resources/serving-graphql.md modified: docs/sdk/troubleshooting.mdx modified: docs/sdk/tutorials/bayc/step-four-optimizations.md modified: docs/sdk/tutorials/bayc/step-one-indexing-transfers.md modified: docs/sdk/tutorials/bayc/step-three-adding-external-data.md modified: docs/sdk/tutorials/bayc/step-two-deriving-owners-and-tokens.md modified: docs/sdk/tutorials/frontier-evm.md modified: docs/sdk/tutorials/ink.md modified: docs/sdk/tutorials/substrate.md modified: docs/solana-indexing/sdk/solana-batch/context-interfaces.md modified: docs/solana-indexing/sdk/solana-batch/general.md modified: docs/squid-cli/run.md --- docs/cloud/reference/manifest.mdx | 2 +- docs/cloud/resources/best-practices.md | 10 ++++----- docs/cloud/resources/monitoring.md | 2 +- docs/cloud/troubleshooting.md | 2 +- docs/external-tools.md | 2 +- docs/glossary.md | 8 +++---- docs/overview.mdx | 6 ++--- docs/sdk/faq.md | 6 ++--- docs/sdk/how-to-start/layout.md | 2 +- docs/sdk/how-to-start/squid-development.mdx | 22 +++++++++---------- docs/sdk/overview.mdx | 6 ++--- .../openreader-server/api/and-or-filters.md | 4 ++-- .../api/cross-relation-field-queries.md | 2 +- .../reference/openreader-server/api/intro.md | 6 ++--- .../api/nested-field-queries.md | 2 +- .../api/paginate-query-results.md | 2 +- .../openreader-server/api/queries.md | 2 +- .../configuration/authorization.md | 4 ++-- .../configuration/dos-protection.md | 2 +- .../configuration/subscriptions.md | 2 +- .../reference/openreader-server/overview.md | 14 ++++++------ .../evm-batch/context-interfaces.md | 2 +- .../reference/processors/evm-batch/general.md | 6 ++--- .../processors/evm-batch/state-diffs.md | 2 +- .../reference/processors/evm-batch/traces.md | 2 +- .../substrate-batch/context-interfaces.md | 2 +- .../processors/substrate-batch/general.md | 6 ++--- .../reference/schema-file/entity-relations.md | 2 +- docs/sdk/reference/schema-file/interfaces.md | 4 ++-- docs/sdk/reference/schema-file/intro.md | 2 +- .../sdk/resources/migrate/migrate-subgraph.md | 6 ++--- docs/sdk/resources/multichain.md | 6 ++--- docs/sdk/resources/serving-graphql.md | 6 ++--- docs/sdk/troubleshooting.mdx | 4 ++-- .../tutorials/bayc/step-four-optimizations.md | 2 +- .../bayc/step-one-indexing-transfers.md | 2 +- .../bayc/step-three-adding-external-data.md | 4 ++-- .../step-two-deriving-owners-and-tokens.md | 2 +- docs/sdk/tutorials/frontier-evm.md | 2 +- docs/sdk/tutorials/ink.md | 2 +- docs/sdk/tutorials/substrate.md | 4 ++-- .../sdk/solana-batch/context-interfaces.md | 2 +- .../sdk/solana-batch/general.md | 2 +- docs/squid-cli/run.md | 2 +- 44 files changed, 91 insertions(+), 91 deletions(-) diff --git a/docs/cloud/reference/manifest.mdx b/docs/cloud/reference/manifest.mdx index 92793e05..5b00e776 100644 --- a/docs/cloud/reference/manifest.mdx +++ b/docs/cloud/reference/manifest.mdx @@ -50,7 +50,7 @@ For a successful build the following files and folders **must** be present in th The `db` and `assets` folders are added to the build context if present in the squid folder. See [Project structure](/sdk/how-to-start/layout) for more info. Under the hood, Cloud builds a Docker image and runs a docker container for each service (`api`, `processor`, `migrate`) using the same image. -See [Self-hosting](/sdk/resources/basics/self-hosting) for instructions on how to build and run the Docker image locally. +See [Self-hosting](/sdk/resources/self-hosting) for instructions on how to build and run the Docker image locally. Even though the squid services (`api`, `processor`, `migrate`) use the same single container image, the exec command is different and can is defined by the `deploy:` section as explained below. ### `cmd:` diff --git a/docs/cloud/resources/best-practices.md b/docs/cloud/resources/best-practices.md index 8c65236c..cf9eba8a 100644 --- a/docs/cloud/resources/best-practices.md +++ b/docs/cloud/resources/best-practices.md @@ -8,7 +8,7 @@ description: Checklist for going to production Here is a list of items to check out before you deploy your squid for use in production: -* Make sure that you use [batch processing](/sdk/resources/basics/batch-processing) throughout your code. Consider using [`@belopash/typeorm-store`](/external-tools/#belopashtypeorm-store) for large projects with extensive [entity relations](/sdk/reference/schema-file/entity-relations) and frequent [database reads](/sdk/reference/store/typeorm/#typeorm-methods). +* Make sure that you use [batch processing](/sdk/resources/batch-processing) throughout your code. Consider using [`@belopash/typeorm-store`](/external-tools/#belopashtypeorm-store) for large projects with extensive [entity relations](/sdk/reference/schema-file/entity-relations) and frequent [database reads](/sdk/reference/store/typeorm/#typeorm-methods). * Filter your data in the batch handler. E.g. if you [request event logs](/sdk/reference/processors/evm-batch/logs) from a particular contract, do check that the `address` field of the returned data items matches the contract address before processing the data. This will make sure that any future changes in your processor configuration will not cause the newly added data to be routed to your old processing code by mistake. @@ -18,11 +18,11 @@ Batch handler data filtering used to be compulsory before the release of `@subsq * If your squid [saves its data to a database](/sdk/resources/persisting-data/typeorm), make sure your [schema](/sdk/reference/schema-file) has [`@index` decorators](/sdk/reference/schema-file/indexes-and-constraints) for all entities that will be looked up frequently. -* If your squid serves a [GraphQL API](/sdk/resources/basics/serving-graphql) - 1. Do not use the [SQD GraphQL server](/sdk/resources/basics/serving-graphql/#the-sqd-graphql-server) if your application uses subscriptions. Instead, use [PostGraphile](/sdk/resources/basics/serving-graphql/#postgraphile) or [Hasura](/sdk/resources/basics/serving-graphql/#hasura). +* If your squid serves a [GraphQL API](/sdk/resources/serving-graphql) + 1. Do not use the [SQD GraphQL server](/sdk/resources/serving-graphql/#the-sqd-graphql-server) if your application uses subscriptions. Instead, use [PostGraphile](/sdk/resources/serving-graphql/#postgraphile) or [Hasura](/sdk/resources/serving-graphql/#hasura). 2. If you do use the SQD GraphQL server: - - configure the built-in [DoS protection](/sdk/reference/graphql-server/configuration/dos-protection) against heavy queries; - - configure [caching](/sdk/reference/graphql-server/configuration/caching). + - configure the built-in [DoS protection](/sdk/reference/openreader-server/configuration/dos-protection) against heavy queries; + - configure [caching](/sdk/reference/openreader-server/configuration/caching). * If you deploy your squid to Subsquid Cloud: 1. Deploy your squid to a [Professional organization](/cloud/resources/organizations/#professional-organizations). diff --git a/docs/cloud/resources/monitoring.md b/docs/cloud/resources/monitoring.md index fc86326f..e84c6660 100644 --- a/docs/cloud/resources/monitoring.md +++ b/docs/cloud/resources/monitoring.md @@ -16,7 +16,7 @@ The processor metrics are available at `https://${org}.subsquid.io/${squid_name} The metrics are documented inline. They include some values reflecting the squid health: - `sqd_processor_last_block`. The last processed block. -- `sqd_processor_chain_height`. Current chain height as reported by the RPC endpoint (when [RPC ingestion](/sdk/resources/basics/unfinalized-blocks) is enabled) or by [Subsquid Network](/subsquid-network) (when it is disabled). +- `sqd_processor_chain_height`. Current chain height as reported by the RPC endpoint (when [RPC ingestion](/sdk/resources/unfinalized-blocks) is enabled) or by [Subsquid Network](/subsquid-network) (when it is disabled). Inspect the metrics endpoint for a full list. diff --git a/docs/cloud/troubleshooting.md b/docs/cloud/troubleshooting.md index ee9b5e7c..7a2e3a22 100644 --- a/docs/cloud/troubleshooting.md +++ b/docs/cloud/troubleshooting.md @@ -22,7 +22,7 @@ npm update -g @subsquid/cli npm run update ``` - Check that the squid adheres to the expected [structure](/sdk/how-to-start/layout) -- Make sure you can [build and run Docker images locally](/sdk/resources/basics/self-hosting) +- Make sure you can [build and run Docker images locally](/sdk/resources/self-hosting) ### `Validation error` when releasing a squid diff --git a/docs/external-tools.md b/docs/external-tools.md index fc89a0cb..b5a414dc 100644 --- a/docs/external-tools.md +++ b/docs/external-tools.md @@ -9,7 +9,7 @@ sidebar_position: 90 ## `@belopash/typeorm-store` -[`@belopash/typeorm-store`](https://github.com/belopash/squid-typeorm-store) is a [fork](/sdk/resources/persisting-data/overview/#custom-database) of [`@subsquid/typeorm-store`](/sdk/reference/store/typeorm) that automates collecting read and write database requests into [batches](/sdk/resources/basics/batch-processing) and caches the available entity records in RAM. Unlike the [standard `typeorm-store`](/sdk/resources/persisting-data/typeorm), @belopash's store is intended to be used with declarative code: it makes it easy to write mapping functions (e.g. event handlers) that explicitly define +[`@belopash/typeorm-store`](https://github.com/belopash/squid-typeorm-store) is a [fork](/sdk/resources/persisting-data/overview/#custom-database) of [`@subsquid/typeorm-store`](/sdk/reference/store/typeorm) that automates collecting read and write database requests into [batches](/sdk/resources/batch-processing) and caches the available entity records in RAM. Unlike the [standard `typeorm-store`](/sdk/resources/persisting-data/typeorm), @belopash's store is intended to be used with declarative code: it makes it easy to write mapping functions (e.g. event handlers) that explicitly define - what data you're going to need from the database - what code has to be executed once the data is available diff --git a/docs/glossary.md b/docs/glossary.md index 29e802aa..68df9c49 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -70,14 +70,14 @@ An SDK (software development kit) and a smart-contract language for developing W ### OpenReader -The GraphQL schema generation library at the heart of the open-source [SQD GraphQL server](/sdk/reference/graphql-server). +The GraphQL schema generation library at the heart of the open-source [SQD GraphQL server](/sdk/reference/openreader-server). * [GitHub repo](https://github.com/subsquid/squid-sdk/tree/master/graphql/openreader) -* [Server documentation](/sdk/reference/graphql-server/overview) +* [Server documentation](/sdk/reference/openreader-server/overview) * [Schema dialect reference](/sdk/reference/schema-file) -* [GraphQL API reference](/sdk/reference/graphql-server/openreader) +* [GraphQL API reference](/sdk/reference/openreader-server/api) -See [Serving GraphQL](/sdk/resources/basics/serving-graphql) to learn more. +See [Serving GraphQL](/sdk/resources/serving-graphql) to learn more. ### Pallet diff --git a/docs/overview.mdx b/docs/overview.mdx index 6ec94feb..5ccee7db 100644 --- a/docs/overview.mdx +++ b/docs/overview.mdx @@ -51,8 +51,8 @@ For real-time use cases such as app-specific APIs use [Squid SDK](/sdk): it'll u - [High-level libraries](/sdk/reference/processors) for extracting and filtering the Subsquid Network data in what can be though of as Extract-Transform-Load (ETL) pipelines - [Ergonomic tools](/sdk/resources/tools/typegen) for decoding and normalizing raw data and efficiently accessing [network state](/sdk/resources/tools/typegen/state-queries) - Pluggable [data sinks](/sdk/reference/store) to save data into Postgres, files (local or s3) or BigQuery -- An expressive [GraphQL server](/sdk/resources/basics/serving-graphql#the-sqd-graphql-server) with a schema-based [config](/sdk/reference/schema-file) -- Seamless handling of [unfinalized blocks and chain reorganizations](/sdk/resources/basics/unfinalized-blocks) for real-time data ingestion +- An expressive [GraphQL server](/sdk/resources/serving-graphql#the-sqd-graphql-server) with a schema-based [config](/sdk/reference/schema-file) +- Seamless handling of [unfinalized blocks and chain reorganizations](/sdk/resources/unfinalized-blocks) for real-time data ingestion - rapid data extraction and decoding [for local analytics](/sdk/tutorials/file-csv) The SDK is a go-to choice for production solutions and prototypes of @@ -81,7 +81,7 @@ A Platform-as-a-Service for deploying Squid SDK indexers, featuring - Learn about [squid components](/sdk/overview), [combining them](/sdk/how-to-start/squid-from-scratch) or follow the [end-to-end development guide](/sdk/how-to-start/squid-development) - Explore [tutorials](/sdk/tutorials) or [examples](/sdk/examples) - Learn how to [migrate from The Graph](/sdk/resources/migrate/migrate-subgraph) -- Explore the [GraphQL server options](/sdk/resources/basics/serving-graphql) +- Explore the [GraphQL server options](/sdk/resources/serving-graphql) ```mdx-code-block diff --git a/docs/sdk/faq.md b/docs/sdk/faq.md index 45790e45..342cf347 100644 --- a/docs/sdk/faq.md +++ b/docs/sdk/faq.md @@ -16,7 +16,7 @@ Here is an incomplete list: ### How does Squid SDK handle unfinalized blocks? -The Subsquid Network only serves finalized blocks and is typically ~1000 blocks behind the tip. The most recent blocks, as well as the unfinalized blocks are seamlessly handled by the SDK from a complementary RPC data source, set by the `chain` config. Potential chain reorgs are automatically handled under the hood. See [Indexing unfinalized blocks](/sdk/resources/basics/unfinalized-blocks) for details. +The Subsquid Network only serves finalized blocks and is typically ~1000 blocks behind the tip. The most recent blocks, as well as the unfinalized blocks are seamlessly handled by the SDK from a complementary RPC data source, set by the `chain` config. Potential chain reorgs are automatically handled under the hood. See [Indexing unfinalized blocks](/sdk/resources/unfinalized-blocks) for details. ### What is the latency for the data served by the squid? @@ -24,11 +24,11 @@ Since the ArrowSquid release, the Squid SDK has the option to ingest unfinalized ### How do I enable GraphQL subscriptions for local runs? -Add `--subscription` flag to the `serve` command defined in `commands.json`. See [Subscriptions](/sdk/reference/graphql-server/configuration/subscriptions) for details. +Add `--subscription` flag to the `serve` command defined in `commands.json`. See [Subscriptions](/sdk/reference/openreader-server/configuration/subscriptions) for details. ### How do squids keep track of their sync progress? -Depends on the data sink used. Squid processors that use [`TypeormDatabase`](/sdk/resources/persisting-data/typeorm) keep their state in a [schema](https://www.postgresql.org/docs/current/sql-createschema.html), not in a table. By default the schema is called `squid_processor` (name must be overridden in [multiprocessor squids](/sdk/resources/basics/multichain)). You can view it with +Depends on the data sink used. Squid processors that use [`TypeormDatabase`](/sdk/resources/persisting-data/typeorm) keep their state in a [schema](https://www.postgresql.org/docs/current/sql-createschema.html), not in a table. By default the schema is called `squid_processor` (name must be overridden in [multiprocessor squids](/sdk/resources/multichain)). You can view it with ```sql select * from squid_processor.status; ``` diff --git a/docs/sdk/how-to-start/layout.md b/docs/sdk/how-to-start/layout.md index 1f58a7b2..0927c116 100644 --- a/docs/sdk/how-to-start/layout.md +++ b/docs/sdk/how-to-start/layout.md @@ -19,7 +19,7 @@ All files and folders except `package.json` are optional. + `/src/processor.ts` -- Processor object ([EVM](/sdk/reference/processors/evm-batch) or [Substrate](/sdk/reference/processors/substrate-batch)) definition and configuration. + `/src/model/generated` -- The folder for the TypeORM entities generated from `schema.graphql`. + `/src/model` -- The module exporting the entity classes. - + `/src/server-extension/resolvers` -- A folder for [user-defined GraphQL resolvers](/sdk/reference/graphql-server/configuration/custom-resolvers) used by the [SQD GraphQL server](/sdk/reference/graphql-server). + + `/src/server-extension/resolvers` -- A folder for [user-defined GraphQL resolvers](/sdk/reference/openreader-server/configuration/custom-resolvers) used by the [SQD GraphQL server](/sdk/reference/openreader-server). + `/src/types` -- A folder for types generated by the Substrate [typegen](/sdk/resources/tools/typegen/) tool for use in data decoding. + `/src/abi` -- A folder for modules generated by the EVM [typegen](/sdk/resources/tools/typegen/) tool containing type definitions and data decoding boilerplate code. - `/db` -- The designated folder with the [database migrations](/sdk/resources/persisting-data/typeorm). diff --git a/docs/sdk/how-to-start/squid-development.mdx b/docs/sdk/how-to-start/squid-development.mdx index abc38f4e..0f6a917a 100644 --- a/docs/sdk/how-to-start/squid-development.mdx +++ b/docs/sdk/how-to-start/squid-development.mdx @@ -27,7 +27,7 @@ See also the [Environment set up](/sdk/how-to-start/development-environment-set- Consider your business requirements and find out 1. How the data should be delivered. Options: - - [PostgreSQL](/sdk/resources/persisting-data/typeorm) with an optional [GraphQL API](/sdk/resources/basics/serving-graphql) - can be real-time + - [PostgreSQL](/sdk/resources/persisting-data/typeorm) with an optional [GraphQL API](/sdk/resources/serving-graphql) - can be real-time - [file-based dataset](/sdk/resources/persisting-data/file) - local or on S3 - [Google BigQuery](/sdk/resources/persisting-data/bigquery/) 2. What data should be delivered @@ -35,9 +35,9 @@ Consider your business requirements and find out - Ethereum Virtual Machine (EVM) chains like [Ethereum](https://ethereum.org) - [supported networks](/subsquid-network/reference/evm-networks) - [Substrate](https://substrate.io)-powered chains like [Polkadot](https://polkadot.network) and [Kusama](https://kusama.network) - [supported networks](/subsquid-network/reference/substrate-networks) - Note that you can use Subsquid via [RPC ingestion](/sdk/resources/basics/unfinalized-blocks) even if your network is not listed. + Note that you can use Subsquid via [RPC ingestion](/sdk/resources/unfinalized-blocks) even if your network is not listed. 4. What exact data should be retrieved from blockchain(s) -5. Whether you need to mix in any [off-chain data](/sdk/resources/basics/external-api) +5. Whether you need to mix in any [off-chain data](/sdk/resources/external-api) #### Example requirements @@ -103,7 +103,7 @@ Although it is possible to [compose a squid from individual packages](/sdk/how-t ```bash sqd init my-squid-name -t gravatar ``` -- A template showing how to [combine data from multiple chains](/sdk/resources/basics/multichain). Indexes USDC transfers on Ethereum and Binance. +- A template showing how to [combine data from multiple chains](/sdk/resources/multichain). Indexes USDC transfers on Ethereum and Binance. ```bash sqd init my-squid-name -t multichain ``` @@ -323,7 +323,7 @@ Edit the definition of `const processor` to 1. Use a data source appropriate for your chain and task. - It is possible to [use RPC](/sdk/reference/processors/evm-batch/general/#set-rpc-endpoint) as the only data source, but [adding](/sdk/reference/processors/evm-batch/general/#set-gateway) a [Subsquid Network](/subsquid-network/reference/evm-networks) data source will make your squid sync much faster. - RPC is a hard requirement if you're building a real-time API. - - If you're using RPC as one of your data sources, make sure to [set the number of finality confirmations](/sdk/reference/processors/evm-batch/general/#set-finality-confirmation) so that [hot blocks ingestion](/sdk/resources/basics/unfinalized-blocks) works properly. + - If you're using RPC as one of your data sources, make sure to [set the number of finality confirmations](/sdk/reference/processors/evm-batch/general/#set-finality-confirmation) so that [hot blocks ingestion](/sdk/resources/unfinalized-blocks) works properly. 2. Request all [event logs](/sdk/reference/processors/evm-batch/logs/), [transactions](/sdk/reference/processors/evm-batch/transactions/), [execution traces](/sdk/reference/processors/evm-batch/traces) and [state diffs](/sdk/reference/processors/evm-batch/state-diffs/) that your task requires, with any necessary related data (e.g. parent transactions for event logs). 3. [Select all data fields](/sdk/reference/processors/evm-batch/field-selection) necessary for your task (e.g. `gasUsed` for transactions). @@ -451,7 +451,7 @@ You can also decode the data of certain pallet-specific events and transactions ### (Optional) IV. Mix in external data and chain state calls output {#external-data} -If you need external (i.e. non-blockchain) data in your transformation, take a look at the [External APIs and IPFS](/sdk/resources/basics/external-api) page. +If you need external (i.e. non-blockchain) data in your transformation, take a look at the [External APIs and IPFS](/sdk/resources/external-api) page. If any of the on-chain data you need is unavalable from the processor or incovenient to retrieve with it, you have an option to get it via [direct chain queries](/sdk/resources/tools/typegen/state-queries). @@ -464,7 +464,7 @@ At `src/main.ts`, change the [`Database`](/sdk/resources/persisting-data/overvie ``` -1. Define the schema of the database (and the [core schema of the GraphQL API](/sdk/reference/graphql-server/openreader) if it is used) at [`schema.graphql`](/sdk/reference/schema-file). +1. Define the schema of the database (and the [core schema of the GraphQL API](/sdk/reference/openreader-server/api) if it is used) at [`schema.graphql`](/sdk/reference/schema-file). 2. Regenerate the TypeORM model classes with ```bash @@ -587,7 +587,7 @@ It will often make sense to keep the entity instances in maps rather than arrays If you perform any [database lookups](/sdk/reference/store/typeorm/#typeorm-methods), try to do so in batches and make sure that the entity fields that you're searching over are [indexed](/sdk/reference/schema-file/indexes-and-constraints). -See also the [patterns](/sdk/resources/basics/batch-processing/#patterns) and [anti-pattens](/sdk/resources/basics/batch-processing/#anti-patterns) sections of the Batch processing guide. +See also the [patterns](/sdk/resources/batch-processing/#patterns) and [anti-pattens](/sdk/resources/batch-processing/#anti-patterns) sections of the Batch processing guide. ```mdx-code-block @@ -628,7 +628,7 @@ The alternative is to do the same steps in a different order: ## Scaling up -If you're developing a large squid, make sure to use [batch processing](/sdk/resources/basics/batch-processing) throughout your code. +If you're developing a large squid, make sure to use [batch processing](/sdk/resources/batch-processing) throughout your code. A common mistake is to make handlers for individual event logs or transactions; for updates that require data retrieval that results in lots of small database lookups and ultimately in poor syncing performance. Collect all the relevant data and process it at once. A simple architecture of that type is discussed in the [BAYC tutorial](/sdk/tutorials/bayc). @@ -640,5 +640,5 @@ For complete examples of complex squids take a look at the [Giant Squid Explorer ## Next steps -* Deploy your squid [on own infrastructure](/sdk/resources/basics/self-hosting) or to [Subsquid Cloud](/cloud) -* If your squid serves a [SQD GraphQL server](/sdk/reference/graphql-server/)-compatible API, consult the [core GraphQL API reference](/sdk/reference/graphql-server/openreader) while writing your frontend application. +* Deploy your squid [on own infrastructure](/sdk/resources/self-hosting) or to [Subsquid Cloud](/cloud) +* If your squid serves a [SQD GraphQL server](/sdk/reference/openreader-server/)-compatible API, consult the [core GraphQL API reference](/sdk/reference/openreader-server/api) while writing your frontend application. diff --git a/docs/sdk/overview.mdx b/docs/sdk/overview.mdx index 41513324..92347367 100644 --- a/docs/sdk/overview.mdx +++ b/docs/sdk/overview.mdx @@ -10,7 +10,7 @@ import TabItem from '@theme/TabItem'; # Overview A _squid_ is an indexing project built with [Squid SDK](https://github.com/subsquid/squid-sdk) to retrieve and process blockchain data from the [Subsquid Network](/subsquid-network/overview) -(either permissioned or decentralized instance). The Squid SDK is a set of open source Typescript libraries that retrieve, decode, transform and persist the data. It can also make the transformed data available via an API. All stages of the indexing pipeline, from the data extraction to transformation to persistence are performed on [batches of blocks](/sdk/resources/basics/batch-processing) to maximize the indexing speed. Modular architecture of the SDK makes it possible to extend indexing projects (squids) with custom plugins and data targets. +(either permissioned or decentralized instance). The Squid SDK is a set of open source Typescript libraries that retrieve, decode, transform and persist the data. It can also make the transformed data available via an API. All stages of the indexing pipeline, from the data extraction to transformation to persistence are performed on [batches of blocks](/sdk/resources/batch-processing) to maximize the indexing speed. Modular architecture of the SDK makes it possible to extend indexing projects (squids) with custom plugins and data targets. ## Required squid components @@ -75,9 +75,9 @@ Install these with `--save-dev`. ### GraphQL server -Squids that store their data in PostgreSQL can subsequently make it available as a GraphQL API via a variety of supported servers. See [Serving GraphQL](/sdk/resources/basics/serving-graphql). +Squids that store their data in PostgreSQL can subsequently make it available as a GraphQL API via a variety of supported servers. See [Serving GraphQL](/sdk/resources/serving-graphql). -Among other alternatives, SQD provides its own server via the [`@subsquid/graphql-server`](https://www.npmjs.com/package/@subsquid/graphql-server) package. The server runs as a separate process. [Core API](/sdk/reference/graphql-server/openreader) is automatically derived from the schema file; it is possible to extend it with [custom queries](/sdk/reference/graphql-server/configuration/custom-resolvers) and [basic access control](/sdk/reference/graphql-server/configuration/authorization). +Among other alternatives, SQD provides its own server via the [`@subsquid/graphql-server`](https://www.npmjs.com/package/@subsquid/graphql-server) package. The server runs as a separate process. [Core API](/sdk/reference/openreader-server/api) is automatically derived from the schema file; it is possible to extend it with [custom queries](/sdk/reference/openreader-server/configuration/custom-resolvers) and [basic access control](/sdk/reference/openreader-server/configuration/authorization). ### Misc utilities diff --git a/docs/sdk/reference/openreader-server/api/and-or-filters.md b/docs/sdk/reference/openreader-server/api/and-or-filters.md index 5141d303..9e45d022 100644 --- a/docs/sdk/reference/openreader-server/api/and-or-filters.md +++ b/docs/sdk/reference/openreader-server/api/and-or-filters.md @@ -9,11 +9,11 @@ description: >- ## Overview -Our GraphQL implementation offers a vast selection of tools to filter and section results. One of these is the `where` clause, very common in most database query languages and [explained here](/sdk/reference/graphql-server/openreader/queries/#filter-query-results--search-queries) in detail. +Our GraphQL implementation offers a vast selection of tools to filter and section results. One of these is the `where` clause, very common in most database query languages and [explained here](/sdk/reference/openreader-server/api/queries/#filter-query-results--search-queries) in detail. In our GraphQL server implementation, we included logical operators to be used in the `where` clause, allowing to group multiple parameters in the same `where` argument using the `AND` and `OR` operators to filter results based on more than one criteria. -Note that the [newer](/sdk/reference/graphql-server/overview/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. +Note that the [newer](/sdk/reference/openreader-server/overview/#supported-queries) and [more advanced](/sdk/reference/openreader-server/api/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. ### Example of an `OR` clause: diff --git a/docs/sdk/reference/openreader-server/api/cross-relation-field-queries.md b/docs/sdk/reference/openreader-server/api/cross-relation-field-queries.md index c6f846e3..6b29861f 100644 --- a/docs/sdk/reference/openreader-server/api/cross-relation-field-queries.md +++ b/docs/sdk/reference/openreader-server/api/cross-relation-field-queries.md @@ -9,7 +9,7 @@ description: >- ## Introduction -The [previous section](/sdk/reference/graphql-server/openreader/nested-field-queries) has already demonstrated that queries can return not just scalars such as a String, but also fields that refer to object or entity types. What's even more interesting is that queries can leverage fields of related objects to filter results. +The [previous section](/sdk/reference/openreader-server/api/nested-field-queries) has already demonstrated that queries can return not just scalars such as a String, but also fields that refer to object or entity types. What's even more interesting is that queries can leverage fields of related objects to filter results. Let's take this sample schema with two entity types and a one-to-many relationship between them: diff --git a/docs/sdk/reference/openreader-server/api/intro.md b/docs/sdk/reference/openreader-server/api/intro.md index 2a769356..30abdaa2 100644 --- a/docs/sdk/reference/openreader-server/api/intro.md +++ b/docs/sdk/reference/openreader-server/api/intro.md @@ -6,14 +6,14 @@ description: >- --- :::info -At the moment, [Squid SDK GraphQL server](/sdk/reference/graphql-server) can only be used with squids that use Postgres as their target database. +At the moment, [Squid SDK GraphQL server](/sdk/reference/openreader-server) can only be used with squids that use Postgres as their target database. ::: GraphQL is an API query language, and a server-side runtime for executing queries using a custom type system. Head over to the [official documentation website](https://graphql.org/learn/) for more info. -A GraphQL API served by the [GraphQL server](/sdk/reference/graphql-server) has two components: +A GraphQL API served by the [GraphQL server](/sdk/reference/openreader-server) has two components: 1. Core API is defined by the [schema file](/sdk/reference/schema-file). -2. Extensions added via [custom resolvers](/sdk/reference/graphql-server/configuration/custom-resolvers). +2. Extensions added via [custom resolvers](/sdk/reference/openreader-server/configuration/custom-resolvers). In this section we cover the core GraphQL API, with short explanations on how to perform GraphQL queries, how to paginate and sort results. This functionality is supported via [OpenReader](https://github.com/subsquid/squid-sdk/tree/master/graphql/openreader), Subsquid's own implementation of [OpenCRUD](https://www.opencrud.org). diff --git a/docs/sdk/reference/openreader-server/api/nested-field-queries.md b/docs/sdk/reference/openreader-server/api/nested-field-queries.md index eb74dc9a..834c0b07 100644 --- a/docs/sdk/reference/openreader-server/api/nested-field-queries.md +++ b/docs/sdk/reference/openreader-server/api/nested-field-queries.md @@ -44,4 +44,4 @@ query { } ``` -Note that the [newer](/sdk/reference/graphql-server/overview/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. +Note that the [newer](/sdk/reference/openreader-server/overview/#supported-queries) and [more advanced](/sdk/reference/openreader-server/api/paginate-query-results) `{entityName}sConnection` queries support exactly the same format of the `where` argument as the older `{entityName}s` queries used in the examples provided here. diff --git a/docs/sdk/reference/openreader-server/api/paginate-query-results.md b/docs/sdk/reference/openreader-server/api/paginate-query-results.md index 1a1cdde6..0ecd6216 100644 --- a/docs/sdk/reference/openreader-server/api/paginate-query-results.md +++ b/docs/sdk/reference/openreader-server/api/paginate-query-results.md @@ -15,7 +15,7 @@ Cursors are used to traverse across entities of an entity set. They work by retu Currently, only forward pagination is supported. If your use case requires bidirectional pagination please let us know at our [Telegram channel](https://t.me/HydraDevs). -In Subsquid GraphQL server, cursor based pagination is implemented with `{entityName}sConnection` queries available for every entity in the input schema. These queries require an explicitly supplied [`orderBy` argument](/sdk/reference/graphql-server/openreader/sorting), and *the field that is used for ordering must also be requested by the query itself*. Check out [this section](/sdk/reference/graphql-server/openreader/paginate-query-results/#important-note-on-orderby) for a valid query template. +In Subsquid GraphQL server, cursor based pagination is implemented with `{entityName}sConnection` queries available for every entity in the input schema. These queries require an explicitly supplied [`orderBy` argument](/sdk/reference/openreader-server/api/sorting), and *the field that is used for ordering must also be requested by the query itself*. Check out [this section](/sdk/reference/openreader-server/api/paginate-query-results/#important-note-on-orderby) for a valid query template. Example: this query fetches a list of videos where `isExplicit` is true and gets their count. diff --git a/docs/sdk/reference/openreader-server/api/queries.md b/docs/sdk/reference/openreader-server/api/queries.md index e4832598..b4668668 100644 --- a/docs/sdk/reference/openreader-server/api/queries.md +++ b/docs/sdk/reference/openreader-server/api/queries.md @@ -29,7 +29,7 @@ query { } } ``` -or, using a [newer](/sdk/reference/graphql-server/overview/#supported-queries) and [more advanced](/sdk/reference/graphql-server/openreader/paginate-query-results) `{entityName}sConnection` query +or, using a [newer](/sdk/reference/openreader-server/overview/#supported-queries) and [more advanced](/sdk/reference/openreader-server/api/paginate-query-results) `{entityName}sConnection` query ```graphql query { diff --git a/docs/sdk/reference/openreader-server/configuration/authorization.md b/docs/sdk/reference/openreader-server/configuration/authorization.md index d92d554c..250aa20d 100644 --- a/docs/sdk/reference/openreader-server/configuration/authorization.md +++ b/docs/sdk/reference/openreader-server/configuration/authorization.md @@ -48,7 +48,7 @@ Here, ## Sending user data to resolvers -Authentication data such as user name can be passed from `requestCheck()` to a [custom resolver](/sdk/reference/graphql-server/configuration/custom-resolvers/) through Openreader context: +Authentication data such as user name can be passed from `requestCheck()` to a [custom resolver](/sdk/reference/openreader-server/configuration/custom-resolvers/) through Openreader context: ```typescript export async function requestCheck(req: RequestCheckContext): Promise { ... @@ -100,7 +100,7 @@ export class UserCommentResolver { ``` See full code in [this branch](https://github.com/subsquid-labs/access-control-example/tree/interacting-with-resolver). -This approach does not work with [subscriptions](/sdk/reference/graphql-server/configuration/subscriptions/). +This approach does not work with [subscriptions](/sdk/reference/openreader-server/configuration/subscriptions/). ## Examples diff --git a/docs/sdk/reference/openreader-server/configuration/dos-protection.md b/docs/sdk/reference/openreader-server/configuration/dos-protection.md index 2b78377e..4513a971 100644 --- a/docs/sdk/reference/openreader-server/configuration/dos-protection.md +++ b/docs/sdk/reference/openreader-server/configuration/dos-protection.md @@ -65,7 +65,7 @@ In a nutshell, assuming that the schema file is properly decorated with `@cardin **`--subscription-max-response-size `** -Same as `--max-response-size` but for live query [subscriptions](/sdk/reference/graphql-server/configuration/subscriptions). +Same as `--max-response-size` but for live query [subscriptions](/sdk/reference/openreader-server/configuration/subscriptions). #### Example diff --git a/docs/sdk/reference/openreader-server/configuration/subscriptions.md b/docs/sdk/reference/openreader-server/configuration/subscriptions.md index d09820ac..70532872 100644 --- a/docs/sdk/reference/openreader-server/configuration/subscriptions.md +++ b/docs/sdk/reference/openreader-server/configuration/subscriptions.md @@ -20,7 +20,7 @@ npx squid-graphql-server --help For each entity types, the following queries are supported for subscriptions: - `${EntityName}ById` -- query a single entity - `${EntityName}s` -- query multiple entities with a `where` filter -Note that despite being [deprecated](/sdk/reference/graphql-server/overview/#supported-queries) from the regular query set, `${EntityName}s` queries will continue to be available for subscriptions going forward. +Note that despite being [deprecated](/sdk/reference/openreader-server/overview/#supported-queries) from the regular query set, `${EntityName}s` queries will continue to be available for subscriptions going forward. ## Local runs diff --git a/docs/sdk/reference/openreader-server/overview.md b/docs/sdk/reference/openreader-server/overview.md index 76cb7dd7..9c49261a 100644 --- a/docs/sdk/reference/openreader-server/overview.md +++ b/docs/sdk/reference/openreader-server/overview.md @@ -6,7 +6,7 @@ description: The SQD GraphQL server, built in-house # Overview :::info -SQD GraphQL server is no longer recommended for use in new squid projects [relying on PostgreSQL](/sdk/resources/persisting-data/typeorm). See [Serving GraphQL](/sdk/resources/basics/serving-graphql) to learn about the new options and the [Known issues](#known-issues) section to understand our motivation. +SQD GraphQL server is no longer recommended for use in new squid projects [relying on PostgreSQL](/sdk/resources/persisting-data/typeorm). See [Serving GraphQL](/sdk/resources/serving-graphql) to learn about the new options and the [Known issues](#known-issues) section to understand our motivation. ::: The data indexed by a squid into a Postgres database can be automatically presented with a GraphQL API service powered by the [OpenReader](https://github.com/subsquid/squid-sdk/tree/master/graphql/openreader) lib of the Squid SDK. The OpenReader GraphQL server takes [schema file](/sdk/reference/schema-file) as an input and serves a GraphQL API supporting [OpenCRUD](https://www.opencrud.org/) queries for the entities defined in the schema. @@ -15,7 +15,7 @@ To start the API server based on `schema.graphql` install `@subsquid/graphql-ser ```bash npx squid-graphql-server ``` -The `squid-graphql-server` executable supports multiple optional flags to enable [caching](/sdk/reference/graphql-server/configuration/caching), [subscriptions](/sdk/reference/graphql-server/configuration/subscriptions), [DoS protection](/sdk/reference/graphql-server/configuration/dos-protection) etc. Its features are covered in the next sections. +The `squid-graphql-server` executable supports multiple optional flags to enable [caching](/sdk/reference/openreader-server/configuration/caching), [subscriptions](/sdk/reference/openreader-server/configuration/subscriptions), [DoS protection](/sdk/reference/openreader-server/configuration/dos-protection) etc. Its features are covered in the next sections. The API server listens at port defined by the `GQL_PORT` environment variable (defaults to `4350`). The database connection is configured with the env variables `DB_NAME`, `DB_USER`, `DB_PASS`, `DB_HOST`, `DB_PORT`. @@ -23,16 +23,16 @@ The GraphQL API is enabled by the `api:` service in the `deploy` section of [squ ## Supported queries -The details of the supported OpenReader queries can be found in a separate section [Query a Squid](/sdk/reference/graphql-server/openreader). Here is a brief overview of the queries generated by OpenReader for each entity defined in the schema file: +The details of the supported OpenReader queries can be found in a separate section [Query a Squid](/sdk/reference/openreader-server/api). Here is a brief overview of the queries generated by OpenReader for each entity defined in the schema file: - the squid last processed block is available with `squidStatus { height }` query - a "get one by ID" query with the name `{entityName}ById` for each [entity](/sdk/reference/schema-file/entities) defined in the schema file - a "get one" query for [`@unique` fields](/sdk/reference/schema-file/indexes-and-constraints), with the name `{entityName}ByUniqueInput` -- Entity queries named `{entityName}sConnection`. Each query supports rich filtering support, including [field-level filters](/sdk/reference/graphql-server/openreader/queries), composite [`AND` and `OR` filters](/sdk/reference/graphql-server/openreader/and-or-filters), [nested queries](/sdk/reference/graphql-server/openreader/nested-field-queries), [cross-relation queries](/sdk/reference/graphql-server/openreader/cross-relation-field-queries) and [Relay-compatible](https://relay.dev/graphql/connections.htm) cursor-based [pagination](/sdk/reference/graphql-server/openreader/paginate-query-results). -- [Subsriptions](/sdk/reference/graphql-server/configuration/subscriptions) via live queries +- Entity queries named `{entityName}sConnection`. Each query supports rich filtering support, including [field-level filters](/sdk/reference/openreader-server/api/queries), composite [`AND` and `OR` filters](/sdk/reference/openreader-server/api/and-or-filters), [nested queries](/sdk/reference/openreader-server/api/nested-field-queries), [cross-relation queries](/sdk/reference/openreader-server/api/cross-relation-field-queries) and [Relay-compatible](https://relay.dev/graphql/connections.htm) cursor-based [pagination](/sdk/reference/openreader-server/api/paginate-query-results). +- [Subsriptions](/sdk/reference/openreader-server/configuration/subscriptions) via live queries - (Deprecated in favor of Relay connections) Lookup queries with the name `{entityName}s`. -[Union and typed JSON types](/sdk/reference/schema-file/unions-and-typed-json) are mapped into [GraphQL Union Types](https://graphql.org/learn/schema/#union-types) with a [proper type resolution](/sdk/reference/graphql-server/openreader/resolve-union-types-interfaces) with `__typename`. +[Union and typed JSON types](/sdk/reference/schema-file/unions-and-typed-json) are mapped into [GraphQL Union Types](https://graphql.org/learn/schema/#union-types) with a [proper type resolution](/sdk/reference/openreader-server/api/resolve-union-types-interfaces) with `__typename`. ## Built-in custom scalar types @@ -44,6 +44,6 @@ The OpenReader GraphQL API defines the following custom scalar types: ## Known issues -- RAM usage of [subscriptions](/sdk/reference/graphql-server/configuration/subscriptions) scales poorly under high load, making the feature unsuitable for most production uses. There are currently no plans to fix this issue. +- RAM usage of [subscriptions](/sdk/reference/openreader-server/configuration/subscriptions) scales poorly under high load, making the feature unsuitable for most production uses. There are currently no plans to fix this issue. - Setting up custom resolvers for subscriptions is unreasonably hard. - `@subsquid/graphql-server` depends on the deprecated Apollo Server v3. diff --git a/docs/sdk/reference/processors/evm-batch/context-interfaces.md b/docs/sdk/reference/processors/evm-batch/context-interfaces.md index 609c7604..bea6b1d9 100644 --- a/docs/sdk/reference/processors/evm-batch/context-interfaces.md +++ b/docs/sdk/reference/processors/evm-batch/context-interfaces.md @@ -34,7 +34,7 @@ The exact fields available in each data item type are inferred from the `setFiel ## Example -The handler below simply outputs all the log items emitted by the contract `0x2E645469f354BB4F5c8a05B3b30A929361cf77eC` in [real time](/sdk/resources/basics/unfinalized-blocks): +The handler below simply outputs all the log items emitted by the contract `0x2E645469f354BB4F5c8a05B3b30A929361cf77eC` in [real time](/sdk/resources/unfinalized-blocks): ```ts import { TypeormDatabase } from '@subsquid/typeorm-store' diff --git a/docs/sdk/reference/processors/evm-batch/general.md b/docs/sdk/reference/processors/evm-batch/general.md index d8642068..04f60d22 100644 --- a/docs/sdk/reference/processors/evm-batch/general.md +++ b/docs/sdk/reference/processors/evm-batch/general.md @@ -16,7 +16,7 @@ The following setters configure the global settings of `EvmBatchProcessor`. They Certain configuration methods are required: * one or both of [`setGateway()`](#set-gateway) and [`setRpcEndpoint()`](#set-rpc-endpoint) - * [`setFinalityConfirmation()`](#set-finality-confirmation) whenever [RPC ingestion](/sdk/resources/basics/unfinalized-blocks) is enabled, namely when + * [`setFinalityConfirmation()`](#set-finality-confirmation) whenever [RPC ingestion](/sdk/resources/unfinalized-blocks) is enabled, namely when - a RPC endpoint was configured with [`setRpcEndpoint()`](#set-rpc-endpoint) - RPC ingestion has **NOT** been explicitly disabled by calling [`setRpcDataIngestionSettings({ disabled: true })`](#set-rpc-data-ingestion-settings) @@ -41,7 +41,7 @@ See [EVM gateways](/subsquid-network/reference/evm-networks). ### `setRpcEndpoint(rpc: ChainRpc)` {#set-rpc-endpoint} Adds a RPC data source. If added, it will be used for - - [RPC ingestion](/sdk/resources/basics/unfinalized-blocks) (unless explicitly disabled with [`setRpcDataIngestionSettings()`](#set-rpc-data-ingestion-settings)) + - [RPC ingestion](/sdk/resources/unfinalized-blocks) (unless explicitly disabled with [`setRpcDataIngestionSettings()`](#set-rpc-data-ingestion-settings)) - any [direct RPC queries](/sdk/resources/tools/typegen/state-queries/?typegen=evm) you make in your squid code A node RPC endpoint can be specified as a string URL or as an object: @@ -67,7 +67,7 @@ Replaced by [`setGateway()`](#set-gateway) and [`setRpcEndpoint()`](#set-rpc-end ### `setRpcDataIngestionSetting(settings: RpcDataIngestionSettings)` {#set-rpc-data-ingestion-settings} -Specify the [RPC ingestion](/sdk/resources/basics/unfinalized-blocks) settings. +Specify the [RPC ingestion](/sdk/resources/unfinalized-blocks) settings. ```ts type RpcDataIngestionSettings = { disabled?: boolean diff --git a/docs/sdk/reference/processors/evm-batch/state-diffs.md b/docs/sdk/reference/processors/evm-batch/state-diffs.md index 98eb1577..c05af8d8 100644 --- a/docs/sdk/reference/processors/evm-batch/state-diffs.md +++ b/docs/sdk/reference/processors/evm-batch/state-diffs.md @@ -7,7 +7,7 @@ description: >- # Storage state diffs :::tip -State diffs for historical blocks are [currently available](/subsquid-network/reference/evm-networks) from [Subsquid Network](/subsquid-network) on the same basis as all other data stored there: for free. If you deploy a squid that indexes traces [in real-time](/sdk/resources/basics/unfinalized-blocks) to Subsquid Cloud and use our [RPC addon](/cloud/resources/rpc-proxy), the necessary `trace_` or `debug_` RPC calls made will be counted alongside all other calls and [the price](/cloud/pricing/#rpc-requests) will be computed for the total count. There are no surcharges for traces or state diffs. +State diffs for historical blocks are [currently available](/subsquid-network/reference/evm-networks) from [Subsquid Network](/subsquid-network) on the same basis as all other data stored there: for free. If you deploy a squid that indexes traces [in real-time](/sdk/resources/unfinalized-blocks) to Subsquid Cloud and use our [RPC addon](/cloud/resources/rpc-proxy), the necessary `trace_` or `debug_` RPC calls made will be counted alongside all other calls and [the price](/cloud/pricing/#rpc-requests) will be computed for the total count. There are no surcharges for traces or state diffs. ::: #### `addStateDiff(options)` {#add-state-diff} diff --git a/docs/sdk/reference/processors/evm-batch/traces.md b/docs/sdk/reference/processors/evm-batch/traces.md index 16d6ce53..eb27c26b 100644 --- a/docs/sdk/reference/processors/evm-batch/traces.md +++ b/docs/sdk/reference/processors/evm-batch/traces.md @@ -7,7 +7,7 @@ description: >- # Traces :::tip -Traces for historical blocks are [currently available](/subsquid-network/reference/evm-networks) from [Subsquid Network](/subsquid-network) on the same basis as all other data stored there: for free. If you deploy a squid that indexes traces [in real-time](/sdk/resources/basics/unfinalized-blocks) to Subsquid Cloud and use our [RPC addon](/cloud/resources/rpc-proxy), the necessary `trace_` or `debug_` RPC calls made will be counted alongside all other calls and [the price](/cloud/pricing/#rpc-requests) will be computed for the total count. There are no surcharges for traces or state diffs. +Traces for historical blocks are [currently available](/subsquid-network/reference/evm-networks) from [Subsquid Network](/subsquid-network) on the same basis as all other data stored there: for free. If you deploy a squid that indexes traces [in real-time](/sdk/resources/unfinalized-blocks) to Subsquid Cloud and use our [RPC addon](/cloud/resources/rpc-proxy), the necessary `trace_` or `debug_` RPC calls made will be counted alongside all other calls and [the price](/cloud/pricing/#rpc-requests) will be computed for the total count. There are no surcharges for traces or state diffs. ::: #### `addTrace(options)` {#add-trace} diff --git a/docs/sdk/reference/processors/substrate-batch/context-interfaces.md b/docs/sdk/reference/processors/substrate-batch/context-interfaces.md index d1d9deb9..fb84cffa 100644 --- a/docs/sdk/reference/processors/substrate-batch/context-interfaces.md +++ b/docs/sdk/reference/processors/substrate-batch/context-interfaces.md @@ -29,7 +29,7 @@ The exact fields available in each data item type are inferred from the `setFiel ## Example -The handler below simply outputs all the `Balances.transfer_all` calls on Kusama in [real time](/sdk/resources/basics/unfinalized-blocks): +The handler below simply outputs all the `Balances.transfer_all` calls on Kusama in [real time](/sdk/resources/unfinalized-blocks): ```ts import {SubstrateBatchProcessor} from '@subsquid/substrate-processor' diff --git a/docs/sdk/reference/processors/substrate-batch/general.md b/docs/sdk/reference/processors/substrate-batch/general.md index e41b349d..cb83e37d 100644 --- a/docs/sdk/reference/processors/substrate-batch/general.md +++ b/docs/sdk/reference/processors/substrate-batch/general.md @@ -15,7 +15,7 @@ The following setters configure the global settings of `SubstrateBatchProcessor` Calling [`setRpcEndpoint()`](#set-rpc-endpoint) is a hard requirement on Substrate, as chain RPC is used to retrieve chain metadata. Adding a [Subsquid Network gateway](/subsquid-network/reference/substrate-networks) with [`setGateway()`](#set-gateway) is optional but highly recommended, as it greatly reduces RPC usage. -To reduce it further, you can explicitly disable [RPC ingestion](/sdk/resources/basics/unfinalized-blocks) by calling [`setRpcDataIngestionSettings({ disabled: true })`](#set-rpc-data-ingestion-settings): in this scenario the RPC will only be used for metadata retrieval and to perform any [direct RPC queries](/sdk/resources/tools/typegen/state-queries/?typegen=substrate) you might be doing in your squid code. This will, however, introduce a delay of a few thousands of blocks between the chain head and the highest block available to your squid. +To reduce it further, you can explicitly disable [RPC ingestion](/sdk/resources/unfinalized-blocks) by calling [`setRpcDataIngestionSettings({ disabled: true })`](#set-rpc-data-ingestion-settings): in this scenario the RPC will only be used for metadata retrieval and to perform any [direct RPC queries](/sdk/resources/tools/typegen/state-queries/?typegen=substrate) you might be doing in your squid code. This will, however, introduce a delay of a few thousands of blocks between the chain head and the highest block available to your squid. ### `setGateway(url: string | GatewaySettings)` {#set-gateway} @@ -31,7 +31,7 @@ See [Substrate gateways](/subsquid-network/reference/substrate-networks). ### `setRpcEndpoint(rpc: ChainRpc)` {#set-rpc-endpoint} Adds a RPC data source. If added, it will be used for - - [RPC ingestion](/sdk/resources/basics/unfinalized-blocks) (unless explicitly disabled with [`setRpcDataIngestionSettings()`](#set-rpc-data-ingestion-settings)) + - [RPC ingestion](/sdk/resources/unfinalized-blocks) (unless explicitly disabled with [`setRpcDataIngestionSettings()`](#set-rpc-data-ingestion-settings)) - any [direct RPC queries](/sdk/resources/tools/typegen/state-queries/?typegen=substrate) you make in your squid code A node RPC endpoint can be specified as a string URL or as an object: @@ -57,7 +57,7 @@ Replaced by [`setGateway()`](#set-gateway) and [`setRpcEndpoint()`](#set-rpc-end ### `setRpcDataIngestionSetting(settings: RpcDataIngestionSettings)` {#set-rpc-data-ingestion-settings} -Specify the [RPC ingestion](/sdk/resources/basics/unfinalized-blocks) settings. +Specify the [RPC ingestion](/sdk/resources/unfinalized-blocks) settings. ```ts type RpcDataIngestionSettings = { disabled?: boolean diff --git a/docs/sdk/reference/schema-file/entity-relations.md b/docs/sdk/reference/schema-file/entity-relations.md index aeca917d..09ff8b62 100644 --- a/docs/sdk/reference/schema-file/entity-relations.md +++ b/docs/sdk/reference/schema-file/entity-relations.md @@ -10,7 +10,7 @@ The term "entity relation" refers to the situation when an entity instance conta [One-to-one](https://github.com/typeorm/typeorm/blob/master/docs/one-to-one-relations.md) and [one-to-many](https://github.com/typeorm/typeorm/blob/master/docs/many-to-one-one-to-many-relations.md) relations are supported by Typeorm. The "many" side of the one-to-many relations is always the owning side. Many-to-many relations are modeled as [two one-to-many relations with an explicit join table](#many-to-many-relations). -An entity relation is always unidirectional, but it is possible to request the data on the owning entity from the non-owning one. To do so, define a field decorated `@derivedFrom` in the schema. Doing so will cause the Typeorm code generated by [`squid-typeorm-codegen`](/sdk/resources/persisting-data/typeorm) and the GraphQL API served by [`squid-graphql-server`](/sdk/reference/graphql-server/overview) to show a virtual (that is, **not mapping to a database column**) field populated via inverse lookup queries. +An entity relation is always unidirectional, but it is possible to request the data on the owning entity from the non-owning one. To do so, define a field decorated `@derivedFrom` in the schema. Doing so will cause the Typeorm code generated by [`squid-typeorm-codegen`](/sdk/resources/persisting-data/typeorm) and the GraphQL API served by [`squid-graphql-server`](/sdk/reference/openreader-server/overview) to show a virtual (that is, **not mapping to a database column**) field populated via inverse lookup queries. The following examples illustrate the concepts. diff --git a/docs/sdk/reference/schema-file/interfaces.md b/docs/sdk/reference/schema-file/interfaces.md index c95baead..9b4054ac 100644 --- a/docs/sdk/reference/schema-file/interfaces.md +++ b/docs/sdk/reference/schema-file/interfaces.md @@ -6,7 +6,7 @@ description: Queriable interfaces # Interfaces -The schema file supports [GraphQL Interfaces](https://graphql.org/learn/schema/#interfaces) for modelling complex types sharing common traits. Interfaces are annotated with `@query` at the type level and do not affect the database schema, only enriching the [API queries](/sdk/reference/graphql-server/openreader) of the [SQD GraphQL server](/sdk/reference/graphql-server) with [inline fragments](https://graphql.org/learn/queries/#inline-fragments). +The schema file supports [GraphQL Interfaces](https://graphql.org/learn/schema/#interfaces) for modelling complex types sharing common traits. Interfaces are annotated with `@query` at the type level and do not affect the database schema, only enriching the [API queries](/sdk/reference/openreader-server/api) of the [SQD GraphQL server](/sdk/reference/openreader-server) with [inline fragments](https://graphql.org/learn/queries/#inline-fragments). ### Examples @@ -47,7 +47,7 @@ type Baz implements MyEntity @entity { } ``` -The `MyEntity` interface above enables `myEntities` and `myEntitiesConnection` [GraphQL API queries](/sdk/reference/graphql-server/openreader) with inline fragments and the `_type`, `__typename` [meta fields](https://graphql.org/learn/queries/#meta-fields): +The `MyEntity` interface above enables `myEntities` and `myEntitiesConnection` [GraphQL API queries](/sdk/reference/openreader-server/api) with inline fragments and the `_type`, `__typename` [meta fields](https://graphql.org/learn/queries/#meta-fields): ```graphql query { diff --git a/docs/sdk/reference/schema-file/intro.md b/docs/sdk/reference/schema-file/intro.md index 85631dd1..429598c8 100644 --- a/docs/sdk/reference/schema-file/intro.md +++ b/docs/sdk/reference/schema-file/intro.md @@ -10,7 +10,7 @@ description: >- The schema file `schema.graphql` uses a GraphQL dialect to model the target entities and entity relations. The tooling around the schema file is then used to: - Generate TypeORM entities (with `squid-typeorm-codegen(1)`, see below) - Generate the database schema from the TypeORM entities (see [db migrations](/sdk/resources/persisting-data/typeorm)) -- Optionally, the schema can be used to present the target data with a [GraphQL API](/sdk/resources/basics/serving-graphql). +- Optionally, the schema can be used to present the target data with a [GraphQL API](/sdk/resources/serving-graphql). The schema file format is loosely compatible with the [subgraph schema](https://thegraph.com/docs/en/developing/creating-a-subgraph/) file, see [Migrate from subgraph](/sdk/resources/migrate/migrate-subgraph) section for details. diff --git a/docs/sdk/resources/migrate/migrate-subgraph.md b/docs/sdk/resources/migrate/migrate-subgraph.md index 67d80ca2..1a79154b 100644 --- a/docs/sdk/resources/migrate/migrate-subgraph.md +++ b/docs/sdk/resources/migrate/migrate-subgraph.md @@ -14,7 +14,7 @@ git clone https://github.com/subsquid-labs/gravatar-squid.git `EvmBatchProcessor` provided by the Squid SDK defines a single handler that indexes EVM logs and transaction data in batches. It differs from the programming model of subgraph mappings that defines a separate data handler for each EVM log topic to be indexed. Due to significantly less frequent database hits (once per batch compared to once per log) the batch-based handling model shows up to a 10x increase in the indexing speed. -At the same time, concepts of the [schema file](/sdk/reference/schema-file), [code generation from the schema file](/sdk/reference/schema-file/intro/#typeorm-codegen) and [auto-generated GraphQL API](/sdk/resources/basics/serving-graphql) should be familiar to subgraph developers. In most cases the schema file of a subgraph can be imported into a squid as is. +At the same time, concepts of the [schema file](/sdk/reference/schema-file), [code generation from the schema file](/sdk/reference/schema-file/intro/#typeorm-codegen) and [auto-generated GraphQL API](/sdk/resources/serving-graphql) should be familiar to subgraph developers. In most cases the schema file of a subgraph can be imported into a squid as is. There are some known limitations: - Many-to-Many entity relations should be [modeled explicitly](/sdk/reference/schema-file/entity-relations/#many-to-many-relations) as two many-to-one relations @@ -24,10 +24,10 @@ On top of the features provided by subgraphs, Squid SDK and Subsquid Cloud offer - Full control over the target database (Postgres), including custom migrations and ad-hoc queries in the handler - Custom target databases and data formats (e.g. CSV) - Arbitrary code execution in the data handler -- [Extension of the GraphQL API](/sdk/reference/graphql-server/configuration/custom-resolvers) with arbitrary SQL +- [Extension of the GraphQL API](/sdk/reference/openreader-server/configuration/custom-resolvers) with arbitrary SQL - [Secret environment variables](/cloud/resources/env-variables), allowing to seamlessly use private third-party JSON-RPC endpoints and integrate with external APIs - [API versioning and aliasing](/cloud/resources/production-alias) -- [API caching](/sdk/reference/graphql-server/configuration/caching) +- [API caching](/sdk/reference/openreader-server/configuration/caching) For a full feature set comparison, see [Subsquid vs The Graph](/sdk/subsquid-vs-thegraph). diff --git a/docs/sdk/resources/multichain.md b/docs/sdk/resources/multichain.md index f8342178..6a68bff6 100644 --- a/docs/sdk/resources/multichain.md +++ b/docs/sdk/resources/multichain.md @@ -6,7 +6,7 @@ description: Combine data from multiple chains # Multichain indexing -Squids can extract data from multiple chains into a shared data sink. If the data is [stored to Postgres](/sdk/resources/persisting-data/typeorm) it can then be served as a unified multichain [GraphQL API](/sdk/resources/basics/serving-graphql). +Squids can extract data from multiple chains into a shared data sink. If the data is [stored to Postgres](/sdk/resources/persisting-data/typeorm) it can then be served as a unified multichain [GraphQL API](/sdk/resources/serving-graphql). To do this, run one [processor](/sdk/overview) per source network: @@ -69,7 +69,7 @@ Also ensure that async (ctx) => { // ... ``` -2. [Schema](/sdk/reference/schema-file) and [GraphQL API](/sdk/resources/basics/serving-graphql) are shared among the processors. +2. [Schema](/sdk/reference/schema-file) and [GraphQL API](/sdk/resources/serving-graphql) are shared among the processors. ### Handling concurrency @@ -79,7 +79,7 @@ Also ensure that - To avoid cross-chain data dependencies, use per-chain records for volatile data. E.g. if you track account balances across multiple chains you can avoid overlaps by storing the balance for each chain in a different table row. - When you need to combine the records (e.g. get a total of all balaces across chains) use a [custom resolver](/sdk/reference/graphql-server/configuration/custom-resolvers) to do it on the GraphQL server side. + When you need to combine the records (e.g. get a total of all balaces across chains) use a [custom resolver](/sdk/reference/openreader-server/configuration/custom-resolvers) to do it on the GraphQL server side. - It is OK to use cross-chain [entities](/sdk/reference/schema-file/entities) to simplify aggregation. Just don't store any data in them: ```graphql diff --git a/docs/sdk/resources/serving-graphql.md b/docs/sdk/resources/serving-graphql.md index 42a28526..7d92f1e8 100644 --- a/docs/sdk/resources/serving-graphql.md +++ b/docs/sdk/resources/serving-graphql.md @@ -6,7 +6,7 @@ description: GraphQL servers commonly used in squids # Serving GraphQL -It is common (although not required) for squids to serve GraphQL APIs. Historically, the most common way to do that was to [persist the squid data to PostgreSQL](/sdk/resources/persisting-data/typeorm), then attach the [SQD GraphQL server](#the-sqd-graphql-server) to it. Although this is still supported, we encourage using [PostGraphile](#postgraphile) or [Hasura](#hasura) in new PostgreSQD-based projects. See [SQD GraphQL server known issues](/sdk/reference/graphql-server/overview/#known-issues) if you're curious about our motivation. +It is common (although not required) for squids to serve GraphQL APIs. Historically, the most common way to do that was to [persist the squid data to PostgreSQL](/sdk/resources/persisting-data/typeorm), then attach the [SQD GraphQL server](#the-sqd-graphql-server) to it. Although this is still supported, we encourage using [PostGraphile](#postgraphile) or [Hasura](#hasura) in new PostgreSQD-based projects. See [SQD GraphQL server known issues](/sdk/reference/openreader-server/overview/#known-issues) if you're curious about our motivation. ## PostGraphile @@ -37,6 +37,6 @@ As per usual with PostGraphile installations, you can freely extend it with plug ## The SQD GraphQL server -The [SQD GraphQL server](/sdk/reference/graphql-server) is a GraphQL server developed by the SQD team. Although still supported, it's not recommeded for new PostgreSQL-powered projects due to its [known issues](/sdk/reference/graphql-server/overview/#known-issues), especially for APIs implementing GraphQL subscriptions. +The [SQD GraphQL server](/sdk/reference/openreader-server) is a GraphQL server developed by the SQD team. Although still supported, it's not recommeded for new PostgreSQL-powered projects due to its [known issues](/sdk/reference/openreader-server/overview/#known-issues), especially for APIs implementing GraphQL subscriptions. -The server uses the [schema file](/sdk/reference/schema-file) to produce its [core API](/sdk/reference/graphql-server/openreader) that can be extended with [custom resolvers](/sdk/reference/graphql-server/configuration/custom-resolvers). Extra features include [DoS protection](/sdk/reference/graphql-server/configuration/dos-protection). +The server uses the [schema file](/sdk/reference/schema-file) to produce its [core API](/sdk/reference/openreader-server/api) that can be extended with [custom resolvers](/sdk/reference/openreader-server/configuration/custom-resolvers). Extra features include [DoS protection](/sdk/reference/openreader-server/configuration/dos-protection). diff --git a/docs/sdk/troubleshooting.mdx b/docs/sdk/troubleshooting.mdx index 20f0494d..347af5c9 100644 --- a/docs/sdk/troubleshooting.mdx +++ b/docs/sdk/troubleshooting.mdx @@ -69,13 +69,13 @@ PostgreSQL doesn't support storing `NULL (\0x00)` characters in text fields. Usu API queries are too slow - Make sure all the necessary fields are [indexed](/sdk/reference/schema-file/indexes-and-constraints/) -- Annotate the schema and [set reasonable limits](/sdk/reference/graphql-server/configuration/dos-protection/) for the incoming queries to protect against DoS attacks +- Annotate the schema and [set reasonable limits](/sdk/reference/openreader-server/configuration/dos-protection/) for the incoming queries to protect against DoS attacks
`response might exceed the size limit` -Make sure the input query has limits set or the entities are decorated with `@cardinality`. We recommend using `XXXConnection` queries for pagination. For configuring limits and max response sizes, see [DoS protection](/sdk/reference/graphql-server/configuration/dos-protection/). +Make sure the input query has limits set or the entities are decorated with `@cardinality`. We recommend using `XXXConnection` queries for pagination. For configuring limits and max response sizes, see [DoS protection](/sdk/reference/openreader-server/configuration/dos-protection/).
diff --git a/docs/sdk/tutorials/bayc/step-four-optimizations.md b/docs/sdk/tutorials/bayc/step-four-optimizations.md index 7a1d1f4b..64b102e7 100644 --- a/docs/sdk/tutorials/bayc/step-four-optimizations.md +++ b/docs/sdk/tutorials/bayc/step-four-optimizations.md @@ -15,7 +15,7 @@ Pre-requisites: Node.js, [Subsquid CLI](/squid-cli/installation), Docker, a proj ## Using Multicall for aggregating state queries -We begin by introducing [batch processing](/sdk/resources/basics/batch-processing/) wherever possible, and our first step is to replace individual contract state queries with [batch calls](/sdk/resources/tools/typegen/state-queries/#batch-state-queries) to a [MakerDAO multicall contract](https://github.com/mds1/multicall). Retrieve the multicall contract ABI by re-running `squid-evm-typegen` with `--multicall` option: +We begin by introducing [batch processing](/sdk/resources/batch-processing/) wherever possible, and our first step is to replace individual contract state queries with [batch calls](/sdk/resources/tools/typegen/state-queries/#batch-state-queries) to a [MakerDAO multicall contract](https://github.com/mds1/multicall). Retrieve the multicall contract ABI by re-running `squid-evm-typegen` with `--multicall` option: ```bash npx squid-evm-typegen --multicall src/abi 0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d#bayc ``` diff --git a/docs/sdk/tutorials/bayc/step-one-indexing-transfers.md b/docs/sdk/tutorials/bayc/step-one-indexing-transfers.md index aedd2c17..dc60e470 100644 --- a/docs/sdk/tutorials/bayc/step-one-indexing-transfers.md +++ b/docs/sdk/tutorials/bayc/step-one-indexing-transfers.md @@ -195,7 +195,7 @@ Note a few things here: * A unique event log ID is available at `log.id` - no need to generate your own! * `tokenId` returned from the decoder is an `ethers.BigNumber`, so it has to be explicitly converted to `number`. The conversion is valid only because we know that BAYC NFT IDs run from 0 to 9999; in most cases we would use `BigInt` for the entity field type and convert with `tokenId.toBigInt()`. * `block.header` contains block metadata that we use to fill the extra fields. -* Accumulating the `Transfer` entity instances before using `ctx.store.insert()` on the whole array of them in the end allows us to get away with just one database transaction per batch. This is [crucial for achieving a good syncing performance](/sdk/resources/basics/batch-processing/). +* Accumulating the `Transfer` entity instances before using `ctx.store.insert()` on the whole array of them in the end allows us to get away with just one database transaction per batch. This is [crucial for achieving a good syncing performance](/sdk/resources/batch-processing/). At this point we have a squid that indexes the data on BAYC token transfers and is capable of serving it over a GraphQL API. Full code is available at [this commit](https://github.com/subsquid-labs/bayc-squid-1/tree/aeb6268168385cc605ce04fe09d0159f708efe47). Test it by running ```bash diff --git a/docs/sdk/tutorials/bayc/step-three-adding-external-data.md b/docs/sdk/tutorials/bayc/step-three-adding-external-data.md index 4bfca3eb..cb4a2513 100644 --- a/docs/sdk/tutorials/bayc/step-three-adding-external-data.md +++ b/docs/sdk/tutorials/bayc/step-three-adding-external-data.md @@ -19,7 +19,7 @@ Now that we have a record for each BAYC NFT, let's explore how we can retrieve m [EIP-721](https://eips.ethereum.org/EIPS/eip-721) suggests that token metadata contracts may make token data available in a JSON referred to by the output of the `tokenURI()` contract function. Upon examining `src/abi/bayc.ts`, we find that the BAYC token contract implements this function. Also, the public ABI has no obvious contract methods that may set token URI or events that may be emitted on its change. In other words, it appears that the only way to retrieve this data is by [querying the contract state](/sdk/resources/tools/typegen/state-queries/). -This requires a RPC endpoint of an archival Ethereum node, but we do not need to add one here: processor will reuse the endpoint we [supplied in part one](../step-one-indexing-transfers/#configuring-the-data-filters) of the tutorial for use in [RPC ingestion](/sdk/resources/basics/unfinalized-blocks). +This requires a RPC endpoint of an archival Ethereum node, but we do not need to add one here: processor will reuse the endpoint we [supplied in part one](../step-one-indexing-transfers/#configuring-the-data-filters) of the tutorial for use in [RPC ingestion](/sdk/resources/unfinalized-blocks). The next step is to prepare for retrieving and parsing the metadata proper. For this, we need to understand the protocols used in the URIs and the structure of metadata JSONs. To learn that, we retrieve and inspect some URIs ahead of the main squid sync. The most straightforward way to achieve this is by adding the following to the batch handler: ```diff title="src/main.ts" @@ -151,7 +151,7 @@ interface PartialToken { } ``` -Here, `PartialToken` stores the incomplete `Token` information obtained purely from blockchain events and function calls, before any [state queries](/sdk/resources/tools/typegen/state-queries/) or enrichment with [external data](/sdk/resources/basics/external-api/). +Here, `PartialToken` stores the incomplete `Token` information obtained purely from blockchain events and function calls, before any [state queries](/sdk/resources/tools/typegen/state-queries/) or enrichment with [external data](/sdk/resources/external-api/). The function `completeTokens()` is responsible for filling `Token` fields that are missing in `PartialToken`s. This involves IO operations, so both the function and its caller `createTokens()` have to be asynchronous. The functions also require a batch context for state queries and logging. We modify the `createTokens()` call in the batch handler to accommodate these changes: ```diff processor.run(new TypeormDatabase(), async (ctx) => { diff --git a/docs/sdk/tutorials/bayc/step-two-deriving-owners-and-tokens.md b/docs/sdk/tutorials/bayc/step-two-deriving-owners-and-tokens.md index 94448804..f114b593 100644 --- a/docs/sdk/tutorials/bayc/step-two-deriving-owners-and-tokens.md +++ b/docs/sdk/tutorials/bayc/step-two-deriving-owners-and-tokens.md @@ -99,7 +99,7 @@ Note how the entities we define form an acyclic dependency graph: As a consequence, the creation of entity instances must proceed in a [particular order](https://en.wikipedia.org/wiki/Topological_sorting). Squids usually use small graphs like this one, and in these the order can be easily found manually (e.g. `Owner`s then `Token`s then `Transfer`s in this case). We will assume that it can be hardcoded by the programmer. -Further, at each step we will [process the data for the whole batch](/sdk/resources/basics/batch-processing/) instead of handling the items individually. This is crucial for achieving a good syncing performance. +Further, at each step we will [process the data for the whole batch](/sdk/resources/batch-processing/) instead of handling the items individually. This is crucial for achieving a good syncing performance. With all that in mind, let's create a batch processor that generates and persists all of our entities: diff --git a/docs/sdk/tutorials/frontier-evm.md b/docs/sdk/tutorials/frontier-evm.md index cf089727..9bce1eb4 100644 --- a/docs/sdk/tutorials/frontier-evm.md +++ b/docs/sdk/tutorials/frontier-evm.md @@ -100,7 +100,7 @@ The results will be stored at `src/abi`. One module will be generated for each A Subsquid SDK provides users with the [`SubstrateBatchProcessor` class](/sdk). Its instances connect to [Subsquid Network](/subsquid-network/overview) gateways at chain-specific URLs, to get chain data and apply custom transformations. The indexing begins at the starting block and keeps up with new blocks after reaching the tip. -`SubstrateBatchProcessor`s [expose methods](/sdk/reference/processors/substrate-batch) that "subscribe" them to specific data such as Substrate events and calls. There are also [specialized methods](/sdk/resources/substrate/frontier-evm) for subscribing to EVM logs and transactions by address. The actual data processing is then started by calling the `.run()` function. This will start generating requests to the Subsquid Network gateway for [*batches*](/sdk/resources/basics/batch-processing) of data specified in the configuration, and will trigger the callback function, or *batch handler* (passed to `.run()` as second argument) every time a batch is returned by the gateway. +`SubstrateBatchProcessor`s [expose methods](/sdk/reference/processors/substrate-batch) that "subscribe" them to specific data such as Substrate events and calls. There are also [specialized methods](/sdk/resources/substrate/frontier-evm) for subscribing to EVM logs and transactions by address. The actual data processing is then started by calling the `.run()` function. This will start generating requests to the Subsquid Network gateway for [*batches*](/sdk/resources/batch-processing) of data specified in the configuration, and will trigger the callback function, or *batch handler* (passed to `.run()` as second argument) every time a batch is returned by the gateway. It is in this callback function that all the mapping logic is expressed. This is where chain data decoding should be implemented, and where the code to save processed data on the database should be defined. diff --git a/docs/sdk/tutorials/ink.md b/docs/sdk/tutorials/ink.md index 1b5d8494..23a971ee 100644 --- a/docs/sdk/tutorials/ink.md +++ b/docs/sdk/tutorials/ink.md @@ -190,7 +190,7 @@ export type ProcessorContext = DataHandlerContext ## Define the batch handler -Once requested, the events can be processed by calling the `.run()` function that starts generating requests to Subsquid Network for [*batches*](/sdk/resources/basics/batch-processing) of data. +Once requested, the events can be processed by calling the `.run()` function that starts generating requests to Subsquid Network for [*batches*](/sdk/resources/batch-processing) of data. Every time a batch is returned by the Network, it will trigger the callback function, or *batch handler* (passed to `.run()` as second argument). It is in this callback function that all the mapping logic is expressed. This is where chain data decoding should be implemented, and where the code to save processed data on the database should be defined. diff --git a/docs/sdk/tutorials/substrate.md b/docs/sdk/tutorials/substrate.md index 2af9cd99..26051e83 100644 --- a/docs/sdk/tutorials/substrate.md +++ b/docs/sdk/tutorials/substrate.md @@ -191,7 +191,7 @@ type Fields = SubstrateBatchProcessorFields export type ProcessorContext = DataHandlerContext ``` This creates a processor that - - Uses Subsquid Network as its main data source and a chain RPC for [real-time updates](/sdk/resources/basics/unfinalized-blocks). URLs of the Subsquid Network gateways are available on [this page](/subsquid-network/reference/substrate-networks) and via [`sqd gateways`](/squid-cli/gateways). See [this page](/sdk/reference/processors/substrate-batch/general) for the reference on data sources configuration; + - Uses Subsquid Network as its main data source and a chain RPC for [real-time updates](/sdk/resources/unfinalized-blocks). URLs of the Subsquid Network gateways are available on [this page](/subsquid-network/reference/substrate-networks) and via [`sqd gateways`](/squid-cli/gateways). See [this page](/sdk/reference/processors/substrate-batch/general) for the reference on data sources configuration; - [Subscribes](/sdk/reference/processors/substrate-batch/data-requests) to `Market.FileSuccess`, `Swork.JoinGroupSuccess` and `Swork.WorksReportSuccess` events emitted at heights starting at 583000; - Additionally subscribes to calls that emitted the events and the corresponding extrinsics; - [Requests](/sdk/reference/processors/substrate-batch/field-selection) the `hash` data field for all retrieved extrinsics and the `timestamp` field for all block headers. @@ -200,7 +200,7 @@ We also export the `ProcessorContext` type to be able to pass the sole argument ## Define the batch handler -Squids [batch process](/sdk/resources/basics/batch-processing) chain data from multiple blocks. Compared to the [handlers](/sdk/resources/basics/batch-processing/#migrate-from-handlers) approach this results in a much lower database load. Batch processing is fully defined by processor's [batch handler](/sdk/reference/processors/architecture/#processorrun), the callback supplied to the `processor.run()` call at the entry point of each processor (`src/main.ts` by convention). +Squids [batch process](/sdk/resources/batch-processing) chain data from multiple blocks. Compared to the [handlers](/sdk/resources/batch-processing/#migrate-from-handlers) approach this results in a much lower database load. Batch processing is fully defined by processor's [batch handler](/sdk/reference/processors/architecture/#processorrun), the callback supplied to the `processor.run()` call at the entry point of each processor (`src/main.ts` by convention). We begin defining our batch handler by importing the entity model classes and Crust event types that we generated in previous sections. We also import the processor and its types: diff --git a/docs/solana-indexing/sdk/solana-batch/context-interfaces.md b/docs/solana-indexing/sdk/solana-batch/context-interfaces.md index 2288b643..a4f66605 100644 --- a/docs/solana-indexing/sdk/solana-batch/context-interfaces.md +++ b/docs/solana-indexing/sdk/solana-batch/context-interfaces.md @@ -43,7 +43,7 @@ The exact fields available in each data item type are inferred from the `setFiel -## The SQD GraphQL server +## OpenReader -The [SQD GraphQL server](/sdk/reference/openreader-server) is a GraphQL server developed by the SQD team. Although still supported, it's not recommeded for new PostgreSQL-powered projects due to its [known issues](/sdk/reference/openreader-server/overview/#known-issues), especially for APIs implementing GraphQL subscriptions. +[OpenReader](/sdk/reference/openreader-server) is a GraphQL server developed by the SQD team. Although still supported, it's not recommeded for new PostgreSQL-powered projects due to its [known issues](/sdk/reference/openreader-server/overview/#known-issues), especially for APIs implementing GraphQL subscriptions. -The server uses the [schema file](/sdk/reference/schema-file) to produce its [core API](/sdk/reference/openreader-server/api) that can be extended with [custom resolvers](/sdk/reference/openreader-server/configuration/custom-resolvers). Extra features include [DoS protection](/sdk/reference/openreader-server/configuration/dos-protection). +The server uses the [schema file](/sdk/reference/schema-file) to produce its [core API](/sdk/reference/openreader-server/api) that can be extended with [custom resolvers](/sdk/reference/openreader-server/configuration/custom-resolvers). Extra features include [DoS protection](/sdk/reference/openreader-server/configuration/dos-protection) and [caching](/sdk/reference/openreader-server/configuration/caching). From e2a3d21adac10a4daa2ab0181519b94c4d176e70 Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Tue, 10 Sep 2024 23:47:02 +0900 Subject: [PATCH 15/16] Fixing a couple of broken links modified: docs/overview.mdx modified: docs/sdk/how-to-start/squid-from-scratch.mdx --- docs/overview.mdx | 2 +- docs/sdk/how-to-start/squid-from-scratch.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/overview.mdx b/docs/overview.mdx index 5ccee7db..a24d862b 100644 --- a/docs/overview.mdx +++ b/docs/overview.mdx @@ -51,7 +51,7 @@ For real-time use cases such as app-specific APIs use [Squid SDK](/sdk): it'll u - [High-level libraries](/sdk/reference/processors) for extracting and filtering the Subsquid Network data in what can be though of as Extract-Transform-Load (ETL) pipelines - [Ergonomic tools](/sdk/resources/tools/typegen) for decoding and normalizing raw data and efficiently accessing [network state](/sdk/resources/tools/typegen/state-queries) - Pluggable [data sinks](/sdk/reference/store) to save data into Postgres, files (local or s3) or BigQuery -- An expressive [GraphQL server](/sdk/resources/serving-graphql#the-sqd-graphql-server) with a schema-based [config](/sdk/reference/schema-file) +- An expressive [GraphQL server](/sdk/resources/serving-graphql#openreader) with a schema-based [config](/sdk/reference/schema-file) - Seamless handling of [unfinalized blocks and chain reorganizations](/sdk/resources/unfinalized-blocks) for real-time data ingestion - rapid data extraction and decoding [for local analytics](/sdk/tutorials/file-csv) diff --git a/docs/sdk/how-to-start/squid-from-scratch.mdx b/docs/sdk/how-to-start/squid-from-scratch.mdx index d715ba3f..eee4bddb 100644 --- a/docs/sdk/how-to-start/squid-from-scratch.mdx +++ b/docs/sdk/how-to-start/squid-from-scratch.mdx @@ -24,7 +24,7 @@ We also assume the following choice of _optional_ packages: * `@subsquid/evm-typegen` - for decoding Ethereum data and useful constants such as event topic0 values * `@subsquid/evm-abi` - as a peer dependency for the code generated by `@subsquid/evm-typegen` -* `@subsquid/graphql-server` / [OpenReader](/sdk/resources/openreader-server) +* `@subsquid/graphql-server` / [OpenReader](/sdk/reference/openreader-server) To make the indexer, follow these steps: From 93d72d9649e020c20ee03a8a951d5b4f00947055 Mon Sep 17 00:00:00 2001 From: abernatskiy Date: Wed, 11 Sep 2024 08:35:20 +0900 Subject: [PATCH 16/16] Hasura docs in full modified: docs/sdk/how-to-start/squid-development.mdx modified: docs/sdk/resources/serving-graphql.md new file: docs/sdk/resources/tools/hasura-configuration-web-ui-import-export.png new file: docs/sdk/resources/tools/hasura-configuration.md --- docs/sdk/how-to-start/squid-development.mdx | 13 ++- docs/sdk/resources/serving-graphql.md | 8 +- ...ura-configuration-web-ui-import-export.png | Bin 0 -> 55539 bytes .../resources/tools/hasura-configuration.md | 89 ++++++++++++++++++ 4 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 docs/sdk/resources/tools/hasura-configuration-web-ui-import-export.png create mode 100644 docs/sdk/resources/tools/hasura-configuration.md diff --git a/docs/sdk/how-to-start/squid-development.mdx b/docs/sdk/how-to-start/squid-development.mdx index 8e339edf..658651f5 100644 --- a/docs/sdk/how-to-start/squid-development.mdx +++ b/docs/sdk/how-to-start/squid-development.mdx @@ -464,7 +464,7 @@ At `src/main.ts`, change the [`Database`](/sdk/resources/persisting-data/overvie ``` -1. Define the schema of the database (and the [core schema of the GraphQL API](/sdk/reference/openreader-server/api) if it is used) at [`schema.graphql`](/sdk/reference/schema-file). +1. Define the schema of the database (and the [core schema of the OpenReader GraphQL API](/sdk/reference/openreader-server/api) if it is used) at [`schema.graphql`](/sdk/reference/schema-file). 2. Regenerate the TypeORM model classes with ```bash @@ -626,6 +626,10 @@ The alternative is to do the same steps in a different order: 5. [Retrieve any external data](#external-data) if necessary 6. [Add the persistence code for the transformed data](#batch-handler-persistence) +## GraphQL options + +[Store your data to PostgreSQL](/sdk/resources/persisting-data/typeorm), then consult [Serving GraphQL](/sdk/resources/serving-graphql) for options. + ## Scaling up If you're developing a large squid, make sure to use [batch processing](/sdk/resources/batch-processing) throughout your code. @@ -640,5 +644,8 @@ For complete examples of complex squids take a look at the [Giant Squid Explorer ## Next steps -* Deploy your squid [on own infrastructure](/sdk/resources/self-hosting) or to [Subsquid Cloud](/cloud) -* If your squid serves an [OpenReader](/sdk/reference/openreader-server/)-compatible API, consult [core API reference](/sdk/reference/openreader-server/api) while writing your frontend application. +* Learn about [batch processing](/sdk/resources/batch-processing). +* Learn how squid deal with [unfinalized blocks](/sdk/resources/unfinalized-blocks). +* [Use external APIs and IPFS](/sdk/resources/external-api) in your squid. +* See how squid should be set up for the [multichain setting](/sdk/resources/multichain). +* Deploy your squid [on own infrastructure](/sdk/resources/self-hosting) or to [Subsquid Cloud](/cloud). diff --git a/docs/sdk/resources/serving-graphql.md b/docs/sdk/resources/serving-graphql.md index b9b1855b..9608d20c 100644 --- a/docs/sdk/resources/serving-graphql.md +++ b/docs/sdk/resources/serving-graphql.md @@ -31,9 +31,13 @@ As per usual with PostGraphile installations, you can freely extend it with plug 2. **Run a dedicated Hasura instance for serving the data just from your squid.** - A complete example implementing this approach is available in [this repository](https://github.com/subsquid-labs/squid-hasura-example). More TBA. + A complete example implementing this approach is available in [this repository](https://github.com/subsquid-labs/squid-hasura-example). Here's how it works: - + * Locally, Hasura runs in a [Docker container](https://github.com/subsquid-labs/squid-hasura-example/blob/70bb6d703dc90c1bb00b47f3fef7f388ab54e565/docker-compose.yml#L14C1-L28C20). In the Cloud it is managed via the [Hasura addon](/cloud/reference/hasura). + * Hasura metadata is shared among all squid instances by means of the [Hasura configuration tool](/sdk/resources/tools/hasura-configuration). The tool can automatically create an initial configuration based on your [TypeORM models](/sdk/reference/schema-file/intro/#typeorm-codegen), then persist any changes you might make with the web GUI and metadata exports. + * Admin authentication secret is set via the `HASURA_GRAPHQL_ADMIN_SECRET`. The variable is set in `.env` locally and from a [secret](/cloud/resources/env-variables/#secrets) in Cloud deployments. + + See the [configuration tool page](/sdk/resources/tools/hasura-configuration) and the [repo readme](https://github.com/subsquid-labs/squid-hasura-example#readme) for more details. ## OpenReader diff --git a/docs/sdk/resources/tools/hasura-configuration-web-ui-import-export.png b/docs/sdk/resources/tools/hasura-configuration-web-ui-import-export.png new file mode 100644 index 0000000000000000000000000000000000000000..1a151b45f7b1331fb4175f8737dc612b7c0c47db GIT binary patch literal 55539 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 +Here's how + +1. Finalize any edits to [`schema.graphql`](/sdk/reference/schema-file) + +2. Update the TypeScript code of your models with + ```bash + npx squid-typeorm-codegen + ``` + +3. Compile your models with + ```bash + npm run build + ``` + +4. Regenerate your [DB migrations](/sdk/resources/persisting-data/typeorm/#database-migrations) with a clean database to make sure they match your updated schema. + ```bash + docker compose down + docker compose up -d + rm -r db + npm squid-typeorm-migration generate + ``` + +You can turn off your database after doing that - Hasura configuration tool does not use it to make its initial configuration + + + +When done, run +```bash +npx squid-hasura-configuration regenerate +``` +The generated configuration will be available at `hasura_metadata.json`. It enables: +- tracking all tables that correspond to [schema entities](/sdk/reference/schema-file/entities); +- `SELECT` permissions for the `public` (or `$HASURA_GRAPHQL_UNAUTHORIZED_ROLE` if it is defined) role for all columns in these tables; +- tracking all [entity relationships](/sdk/reference/schema-file/entity-relations). + +## Applying the configuration + +Make sure your database is up, your Hasura instance is connected to it and the schema is up to date. If necessary, apply the migrations: +```bash +npx squid-typeorm-migration apply +``` + +When done, you can apply the generated config with +```bash +npx squid-hasura-configuration apply +``` +or import it using the _Settings > Metadata Actions > Import metadata_ function of the web GUI. + +## Persisting configuration changes + +:::warning +Regenerating `hasura_metadata.json` removes any modifications you might have made via metadata exporting. So, it is advisable that you finalize your schema before you begin any manual API fine-tuning. +::: + +When running a squid with a dedicated Hasura instance you will notice that squid resetting operations (`docker compose down; docker compose up -d` and `sqd deploy -r`) restore your Hasura API to its non-configured state. As you develop your API further you may want to persist your changes. `squid-hasura-configuration` helps with that by being compatible with the _Settings > Metadata Actions > Import/Export metadata_ functions of the web GUI. + +![Web UI import and export](hasura-configuration-web-ui-import-export.png) + +Any extra configuration you may make via the web GUI or [Hasura metadata API](https://hasura.io/docs/2.0/api-reference/metadata-api/index) can be persisted by exporting the metadata to `hasura_metadata.json` via the _Export metadata_ function, then applying it to blank Hasura instances with +```bash +npx squid-hasura-configuration apply +``` + +## Example + +See [this repo](https://github.com/subsquid-labs/squid-hasura-example).