Skip to content

[DRAFT] Web3API Client Type Extensions for plugins, API wrappers #314

@krisbitney

Description

@krisbitney

It is possible to allow plugin and API developers to extend the Web3API Client interface. In doing so, developers can provide abbreviated syntax, facilitate type checking, and facilitate IDE features like type suggestions and code auto-completion (e.g. intellisense).

From the end-user perspective, this:

const tokenData = await client.query<{
  fetchTokenData: Token;
}>({
  uri: ensUri,
  query: `
    query {
      fetchTokenData(
        chainId: $chainId
        address: $address
      )
    }
  `,
  variables: {
    chainId: chainId,
    address: address,
  },
});

Would become something like this:

const tokenData = client.uniswap.fetchTokenData(chainId, address);

This is syntactic sugar. Behind the scenes, client.query() would still be called.

Plugin developers can package their plugin to use the shortened syntax by default. API developers may need to write language-specific wrappers. This feature may be specific to languages like JavaScript/TypeScript, Kotlin, and others that offer this sort of type extension without the need for class extension/inheritance. Plugin and API developers could also use this approach to bundle custom redirects or other configuration.

This idea comes from Hardhat, which allows Hardhat plugin developers to extend their HardhatRuntimeEnvironment type. The TypeScript syntax to extend the type for the hardhat plugin I've been (slowly) working on looks something like this abridged code snippet:

declare module "hardhat/types/runtime" {
  export interface HardhatRuntimeEnvironment {
    web3api: {
      providers: {
        ipfs: string;
      };
      myFunction(arg1: string, arg2: number) => Promise<{ result: string; }>
    };
  }
}

Once that is done, features like type suggestions work immediately in my IDE.

Harhdat provides a hook that Hardhat plugin developers can use to assign values to the new properties. The hook runs when the HardhatRuntimeEnvironment object is instantiated:

extendEnvironment((hre) => {
  hre.web3api = {
    providers: {
      ipfs: "myProvider",
    },
    myFunction: async (arg1: string, arg2: number) => { return "result"; };
  };
});

Now I just import my hardhat plugin in my hardhat config file, and I can then call myFunction in other files like so:

import * as hre from "hardhat";
const result = hre.myFunction("arg1", 2);

Hardhat links:
Simple example on GitHub used for Plugin Developer boilerplate (analogous to our web3api templates)
Building Hardhat plugins
Extending the Hardhat Runtime Environment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions