Search code examples
swiftcode-generationapolloapollo-ios

Apollo iOS codegen: Nested use of a fragment in a mutation creates unexpected property types in Fragments struct


I have the following fragment:

fragment User on UserResponse {
    firstName
    lastName
    emailAddress
    emailConsent
    phoneNumber
}

When used as root in a mutation, the code generation will correctly generate a root User struct in API.swift and use that struct as the type of user properties in Fragments

Eg.:

mutation updateUserYourInformation($phoneNumber: String!, $emailConsent: Boolean!) {
    updateUser(phoneNumber: $phoneNumber, emailConsent: $emailConsent) {
        ...User
    }
}

and

mutation addRelations($spouse: Boolean!, $children: Int!, $roomMates: Int!) {
     addRelations(spouse: $spouse, roommates: $roomMates, children: $children) {
        ...User
    }
}

will generate mutations where both UpdateUserYourInformationMutation.Data.UpdateUser.Fragments and AddRelationsMutation.Data.AddRelation.Fragments has a user property of the same struct type User.

However, when nesting the fragment in a mutation it generates a nested User struct within the Mutation struct, which will be the type of the user property in the generated nested Fragments struct. E.g:

mutation exchangePin($email: String!, $pin: String!) {
    exchangePinForToken(email: $email, pin: $pin) {
        valid
        user {
            ...User
        }
        authToken
        remainingAttempts
    }
}

will generate ExchangePinMutation.Data.ExchangePinForToken.User and ExchangePinMutation.Data.ExchangePinForToken.User.Fragments structs. However, the user property of ExchangePinMutation.Data.ExchangePinForToken.User.Fragments is of type ExchangePinMutation.Data.ExchangePinForToken.User and not of type User, as I would have expected.

Consequently, the types differ and in order to update the current User object in my app, I have to take the snapshot of ExchangePinMutation.Data.ExchangePinForToken.User and initialise a new User object using that: E.g:

...
let userSnapshot = data.exchangePinForToken.user?.snapshot
Session.currentUser = User(snapshot: userSnapshot)
...

Maybe I'm just creating my fragments and or mutations wrong?


Solution

  • The problem is that the user property of the ExchangePinMutation.Data.ExchangePinForToken.User.Fragments struct should be of the User fragment type, but the type is shadowed by the local ExchangePinMutation.Data.ExchangePinForToken.User type.

    I fixed my issue by renaming the User fragment to UserFull and creating a typealias: typealias User = UserFull

    Almost no refactoring needed!

    https://github.com/apollographql/apollo-codegen/issues/394#issuecomment-373323235