apollographql / apollo-ios

📱  A strongly-typed, caching GraphQL client for iOS, written in Swift.
https://www.apollographql.com/docs/ios/
MIT License
3.86k stars 712 forks source link

Type already exists in the schema #2048

Closed wow-such-amazing closed 2 years ago

wow-such-amazing commented 2 years ago

Hi everyone! 👋

We've recently migrated our Apollo implementation to the Swift Script. Everything went well on our local computers, but we have faced issues when trying to run builds on our remote machines. We ran out of ideas what could be the source of the problem.

And the error itself that we get doesn't give much clues. It's super weird that we get in only on the build machine environment.

Here is the error output:

Screenshot 2021-12-03 at 15 33 09

Here is our command to generate swift code:

struct GenerateCode: ParsableCommand {
    static var configuration = CommandConfiguration(
        commandName: "generate-code",
        abstract: "Generates swift code from your schema + graphql files."
    )

    func run() throws {
        let fileStructure = try FileStructure()

        CodegenLogger.log("File structure: \(fileStructure)")

        // Get the root of the target for which you want to generate code.
        let targetRootURL = fileStructure.sourceRootURL

        // Make sure the folder exists before trying to generate code.
        try FileManager.default.apollo.createFolderIfNeeded(at: targetRootURL)

        let schemaFileUrl = try fileStructure.coreFolderUrl
            .apollo.childFileURL(fileName: "schema.graphqls")
        let apiFolderUrl = fileStructure.coreFolderUrl
            .apollo.childFolderURL(folderName: "API")

        // Create the Codegen options object https://www.apollographql.com/docs/ios/api/ApolloCodegenLib/structs/ApolloCodegenOptions/
        let codegenOptions = ApolloCodegenOptions(
            includes: "./../**/*.graphql",
            mergeInFieldsFromFragmentSpreads: false,
            omitDeprecatedEnumCases: true,
            outputFormat: .multipleFiles(inFolderAtURL: apiFolderUrl),
            urlToSchemaFile: schemaFileUrl
        )

        // Actually attempt to generate code.
        try ApolloCodegen.run(from: fileStructure.sourceRootURL,
                              with: fileStructure.cliFolderURL,
                              options: codegenOptions)
    }
}

Which is called this way:

# Don't run this during index builds
if [ $ACTION = "indexbuild" ]; then exit 0; fi

cd "${SRCROOT}"/ApolloCodegen

xcrun -sdk macosx swift run ApolloCodegen generate-code

