Single value vs Array in GraphQL Enum input types - graphql

How do you define an input type that either accepts a single enum value or an array of values in GraphQL?
According to GitHub GraphQL API,
{
securityVulnerabilities(first: 3, ecosystem: RUBYGEMS) {
nodes {
advisory {
description
}
}
}
}
But I think array can be good because user can search across ecosystem.
{
securityVulnerabilities(first: 3, ecosystem: [RUBYGEMS, NPM]) {
nodes {
advisory {
description
}
}
}
}

You can do this by defining the input value as an array [] of your defined Enum, something like:
enum MyEnum {
RUBYGEMS
NPM
}
type Query {
securityVulnerabilities(ecosystem: [MyEnum!]): MyReturnObject
}
And then you can query it like:
{
securityVulnerabilities(ecosystem: [RUBYGEMS, NPM]) {
....
}
}
And it works with both an array or a single value:
{
securityVulnerabilities(ecosystem: RUBYGEMS) {
....
}
}
The GraphQL spec explains the following:
If the value passed as an input to a list type is not a list and not
the null value, then the result of input coercion is a list of size
one [...]

Related

Dynamic field or field of type (Struct, Map, Any) for custom options

Assuming I need to define a custom option for a method, for example:
message MessageBusOptions {
string namespace = 1;
optional string queue = 2;
}
extend google.protobuf.MethodOptions {
optional MessageBusOptions message_bus_options = 50000;
}
So far everything works as expected. I can define my service the following way:
services TestServices {
rpc SendMessage(MessageReq) returns(MessageRes) {
option (message_bus_options) = {
namespace: "abc",
queue: "default"
}
}
}
Now, how I can I add a dynamic field to the MessageBusOptions so that I can provide a dynamic value, for example:
services TestServices {
rpc SendMessage(MessageReq) returns(MessageRes) {
option (message_bus_options) = {
namespace: "abc",
queue: "default",
dynamic_field: {
a: "a",
b: "b"
}
}
}
}
I tried the following types (Map, Any, Struct) but all of them led to this error
Error while parsing option value for "xxx": Message type "xxx" has no field named "xxx".
How can I define such dynamic field in the custom option?

GraphQL query filtering multiple relations

(From Strapi) I am trying to get all "acts" with a certain age (can return multiple) and with a certain place (can return multiple). I can't figure out how to filter that.
This is what I am trying in GraphQL-playground (works without the variables), but it says "Unknown argument "age" on field "Act.ages"." (and "place" respectively).
query GetActs ($age:Int, $place:String) {
acts {
data {
id
attributes {
Title
ages (age: $age) {
data {
id
attributes {
age
}
}
}
places (place: $place) {
data {
id
attributes {
place
}
}
}
}
}
}
}
I just ran into this same issue. I can't make out the error you're reporting, but here is what worked for me.
You can use filter at the collection level to drill down to nested fields for the corresponding attributes. This follows the GraphQL example at the bottom of this Strapi resource on filtering nested fields.
Solution
query GetActs ($age:Int, $place:String) {
acts (filters: {ages: {age: {eq: $age}}, places: {place: {eq: $place}}}) {
data {
id
attributes {
Title
ages {
data {
id
attributes {
age
}
}
}
places {
data {
id
attributes {
place
}
}
}
}
}
}
}

sort content by tag in Gatsby with Conteful API

In Contentful, I create a content with few media pictures. The pictures have two different tags boxon and attaqueGenetique. I want to sort the slideshow by using tags I've added for each media, but I don't find the way to do that. There is an example on the website Gatsby, but is not really clear and my try failed to make it mine.
The example from Gatsby
query FilterByTagsQuery {
allContentfulNumber(
sort: { fields: contentful_id }
filter: {
metadata: {
tags: { elemMatch: { contentful_id: { eq: "numberInteger" } } }
}
}
) {
nodes {
title
integer
}
}
}
I've supposed I must transpose thise code to mine where
allContentfulNumber become allContentfulDiaporama, and
metadata: {
tags: { elemMatch: { contentful_id: { eq: "numberInteger" } } }
}
become
metadata: {
tags: { elemMatch: { contentful_id: { eq: "boxon" } } }
}
but when I try to compile the console return
56:5 error Field "metadata" is not defined by type "ContentfulDiaporamaFilterInput" graphql/template-strings
I don't know where catch metadata from media when it's imported in content... but I'm very beginner with graphql and Contentful. If there is a solution, that's can make my day happy !!!
metadata in Gatsby's example is a GraphQL node valid in their data structure, if yours hasn't it simply don't use it or it will break the code since it's not a valid custom type.
The problem in your query, besides using an invalid field (metadata) is that you are using an elemMatch filter, comparingcontentful_id (number) to boxon (string), so it will never work in your scenario (it works in Gatsbys' because it's the same type). In your case, you may want to use in (for arrays) or eq (for single values). Check the available list at: https://www.gatsbyjs.com/docs/graphql-reference/#filter
As far as I understand your question, it seems that you want to split your diaporama data in two different nodes, the ones that contain boxon and the ones that contain attaqueGenetique. If so, you will need to create different nodes by aliasing them:
query FilterByTagsQuery {
boxon: allContentfulDiaporama(
sort: { fields: contentful_id }
filter: {
metadata: { tags: { in: ["boxon"] } }
}
) {
nodes {
#your data/fields here
}
}
attaqueGenetique: allContentfulDiaporama(
sort: { fields: contentful_id }
filter: {
metadata: { tags: { in: ["attaqueGenetique"] } }
}
) {
nodes {
#your data/fields here
}
}
}
Test the query in the GraphiQL playground, available at localhost:8000/___graphql where it will be much more intuitive for you to add or remove filters and see the available nodes.
The snippet above will generate two different data structures based on the tags aliased. With this: boxon: allContentfulDiaporama, you are aliasing the result of allContentfulDiaporama in boxon so in your page, you will be able to access directly props.data.boxon and props.data.attaqueGenetique respectively.
Keep in mind that the sort filtering method only works on dates or numeric values, in the case of strings, it will sort them alphabetically. So I'm assuming that your data has a contentful_id (I'm not sure how it will be helpful sorting by contentful_id).
According to this pull-request the enableTags feature was fixed in the cutting-edge release(5 days ago) so try to upgrade your plugin dependency.
It seems to be fixed in, according to this GitHub thread:
gatsby-source-contentful#7.5.0-next.0
Or in the next release.

