graphql-faker
graphql-faker copied to clipboard
Values from @example should be used as exact values
Reported by @sepehr500 in #25
Currently, if want to fake a string, I do the following
type CourtCase {
jurisdiction: String @examples(values: ["DFT", "FUR"])
}
This makes the think that values
expects it's value to be an array of whatever the property type is. So it would follow, that if the type was the following,
type CourtCase {
jurisdiction: [String] @examples(values: [["DFT", "FUR"],["DFS","DNA"])
}
Since the property type is now an array of strings, it would make sense to pass in an array of strings into the array to match the return type. So if we take this same logic an apply it to Objects, then we would expect a property that has a type that is an array of objects, to look like the following,
type Query {
allCourtCases: [CourtCase!]!
@examples(values: [[{state: "WASH", capital: "SEA"},{state: "VA", capital: "RMD"}], [{state:"VA"}]])
}
This way, you have a consistent rule that values
always expects an array of whatever type the return type of the property is.
@sepehr500 Agree, it's not very logic behavior. Idea behind it was that @examples
mimics @fake
behavior and you need some mechanism to allow @fake
on arrays, e.g.:
type Query {
names: [String] @fake(type: "first_name")
}
Not sure how to solve this. What do you think about @exampleItems
and @fakeItems
?
Would love to hear alternative ideas?
In any case, changing current behavior is breaking change and require 2.0.0
version. Don't want to block #25 so I split it out into the separate issue.
what would you gain by doing @exampleItems
and @fakeItems
? I think it's better to just keep the logic that of "value takes an array of items that match the return type".
@sepehr500 Problem is that there are two types of scenarios I want to mock. Field that returns:
- exact array.
- random array consisting from provided elements.
For example
type Query {
letters: [String] @examples(values: ["A", "B", "C"])
}
So there two scenarious:
- you always get
["A", "B", "C"]
- some combination of examples like:
["B", "C", A"]
,["B", "B", "A"]
, etc.
I want to support both scenarios. Another variant to achieve both would be:
-
@examples(values = [["A", "B", "C"]])
-
@examples(items = ["A", "B", "C"])
Might be better to have a flag that randomizes the order of what is returned. Personally, when I am doing local development, I usually don't prefer order being randomized every time. The page should not look totally different every time, just like when using the webpage normally. It also causes problems when GraphQL is ordering results(for example, order by date). So maybe a better solution is,
type Query {
letters: [String] @examples(values: [["A", "B", "C"]], options: {randomize: true})
}
Might be better to have a flag that randomizes the order of what is returned. Personally, when I am doing local development, I usually don't prefer order being randomized every time. The page should not look totally different every time, just like when using the webpage normally.
@sepehr500 I think it should be handled on the global level. For next major version, I want to add
/graphql/seed/{seed_number}
endpoint to always have exactly the same result for an entire query including data generated by @fake
. Or allow specifying seed inside query itself e.g.:
query @seed(number: 1234) {
letters
}
So maybe a better solution is
I'm confused, I thought you advocated on specifying an array of return values inside values
so it should be @examples(values: [["A", "B", "C"]]
(note additional square brackets). Or I'm missing something?
My mistake! It was a typo and I fixed it. I like the ease of being able to specify random order on a global level, but like the granularity of being able to specify random order on a field level as well. Why not both?
@sepehr500 Thank you for suggestions 👍
Right now working on a new GraphQL project, so will put this issue on hold.
But after releasing it I will try to iterate on this and other issues and release version 2.0.0
.
Hi, I was just wondering if this was something you still plan to add as part of the version 2.0.0
release? It would be great to specify an exact array to return, for example:
type Query {
letters: [String] @examples(values: [["A", "B", "C"]])
}
Then running the query:
{
letters
}
always returns the array ["A", "B", "C"] in that order. Thanks!
Over a year later since the last ping, and 2.0.0 is currently in RC phase. Wondering if there's any chance that this will be implemented? Finding myself needing it, and sorely disappointed that it's not there.
Specifically the use case I'm trying to solve is something like this:
interface IPlugin {
name: String!
}
type Pluggable {
plugins: [IPlugin!]! @examples(values: [[PluginA, PluginB], [PluginC, PluginD]])
}
type PluginA implements IPlugin {
name: String! @fake(type: productName)
}
type PluginB implements IPlugin {
name: String! @fake(type: productName)
}
type PluginC implements IPlugin {
name: String! @fake(type: productName)
}
type PluginD implements IPlugin {
name: String! @fake(type: productName)
}
type Query {
pluggable: Pluggable
}
Here's a query which should show the sets.
{
pluggable {
plugins {
__typename
... on PluginA {
name
}
... on PluginB {
name
}
... on PluginC {
name
}
... on PluginD {
name
}
}
}
}
With the expected outcome to always return a collection with PluginA, and PluginB, or a collection with PluginC and PluginD.
I did some work, but it's not PR ready. I was able to resolve the arrays to the schema types and get a list of the types I should create fakes of to return the array. But wasn't able to get the fakeTypeResolver to work from the fakeFieldResolver (see the function getExampleArrayValueCB). I'm attaching the patch of the work I did for review and hoping that someone else can help finish the work.
diff --git a/src/fake_schema.ts b/src/fake_schema.ts
index 1bc8cd0..de88a8a 100644
--- a/src/fake_schema.ts
+++ b/src/fake_schema.ts
@@ -102,6 +102,14 @@ export const fakeFieldResolver: GraphQLFieldResolver<unknown, unknown> = async (
}
if (isListType(type)) {
+ if (exampleValuesTypesAreArrays(fieldDef) ||
+ exampleValuesTypesAreArrays(type)) {
+
+ return getExampleArrayValueCB(fieldDef) ||
+ getExampleArrayValueCB(type);
+ }
+
+ // If not, then listen to the list length, and randomly generate
return Array(getListLength(fieldDef))
.fill(null)
.map(() => fakeValueOfType(type.ofType));
@@ -143,6 +151,30 @@ export const fakeFieldResolver: GraphQLFieldResolver<unknown, unknown> = async (
return args && (() => getRandomItem(args.values));
}
+ function exampleValuesTypesAreArrays(object) {
+ const examplesDirective = schema.getDirective('examples');
+ const args = getDirectiveArgs(examplesDirective, object) as ExamplesArgs;
+ return args.values.find(e => Array.isArray(e));
+ }
+
+ function getExampleArrayValueCB(object) {
+ const examplesDirective = schema.getDirective('examples');
+ const args = getDirectiveArgs(examplesDirective, object) as ExamplesArgs;
+
+ var entry = getRandomItem(args.values);
+
+ if (Array.isArray(entry)){
+ var arr = Array(entry.length)
+ .fill(null)
+ .map((e) => fakeTypeResolver(schema.getType(e), context, info, abstractType))
+
+ return arr;
+ }
+
+ return null;
+ }
+
function getListLength(object): ListLengthArgs {
const listLength = schema.getDirective('listLength');
const args = getDirectiveArgs(listLength, object) as ListLengthArgs;
My proposal https://github.com/graphql-kit/graphql-faker/pull/199