simulacrum
simulacrum copied to clipboard
Spike a graphql simulator
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?
@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.
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
Personentity 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.
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
}
This is a great writeup @jgnieuwhof!
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.