How to return a graphql Union from a python lambda to AWS appsync?
Asked Answered
C

2

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?

Confabulation answered 14/10, 2020 at 0:32 Comment(4)
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?Attestation
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?Confabulation
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.Attestation
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 <type>" statements.Docile
A
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

Attestation answered 1/11, 2020 at 22:31 Comment(3)
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.Confabulation
@JohnMee perhaps, I do think the bounty’s grace period may have already expired, however. Nonetheless, let me know if you get it working.Attestation
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.Docile
K
-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

Kiangsu answered 28/10, 2020 at 6:30 Comment(1)
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 :-/Confabulation

© 2022 - 2024 — McMap. All rights reserved.