And here is the build phase that we have had before (I've added newlines for easier reading here):

\"${SCRIPT_PATH}\"/run-bundled-codegen.sh
 codegen:generate
 --omitDeprecatedEnumCases
 --target=swift
 --includes=./../**/*.graphql
 --localSchemaFile=\"Core/schema.json\"
 Core/API.swift

One other note is that on our local computers we have M1 while on our build machine it's Intel chip.

Do you have any ideas what could be the problem? 🙏 🥺

designatednerd commented 2 years ago

The errors you're getting indicate that as the schema is being parsed, there's more than one definition for Query and Mutation, which, if that's the case, yes that should be an error.

The other main change is that you've switched from using schema.json to schema.graphqls - that is definitely desirable given that it's more human-readable and waaaaayyyy smaller files, but I'm wondering if there's something screwy in your graphqls schema definition file. Would you be able to share that with me either here or at ellen at apollographql dot com? Thank you!

wow-such-amazing commented 2 years ago

Hey @designatednerd, thanks for reaching out!

I've sent you our graphqls file by email, but we've also tried using the old schema.json file and the problem was still there. So seems like the problem comes from the generate command. Maybe there is some conflict on the cli part, like something similar to this one 🤔

But that's just some guessing, not sure if it helps 😅

designatednerd commented 2 years ago

Thanks for sending - I've emailed two versions of the project with your schema back, one with the non-swift scripting setup and one with the swift scripting setup, and both seem to be working fine with a single query to ping, so it does look like your schema is set up properly.

The next two things I can think of:

wow-such-amazing commented 2 years ago

Thanks for looking into it 🙌🏼

Make sure the ApolloCodegen folder's Package.swift is using the same version of the apollo-ios library as your main application. Mismatches there can cause problems, but I'd be surprised if they're causing this one.

We have verified that it's all good in these terms 🤔

Look in your file tree for duplicate copies of your schema. My theory is that if this is also happening with the way things were set up before, there's something getting picked up twice that shouldn't be.

It doesn't happen with the previous setup that we had. Regarding the schema duplication I agree that this seems like possible issue, but don't know where to look for the second schema. And also given the fact that we provide the schema file url how it could be possible that another schema file would cause problems?

designatednerd commented 2 years ago

One thing I've seen in the past is that if you use graphql rather than graphqls for your schema, the engine we use for parsing and validation can sometimes freak out and decide there are multiple schemas, because it's been included with everything in your glob import. That would at least explain why you're seeing warnings about duplicate Query and Mutation - because the parser is, in fact, seeing them twice, even though you've only specified them once.

Like I said, this is where I would recommend starting - it's clear this is not a normal issue, so there's something unusual going on here. Just trying to get to the bottom of what.

wow-such-amazing commented 2 years ago

One thing I've seen in the past is that if you use graphql rather than graphqls for your schema

How it could be possible? I though the only valid extensions are json and graphqls 🤔

Like I said, this is where I would recommend starting - it's clear this is not a normal issue, so there's something unusual going on here. Just trying to get to the bottom of what.

Yeah, I'm trying to figure out, but the problem is so frustrating mostly because it works correctly on our personal machines and fails only on the jenkins one 😕

Just in case sharing our file structure for where we locate schema and generated swift files. Don't know if this can provide any value.

Screenshot 2021-12-09 at 14 25 21

I feel like there is some misconfiguration on our side that causes this to fail. Cause as I've said same configuration works perfectly on our personal machines. We just can't figure out what exactly 😢

Will keep you posted, hopefully we will find a solution 🤞

wow-such-amazing commented 2 years ago

I think I've made it work 😮 Will share my findings later ☺️

wow-such-amazing commented 2 years ago

To resolve the issue I decided to try to change the location of the ApolloCodegen to make sure that when CLI browses our graphql files or our schema it doesn't "parse" the ApolloCodegen files.

So instead of a thousand words the fix looks like this: iOS - Apollo Codegen

I think the issue could be closed, but it would be useful to mention this case in docs. Also would be cool if it could be possible to exclude some folders from the "parse" action.

designatednerd commented 2 years ago

Ahhhhh yeah that would do it - I tried to add some ASCII art to explain that that it should be set up at a similar level to this in the swift scripting docs, but I think I need to look at doing that as a diagram or a screenshot instead.

It's super useful to have this documented as a possible outcome, though, so thank you for letting us know!

designatednerd commented 2 years ago

Would appreciate your feedback on #2063 if you have any!

wow-such-amazing commented 2 years ago

I think it would make sense to add something like Known issues or a Warnings to let Apollo users know about a possible issues. It's good to describe the desired structure, but it's also worth mentioning what is not a desired structure, so that in case of any problems we could check a list of things that we should avoid. For example:

Why swift scripting doesn't work for me?

Thanks for asking! 🙂

morluna commented 2 years ago

Hello all! Leaving this note for others in case it helps you.

We were seeing this exact same issue in our project, despite having a setup similar to the one outlined by @wow-such-amazing in https://github.com/apollographql/apollo-ios/issues/2048#issuecomment-990000861.

We have recently changed the Derived Data path in our build commands (we use Fastlane) to the root of our project's repo. We did this for other optimization reasons, but in doing so, there was now two GraphQL schemas being picked up by CodeGen. One in our project ({root iOS folder}/graphQLSchema.graphqls) and one in our newly added Fastlane derived data path (/{root iOS folder}/ci-Derived-Data). So every time a developer ran a Fastlane command locally on their machine, this new derived data was created but never cleaned up.

A quick visual:

### Before (was working)
- Xcode
    - DerivedData
        - `graphQLSchema.graphqls`
- ProjectRootFolder
   - CodeGen
   - Generated
   - `graphQLSchema.graphqls`

### After (broken)
- ProjectRootFolder
   - ci-DerivedData <---- new directory causing issues if not deleted
       - `graphQLSchema.graphqls`
   - CodeGen
   - Generated
   - `graphQLSchema.graphqls`