8

Is it possible to respond with graphql Union from a python lambda? How? It seems possible but I cannot get it over the line.

I am including a __typename attribute but most of the time I get this error:

{'errorType': 'BadRequestException', 
 'message': "Could not determine the exact type of MealMix. Missing __typename key on value.'"}

MealMix is my union, and the schema looks like:

type Meal { name: String }
type OtherMeal { name: String }
union MealMix = Meal | OtherMeal
type Query {
    GetMealMix(identity_id: ID!, date: AWSDate!): [MealMix]
}

The query is:

        query test_query {
            GetMealMix(identity_id: "this", date: "2020-11-20") {
                ... on Meal {name}
                ... on OtherMeal {name}
            }
        }

From the lambda I am returning:

return [{' __typename': 'Meal',
         'name': 'Kiwifruit, Zespri Gold, Raw'},
        {' __typename': 'OtherMeal',
         'name': 'The meal at the end of the universe'}]

The response template is the default: $util.toJson($ctx.result)

My googling seems to suggest I just need to include the __typename attribute, but there are no explicit Python examples to that effect. I'm asking first, am I flogging a dead horse (meaning this is not implemented and will never work), and second, if it does work, how exactly?

John Mee
  • 50,179
  • 34
  • 152
  • 186
  • I’ve been researching this question on and off for a few days now. Just confirming—your lambda is logging the correct return value, but http response returns bad request? – pygeek Oct 30 '20 at 20:24
  • Fair question. I have not got it handy to double check, but the answer will be "yes': the lambda is returning the list of dict as shown... the return statement is a cut/paste, and the httpresponse.content is the errortype dict at the top. Have you had any success? – John Mee Nov 01 '20 at 22:18
  • I posted an answer with some suggestions—I think Option 2 is more likely to be your answer. Oh, and I'm not sure what identity_id: "this" is, but it may be caching your result and causing weird issues, consider passing something unique each time even if mocking the response. – pygeek Nov 01 '20 at 22:42
  • You may want to look at typify in the appsync-tools module. Disclaimer, I am the author. If you add __typename to the results then returning a union works fine if your query/mutation uses "... on " statements. – OneLiner Nov 12 '20 at 03:29

2 Answers2

0

Problem

On one hand, I found examples where __typename, as you reference, may need to be included in your query. On the other hand, It's also very interesting, because the AWS documentation mentions nothing about including __typename in your query, but does mention the use of interfaces so I wonder if that's the key to getting things working, that all types extend the same interface.

Solution

Option 1

Try including __typename within Meal and OtherMeal fragments (you mentioned using __typename in your queries, but not sure where you were putting it).

Example

query test_query {
            GetMealMix(date: "2020-11-20") {
                ... on Meal {
                    __typename
                    name
                }
                ... on OtherMeal {
                    __typename                    
                    name
                }
            }
        }

Option 2

All types included in union use the same interface, as demonstrated in a section of the documentation you shared titled "Type resolution example"

Example

interface MealInterface { name: String }
type Meal implements MealInterface { name: String }
type OtherMeal implements MealInterface { name: String }

Notes

Hardcoded Responses

You return a hardcoded response, but I'm unsure if additional metadata is needed to process the GQL response on AWS Lambda. Try logging the response to determine if __typename is included. If __typename is not included, consider adding typename to id and use transformation recommended in the AWS documentation you shared:

#foreach ($result in $context.result)
    ## Extract type name from the id field.
    #set( $typeName = $result.id.split("-")[0] )
    #set( $ignore = $result.put("__typename", $typeName))
#end
$util.toJson($context.result)

identity_id

Also, "this" in "identity_id" parameter may be causing caching issues due to the way GraphQL handles ID types (see: https://graphql.org/learn/schema/#scalar-types)

References

GraphQL __typename query example on AWS: https://github.com/LambdaSharp/AppSync-Challenge GraphQL Scalar types: https://graphql.org/learn/schema/#scalar-types

pygeek
  • 7,356
  • 1
  • 20
  • 41
  • Sorry mate, I haven't had a chance to go back and try this out yet. I'll get to it. Reading through the bounty blurbs it looked like I can still award it if I jump through all the right hoops, which I will do if success. – John Mee Nov 03 '20 at 01:29
  • @JohnMee perhaps, I do think the bounty’s grace period may have already expired, however. Nonetheless, let me know if you get it working. – pygeek Nov 03 '20 at 01:32
  • I am currently building an Appsync app that returns multiple different types from a union in the same query. I can say that all of my tests show that all types in the union need to implement the same interface. We use typify from appsync-tools to insert the type name and the use the "... on Foo" syntax in queries. – OneLiner Nov 12 '20 at 03:38
-1

You can write in this way as given below. It's should work for you.

schema {
    query: Query
}

type Query {
    GetMealMix(identity_id: ID!, date: AWSDate!): [MealMix]
}

union MealMix = Meal | OtherMeal

type Meal {
    name: String
}

type OtherMeal {
    name: String
}

query {
    GetMealMix(identity_id: "this", date: "2020-11-20") {
        ... on Meal {name}
        ... on OtherMeal {name}
    }
}

You can take reference from the below URL: Interfaces and unions in GraphQL

sanjusci
  • 187
  • 1
  • 9
  • Hi. Have you, yourself, been able to return a list of mixed types from a lambda? This "answer" seems to be just a reformatting of the question. Nice try tho :-/ – John Mee Oct 28 '20 at 23:19