Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow client to be extended with custom controllers #240

Merged
merged 6 commits into from
Jun 10, 2024

Conversation

fdionisi
Copy link
Member

@fdionisi fdionisi commented Jun 7, 2024

Description

EdcConnectorClient is now able to be extended by providing a custom EdcController implementation when building it.

For this purpose, EdcConnectorClient.Builder has a new method use which takes a string property name as first argument and a EdcController class as second.

/cc @psalmry @selimbens

Closes #213

How to test it

import {EdcConnectorClient, EdcController} from "@think-it-labs/edc-connector-client"

class Foo extends EdcController {
  bar() {
    return true
  }
}

console.assert(new EdcConnectorClient.Builder().use("foo", Foo).build().bar() == true)

Approach

In the first place, this PR adds a new class: EdcController.
EdcController is a base implementation of a controller, which defines:

  1. how a controller is constructed, and
  2. the inner and context fields the controller exposes

This class is necessary for defining a common base type and ensure type safety; as controllers will be lazily instanciated, we need a shared interface.

// src/edc-controller.ts
import { EdcConnectorClientContext } from "./context";
import { Inner } from "./inner";

export class EdcController {
  protected inner: Inner;
  protected context?: EdcConnectorClientContext;

  constructor(inner: Inner, context?: EdcConnectorClientContext) {
    this.inner = inner;
    this.context = context;
  }
}

Having a base class it allows us to implement the middleware-like extension. So, the client's Builder class now include a use method, which takes a property name and a EdcController-extended class, adding it to the instance upon build.

// src/client.ts
export class EdcConnectorClient {
  static Builder = class Builder<Controllers = {}> {

    // ...

    use<K extends string, C extends EdcController>(
      key: K,
      Controller: Class<C>,
    ): Builder<Controllers & Record<K, C>> {
      Object.defineProperty(this.#instance, key, {
        get() {
          return new Controller(
            this.#inner,
            this.createContext(
              this.#apiToken!,
              this.#addresses,
            ),
          );
        },
        enumerable: true,
        configurable: false,
      });

      return this;
    }
  }
}

With the new controller class and builder method, it is now possible to extend the EdcConnectorClient as showed above in the "How to test it" section

Open Questions

Types' ergonomics

Currently the library exports EdcConnectorClient class and the EdcConnectorClientType<T>. The latter one allows us to define typings for an extended client.

let myClient: EdcConnectorClientType<{ foo: FooController }> | undefiend;

I'm wondering if it would make sense to rename these types to be more elegant (yeah, very subjective 😅).

  • EdcConnectorClient -> Client
  • EdcConnectorContext -> Context
  • EdcConnectorClientType<T> -> EdcConnectorClient<T>

This change would be a breaking change though - which is not too bad, as we are still pre-1.0.0, but still a bit of a pain.

Nevertheless, this update should be part of a follow up PR.

@fdionisi fdionisi requested a review from ndr-brt June 7, 2024 15:56
@fdionisi fdionisi merged commit e923554 into main Jun 10, 2024
1 check passed
@fdionisi fdionisi deleted the feat/allow-client-extension branch June 10, 2024 13:52
@fdionisi fdionisi added the enhancement New feature or request label Jun 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow client to be extended with custom-made controllers
2 participants