Is there a way to pass a parameter into a GraphQL query to specify the GraphQL type it should be run on?

I'm new to GraphQL and would like to be able to use a variable for a GraphQL name in a query.
I've attempted to use the standard $ syntax but with no luck.
Working query:
query Tryptych($section: SectionsEnum = home) {
enGB: entries(section: [$section], site: "enGB") {
... on Home {
tryptych {
...tryptychFields
}
}
}
}
What I'd like to be able to do:
query Tryptych($section: SectionsEnum = home, $interface: SomeType = Home) {
enGB: entries(section: [$section], site: "enGB") {
... on $interface {
tryptych {
...tryptychFields
}
}
}
}
Fragment for reference:
fragment tryptychFields on TryptychTryptych {
__typename
theme
tagline
firstImageTitle
firstImageContent
firstImageAsset {
url
}
firstImageLink
secondImageTitle
secondImageContent
secondImageAsset {
url
}
secondImageLink
thirdImageTitle
thirdImageContent
thirdImageAsset {
url
}
thirdImageLink
}
In the code snippet for what I'd like to achieve I get the error message:
Expected Name, found $
Thanks for the help.
A variable can only have one type, that type must be an input type (i.e. a scalar, enum or input object type), and it can only be used where an input type would be expected (i.e. a field or directive argument). In other words, the syntax you're suggesting is not supported.
If you have multiple types that may be returned by the same field, you may use any number of fragments to specify the selection set by type. The actual selection set will be determined at runtime when the type of the field is evaluated. For example, if the animal field returns a union of Cat, Dog and Bird types:
query {
animal {
... on Cat {
meows
}
... on Dog {
barks
}
... on Bird {
chirps
}
}
}
You may also use the #skip and #include directives to control which fields are selected:
query ($inAHouse: Boolean!, $withAMouse: Boolean!) {
greenEggs #skip(if: $inAHouse)
ham #include(if: $withAMouse)
}
And you may include multiple operations in a single document, and then specify an operationName with your request to tell the server which operation to run:
query OperationA {
foo
}
query OperationB {
bar
}

GraphQL arguments to connection sub results

I'm need help passing arguments to collections/connections/arrays in GraphQL syntax.
I'm just learning it, playing with the SWAPI at http://graphql.org/swapi-graphql/
I can pass an id argument to a single type, like this:
query getANewHope {
film(id: "ZmlsbXM6MQ==") {
id
title
}
}
But I don't know how to query the results of a collection/connection
query starships {
allStarships(id: "c3RhcnNoaXBzOjI=") { # this doesn't work
edges {
node(id: "c3RhcnNoaXBzOjI=") { # ...nor this.
id
}
}
}
}
I want to query collections because, I'd like to connect the two ideas like "All Starfighter type ships in A New Hope"?
query filmStarships {
film(id: "ZmlsbXM6MQ==") {
title
starshipConnection { #How to limit this? I can't use (starshipClass: "Starfighter") here...
edges {
node { # ...nor here..
starshipClass # ...nor here.
}
}
}
}
}
query starships2 {
starship (id: "c3RhcnNoaXBzOjI=") { # This doesn't work either
id # even without an arugment abovce, it says "Unknown argument \"id\" on field \"node\" of type \"StarshipsEdge\"."
}
}
Arguments like you're asking for have to be implemented in the schema. The SWAPI does does not expose an argument to filter by starshipClass. Click Docs on the top right of the GraphiQL window to explore the provided schema.
If you are implementing your own schema it would be very easy to add a filter on starshipClass in the resolvers.

Resources