Skip to content

Commit

Permalink
add typescript example
Browse files Browse the repository at this point in the history
  • Loading branch information
zapaz committed Dec 1, 2022
1 parent aff38e2 commit 97ededf
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 59 deletions.
69 changes: 50 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,23 @@ This is due, by nature, to the slowness of metadata fetching that can't be done

To tackle this problem, work by The Graph Core Development team on « File data sources » is under process.

### Solution
### TheRelay Solution

TheRelay enables today the enrichment of NFT subgraphs, in a centralized / hosted way.

TheRelay can only enrich NFTs having ERC721Medata option, i.e. with tokenURI, that is nevertheless most of NFTs, but not all.

TheRelay acts a proxy between your GraphQL query and TheGraph network.

TheRelay stores json metadata on IPFS if an IPFS server is available, either stores it on it's local filesystem.
TheRelay acts a json proxy between your GraphQL query and TheGraph network.
TheRelay stores json metadata on IPFS if an IPFS server is available or stores it on it's local filesystem.

When "File Data Sources" will be deployed to TheGraph, this will be also possible in a decentralized way.

### Basic example

'wighawag/eip721-subgraph' will be used as the reference subgraph to query

For exemple this query
For example this query :

```
```graphql
{
tokens(first: 1, skip: 2000) {
id
Expand All @@ -47,7 +45,7 @@ https://api.thegraph.com/subgraphs/name/wighawag/eip721-subgraph

returns :

```
```json
{
"tokens": [
{
Expand All @@ -56,24 +54,23 @@ returns :
}
]
}
```

You can replay it with
You can replay it with :

```
```shell
pnpm thequery wighawag/eip721-subgraph token
```

Same query sent via TheRelay
Same query sent via TheRelay :

```
http:127.0.0.1:8080/subgraphs/name/wighawag/eip721-subgraph/graphq
```

returns :

```
```json
[
{
"id": "0x00000000001ba87a34f0d3224286643b36646d81_2610",
Expand Down Expand Up @@ -126,12 +123,43 @@ returns :
]
```

You can replay it with
You can replay it with :

```
```shell
pnpm thequery wighawag/eip721-subgraph token --therelay
```

A [TypeScript code example](tests/simpleQuery.ts) is as follows :

```typescript
import { theRelayStart, theRelayStop } from "@lib/theRelay";
import { queryGetByName, queryTheGraph, queryTheRelay } from "@lib/query/query";

const subgraphName = "wighawag/eip721-subgraph";
const endpoint = `https://api.thegraph.com/subgraphs/name/${subgraphName}`;

const main = async () => {
// Get basic token query
const queryToken = queryGetByName(subgraphName, "token");

// Query TheGraph directly
console.log("TheGraph", await queryTheGraph(endpoint, queryToken));

{
// Start TheRelay locally
await theRelayStart();

// Query TheGraph via TheRelay
console.log("TheRelay", await queryTheRelay(endpoint, queryToken));

// Stop TheRelay
await theRelayStop();
}
};

main().catch(console.error);
```

### Features

#### Available
Expand All @@ -140,30 +168,33 @@ pnpm thequery wighawag/eip721-subgraph token --therelay
- on each NFT query, on each NFT retrieved :
- NFT metadata read from IPFS (or filesystem) if available
- else metadata fetched from the tokenURI
- then saved to filesystem
- and saved to IPFS if available
- then optional archive to IPFS
- then optional save to filesystem
- start/stop/status commands available
- can be run as a daemon or inside TheQuery client
- can be run on local desktop or remote server
- manage fetching errors
- manage a database of chainId/collectionAddress/tokenID to metadata IPFS CID
- manage metadata cache on filesystem (locally or remotely)
- TheQuery : cli framework
- TheGraph NFT queries : with both [wighawag](https://github.com/wighawag/eip721-subgraph/blob/master/schema.graphql) and [amxx](https://github.com/OpenZeppelin/openzeppelin-subgraphs/blob/main/generated/erc721.schema.graphql) NFT schemas
- TheGraph NFT queries enriched with metadata via TheRelay (for both NFT schemas)
- Some unstable http://therelay.kredeum.com server
- GraphQL utility
- IFPS utility
- Ready for multi blockchain queries

#### Roadmap

- TheRelay
- manage fetching / json errors
- manage json errors
- manage inline metadata
- setup a stable remote server, with https, with IPFS pinning service
- transform TheRelay from a json relay to a real graphQL relay (then accessible via [GraphiQL](https://github.com/graphql/graphiql/tree/main/packages/graphiql))
- TheQuery
- full support of ENV parameters
- develop and run indexing scripts, to be applied on various blockchains to store / pin IPFS
- target specific position of tokenURI (currently only nfts/uri or nfts/tokenURI in TheGraph results)
- multi blockchain queries (with also chain identification when only monochain)

### Usage

Expand Down
2 changes: 1 addition & 1 deletion lib/metadata/metadataSave.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const metadataSaveToFile = (json: string, cid: string, chainId: number, address:


const metadataSave = async (jsonObject: unknown, address: string, tokenID: string, chainId = 0): Promise<string> => {
const jsonString = JSON.stringify(jsonObject, null, " ");
const jsonString = JSON.stringify(jsonObject, null, 2);
let cid: string;

// Add json to IPFS
Expand Down
16 changes: 16 additions & 0 deletions lib/query/query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { queryGraphQL, queryGraphQLResponse } from "@lib/query/queryGraphQL";
import { queryGetVariables } from "@lib/query/queryGetVariables";
import {
queryGetPreprocessed, queryGetByFile, queryGetByPath, queryGetByName,
queryGetTheGraphEndpoint, queryGetSubgraphDescription
} from "@lib/query/queryGet";

import { queryTheRelay } from "@lib/query/queryTheRelay";

const queryTheGraph = queryGraphQL;

export {
queryGetPreprocessed, queryGetByFile, queryGetByPath, queryGetByName,
queryGetTheGraphEndpoint, queryGetSubgraphDescription, queryGetVariables,
queryTheGraph, queryTheRelay, queryGraphQL, queryGraphQLResponse
};
6 changes: 3 additions & 3 deletions lib/query/queryGraphQL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ const queryGraphQL = async (endpoint: string, query: string, params?: TheQueryPa
if (params?.verbose) console.info(`${endpoint}\n${query}`);

const resp = await queryGraphQLResponse(endpoint, query, params?.verbose);
// console.log("queryGraphQL", JSON.stringify(resp, null, " "));
// console.log("queryGraphQL", JSON.stringify(resp, null, 2));

// if (resp.errors) throw `GRAPHQL ERROR, ${JSON.stringify(resp.errors, null, " ")}`;
// if (resp.errors) throw `GRAPHQL ERROR, ${JSON.stringify(resp.errors, null, 2)}`;

const json = JSON.stringify(resp.data || {}, null, " ");
const json = JSON.stringify(resp.data || {}, null, 2);

// console.log("queryGraphQL", json);
return json;
Expand Down
11 changes: 0 additions & 11 deletions lib/query/queryTheGraph.ts

This file was deleted.

5 changes: 3 additions & 2 deletions lib/query/queryTheRelay.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { RequestInit } from "node-fetch";
import { TheRelayParamsType, THERELAY_STARTING } from "@lib/types";
import { TheRelayParamsType, THERELAY_PARAMS_DEFAULT, THERELAY_STARTING } from "@lib/types";

import { fetchJson } from "@lib/fetch/fetchJson";
import { theRelayStart, theRelayStop } from "@lib/theRelay";

const queryTheRelay = async (endpoint: string, query: string, params: TheRelayParamsType): Promise<unknown> => {
const queryTheRelay = async (endpoint: string, query: string, params: TheRelayParamsType = THERELAY_PARAMS_DEFAULT): Promise<unknown> => {
if (params?.verbose) console.info(`${endpoint}\n${query}`);

const config: RequestInit = {
Expand All @@ -24,6 +24,7 @@ const queryTheRelay = async (endpoint: string, query: string, params: TheRelayPa
if (params?.therelay) status = await theRelayStart(params);

const json = await fetchJson(url, config, false);
if (params.verbose) console.info(url);

if (status == THERELAY_STARTING) await theRelayStop();

Expand Down
7 changes: 4 additions & 3 deletions lib/theRelay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Response } from "node-fetch";
import express from "express";
import {
THERELAY_URL, THERELAY_RUNNING, THERELAY_STOPPING,
THERELAY_STOPPED, THERELAY_STARTING, THERELAY_ERROR, TheRelayParamsType
THERELAY_STOPPED, THERELAY_STARTING, THERELAY_ERROR, TheRelayParamsType, THERELAY_URL_DEFAULT, THERELAY_PARAMS_DEFAULT
} from "@lib/types";
import fetch from "node-fetch";
import morgan from "morgan";
Expand Down Expand Up @@ -63,7 +63,7 @@ app.post("*", async (req, res): Promise<void> => {

await metadataAdds(nfts, chainId);

const jsonMetadata = JSON.stringify(nfts, null, " ");
const jsonMetadata = JSON.stringify(nfts, null, 2);
// console.log("TheRelay", jsonMetadata);

res.json(jsonMetadata);
Expand Down Expand Up @@ -93,7 +93,8 @@ const theRelayStop = async (): Promise<string> => {
return message;
};

const theRelayStart = async (params: TheRelayParamsType): Promise<string> => {

const theRelayStart = async (params: TheRelayParamsType = THERELAY_PARAMS_DEFAULT): Promise<string> => {
theRelayParams = params;
if (theRelayParams.verbose) console.info("TheRelay params", theRelayParams);

Expand Down
3 changes: 2 additions & 1 deletion lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const THERELAY_API_DEFAULT = "http://127.0.0.1:5001";

const THERELAY_URL_DEFAULT = "http://127.0.0.1:4004";
const THERELAY_URL = process.env.THERELAY_URL || THERELAY_URL_DEFAULT;
const THERELAY_PARAMS_DEFAULT = { therelay: true, therelayUrl: THERELAY_URL_DEFAULT, save: true, ipfs: false, verbose: false };

const THERELAY_RUNNING = "RUNNING";
const THERELAY_STOPPING = "STOPPING";
Expand Down Expand Up @@ -65,7 +66,7 @@ type TheQueryType = {
}

export {
PACKAGE_VERSION, THERELAY_API_DEFAULT,
PACKAGE_VERSION, THERELAY_API_DEFAULT, THERELAY_PARAMS_DEFAULT,
IPFS_RUNNING, IPFS_STOPPED,
THERELAY_URL, THERELAY_URL_DEFAULT,
THERELAY_RUNNING, THERELAY_STOPPING, THERELAY_STOPPED, THERELAY_ERROR, THERELAY_STARTING
Expand Down
26 changes: 13 additions & 13 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Different scripts are available :

and generic utilities :

1. GraphQL script : to query GraphQL endpoints in pure GraphQL
1. IPFS script : to manage IPFS files
1. GraphQL script : to query GraphQL endpoints in pure GraphQL

## Prerequisites

Expand All @@ -19,15 +19,15 @@ and generic utilities :

## Installation

```
```shell
pnpm install
```

## TheRelay

TheRelay is a service that can be run as a daemon on your local machine or on a remote server

```
```text
Usage: pnpm therelay [options] [command]
Manage TheRelay daemon
Expand Down Expand Up @@ -59,7 +59,7 @@ TheQuery use pre-defined queries, located in `queries` directory

Metadata retreived by the TheRelay is stored on IPFS, and in case IPFS is not available, also stores metadata on the local filesystem of TheRelay machine in `datas` directory

```
```text
Usage: pnpm thequery [options] <graphName> <queryName>
Query TheGraph, transparent mode or via TheRelay proxy (-r)
Expand All @@ -83,13 +83,13 @@ Options:

Query example (without TheRelay) :

```
```shell
pnpm thequery wighawag/eip721-subgraph tokens
```

Query example with TheRelay :

```
```shell
pnpm thequery wighawag/eip721-subgraph tokens -r
```

Expand All @@ -98,19 +98,19 @@ Default local relay is http://127.0.0.1:4004 (launched for the time of the query

Query examples with parameters :

```
```shell
pnpm thequery wighawag/eip721-subgraph my-tokens --owner-address 0xa6d856e4e9b1d12f42687bcacd691ba48008d6c3 --verbose
```

```
```shell
pnpm thequery wighawag/eip721-subgraph collection --collection-address 0x00000000001ba87a34f0d3224286643b36646d81 -r
```

### IPFS generic utility

_To run IFPS command you should have a IPFS server running locally or remotely_

```
```text
Usage: pnpm ipfs [options] [command]
IPFS commands
Expand All @@ -132,19 +132,19 @@ Commands:

Add to IPFS example :

```
```shell
pnpm ipfs add "TheRelay test"
```

Get from IPFS example :

```
```shell
pnpm ipfs cat bafybeidg3zkcudh4mvpaevcy3ezdmzsxuel6jgshl4rsu2h35672t3blvm
```

### GraphQL generic utility

```
```text
Usage: pnpm graphql [options] <endpoint> <queryPath> [queryParams]
Query Graphql, query whatever GraphQL service
Expand All @@ -160,6 +160,6 @@ Options:

Query example :

```
```shell
pnpm graphql https://api.thegraph.com/subgraphs/name/wighawag/eip721-subgraph wighawag/eip721-subgraph/tokens
```
3 changes: 1 addition & 2 deletions scripts/graphql.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#!/usr/bin/env ts-node

import { Command } from "commander";
import { queryGraphQL } from "@lib/query/queryGraphQL";
import { queryGraphQL, queryGetByPath } from "@lib/query/query";
import { TheQueryParamsType } from "@lib/types";
import { queryGetByPath } from "@lib/query/queryGet";

const main = async () => {
const program = new Command();
Expand Down
Loading

0 comments on commit 97ededf

Please sign in to comment.