Skip to content

[RFC] Changes to the existing API and workflow #115

@danielrearden

Description

@danielrearden

There’s a number of issues with the library in its current form:

  • Reliance on schema directives means the library is incompatible with code-first libraries like nexus, type-graphql or graphql-compose
  • Transforming the schema, whether done through schema directives or some other mechanism (like annotations), makes it hard to work with other tools like GraphQL Code Generator or IDE plugins.
  • Exposing model details in the type definitions tightly couples the schema with the underlying data sources and the library itself. Migrating away from Sqlmancer would require not only changing the resolvers but changing all the type definitions as well.
  • Exposing model details in the type definitions means we’re forced to utilize code generation -- the client’s type cannot just be inferred by TypeScript
  • A schema-first approach means that if additional data models needed for internal use, they have to be exposed first as GraphQL types that are later removed from the schema using the @private directive

What we could do differently:

  • Remove all schema directives and use a single, standalone configuration object that includes all data model details.
  • The data models defined inside the configuration object would resemble more traditional ORM data models and become the “source of truth” for the application. “Base” type definitions could be generated from the models as a convenience but type definitions could also be written by hand. Similarly, migration files could also be generated to keep the database in sync with the models.
  • The data models could still include information specific to their respective GraphQL types, like “virtual” and paginated fields

The new workflow would look something like this:

  • Write data models
  • (Optionally) generate and run migrations based on the models
  • (Optionally) generate type definitions from the models
  • Write any remaining type definitions for the schema
  • Instantiate client using only config object/data models and use it to write the resolvers
  • Build the schema however you normally build your schema, with no extra steps

The API of the client itself would stay the same. When the data models change, the base type definitions can be regenerated and a new migration file can be created to sync the database.

In some ways, this workflow would be potentially more complicated than the existing one. Adding a where or orderBy argument to a field would require more steps than just sticking a directive on a field. On the other hand, utilizing a configuration object means we can leverage TypeScript for type checking and autocompletion, making it less error prone than stumbling through trying to add directives with the correct arguments.

Any "compliant" schema will work with the client, regardless of how it's created, opening up the possibility to use Sqlmancer with code-first schema libraries or even writing schemas using the core graphql module. The code generation feature could be expanded in the future to include generating code for these libraries without having to create additional, Sqlmancer-specific plugins for them.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions