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

Spike a graphql simulator #83

Closed
wants to merge 15 commits into from
Closed

Spike a graphql simulator #83

wants to merge 15 commits into from

Conversation

cowboyd
Copy link
Member

@cowboyd cowboyd commented Jul 6, 2021

This spikes a graphql simulator with envelope, express-graphql
playground, and using the starwars schema from the graphql-js examples

TODO

  • How is this going to work as plugin?

Comment on lines 1 to 3
export { schema } from './schema';
export { context } from './simulation/context';
export { scenarios } from './simulation/scenarios';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to export these from a module since the 'graphql' simulator accepts these options as dynamic imports.

It's a little undesirable to have this example schema in the 'graphql' simulator package itself.

Should we introduce a @simulacrum/graphql-starwars-schema package?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just @simulacrum/graphql-starwars since the simulator actually will run an entire graphql API. The idea being that if you could just do something like:

import { createSimulationServer } from '@simulacrum/server';
import { starwars }  from '@simulacrum/graphql-starwars';

export function createServer() {
  return createSimulationServer({ simulators: { starwars } });
}

Comment on lines 3 to 7
/**
* This is an example of a real store to accompany the schema.
* We can create a simulacrum store that matches the _shape_ of this one,
* and place it in context to run the schema as a simulation
*/
Copy link
Collaborator

@jgnieuwhof jgnieuwhof Jul 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This store isn't actually used anywhere in-code (we only wire-up / test the simulated store). It does seem to have some value, if only to illustrate the workflow of having a simulated store that matches the shape of the real one.

Any thoughts on whether we should remove this, or leave it here (and maybe add a simple test)?

Comment on lines 12 to 14
if (!result) {
console.warn(`export not found: "${JSON.stringify(options)}"`);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't entirely sure of the error handling strategy for these simulators; this should probably be improved?

@jgnieuwhof
Copy link
Collaborator

jgnieuwhof commented Jul 8, 2021

@cowboyd - this has been modularized / cleaned up, and now has some test coverage.

not entirely sure where to go from here; we've thrown around some ideas but it'd be nice to converge on something concrete.

@jgnieuwhof jgnieuwhof force-pushed the graphql-spike branch 2 times, most recently from 270911f to 6e74f3d Compare July 8, 2021 21:14
@jgnieuwhof
Copy link
Collaborator

jgnieuwhof commented Jul 9, 2021

To give an update on where this is at:

At the current moment, this PR includes a simple graphql simulator. The simulator accepts a schema, context, and scenarios from the consumer, since we can't make any assumptions about the context or scenarios expected by the schema. This means that the work is still on the consumer to ensure that the schema has everything that it needs.

To this end, an example starwars schema has been added, accompanied by a simulated store and corresponding scenarios. The test suite uses the starwars schema to validate the simulator wires things up correctly.

Next steps might include the following:

  • Allow consumers to specify which graph entity corresponds with the Person entity to allow the graphql simulator to work in conjunction with the auth0 simulator
  • Providing an option to enable dynamic data generation. This would eliminate the need for consumers to provide a simulated store and corresponding scenarios.

@jgnieuwhof
Copy link
Collaborator

jgnieuwhof commented Jul 9, 2021

Notes from a follow up discussion with @cowboyd:

Cross-service entity composition

The 'person' simulator creates people that exist independent of any other services running in simulation. These services need a way to augment their scenario with the entities from the 'person' simulator.

The following solution was discussed:

  • Each service should define and manage its own slice of the store
  • The 'person' service should publish a function that allows other service to subscribe to the creation of people
  • Services should not be able to subscribe to 'person' changes after scenarios have been initialized, since this would represent an unrealistic response to external changes

Store Ergonomics

The starwars simulation store has been created using the low-level store API provided by @effection/atom. This works, but is cumbersome when trying to perform CRUD operations on tabular data.

We should provide an API backed by the store that supports the CRUD operations that services (like the GraphQL service) typically need to perform.

Design TBD.

GraphQL Factories

The GraphQL schema determines the shape and relationships of the entities in the graph. We can use this information to create factories that help scenario authors create and mutate their simulated data.

While the schema can provide the shape of the data, it does not contain the information required to fully generate semantically correct data (ex. given type User { firstName: String } we want to generate a name, not just a string).

We need to either (or both):

  • allow consumers to specify generator functions for scalar fields
  • use something like https://github.com/google/intermock to auto-determine generator functions based on field names (this uses JSDoc annotations to specify faker generator functions)

GraphQL Dynamic Data Generation

Once we have GraphQL factories we should have the ability to respond to queries with auto-generated data. This can be very useful for rapid prototyping and demos. This should be presented as an option, since there are situations (such as testing) where consumers need to be very specific about the simulation's data set.

Running the GraphQL simulator in this mode would replace the schema's resolvers with ones that respond with dynamically generated data. This has the added bonus of eliminating the need for consumers to specify a simulation context and scenarios.

Auto-generated data should be stable (running the same query multiple times returns the same data).

The generated data should also have relational integrity; that is, entities that have back-references should result in data that also has back-references. Similar to factories this cannot be inferred by the shape of the schema alone; we will need to provide a way for consumers to specify relational cycles.

For example:

# Person.pet <-> Dog.guardian are inverses
# Person.pet <-> Dog.sitter are not
# This cannot be determined without consumer-specific metadata

type Person {
  pet: Dog
}

type Dog {
  guardian: Person
  sitter: Person
}

@cowboyd
Copy link
Member Author

cowboyd commented Jul 12, 2021

This is a great writeup @jgnieuwhof!

Copy link
Member Author

@cowboyd cowboyd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jgnieuwhof I think we should go ahead and merge these in. Can you add the private true to the packages so they don't publish to NPM just yet and we can let it rip?

@jbolda
Copy link
Contributor

jbolda commented Jul 19, 2024

The work here is stale and our implementation has drifted. Closing and we can open up a new PR in the future if this is still required.

@jbolda jbolda closed this Jul 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants