Shopify / syrup

A type-safe GraphQL model generator for Kotlin, Swift, and TypeScript.

Home Page:https://shopify.github.io/syrup/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

First experience feedback

crayment opened this issue · comments

Excited to stumble on this as I think there is demand for some GraphQL support libraries that are not Apollo. I just want type safe code generation for queries and mutations, not all the caching and observing stuff that come along with Apollo.

I tried to run this on my project but the errors I got were very unhelpful:

ERROR: Syrup encountered an error
The data couldn’t be read because it is missing.

So I tried running from Xcode but then it seems to be searching for files all relative to the build directory - which is deep in my derived data. I'm specifying absolute paths so not sure why it would do this and it's not clear to me how I could work around this.

Thanks for giving syrup a try and appreciate the feedback! Totally agree the error messages can be significantly improved.

I suspect this might be syrup having a problem reading the Yaml configuration. Would you mind sharing what that looks like? For reference, https://github.com/Shopify/syrup/blob/master/samples/swift/.syrup.yml is a good example of a basic valid config.

Sure! I have the following:

.syrup.yml

moduleName: MyProject
filenameSuffix: "generated"
header: |
        // Syrup auto-generated file
supportFilesHeader: |
        // Syrup auto-generated support file
accessLevelOverride: "internal" # optional field
generateSelections: true # optional field

.schema.yml

location: MyProject/API/GraphQL/schema.json
customScalars:
- graphType: DateTime
  nativeType: Date

And I'm running it from my shell via:

/Users/crayment/dev/play/syrup/.build/debug/Syrup generate MyProject/API/GraphQL/queries/ models support Syrup-Template

I copied the Swift template into my working dir as Syrup-Template. Initially I was referencing the path to my Syrup clone but that wasn't working either.

Trying with the exact yaml file you linked leads to:

Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/crayment/dev/play/syrup/Sources/SyrupCore/Utilities/Loaders.swift, line 28
Illegal instruction: 4

I also tried to use the override option

/Users/crayment/dev/play/syrup/.build/debug/Syrup generate MyProject/API/GraphQL/queries/ models support Syrup-Template --override-schema MyProject/API/GraphQL/schema.json

But get the same error:

The data couldn’t be read because it is missing.

Sure! I have the following:

.syrup.yml

...........

.schema.yml

I copied the Swift template into my working dir as Syrup-Template. Initially I was referencing the path to my Syrup clone but that wasn't working either.

Looks like your .syrup.yml config is incomplete and should contain the contents from your .schema.yml as well. You should be able to able to reference the language templates from your cloned Syrup repository too.

Using the GitLab GraphQL schema from their introspection URL https://gist.github.com/jaredh/a4895c8c8f084b7fbce3b89571f91156 as an example, and the following .syrup.yml

location: gitlab.json
customScalars: []
moduleName: GitLab
header: |
        // Syrup auto-generated file
        import Foundation
supportFilesHeader: |
        // Syrup auto-generated support file
        import Foundation
generateSelections: false
$ ~/dev/syrup/.build/debug/Syrup generate graphql models support ~/dev/syrup/Templates/Swift
Loading schema: ./gitlab.json
Generating models
Parsing .graphql files
Writing to Responses
Writing to Queries
Writing to Mutations
Writing to Inputs
Writing to Enums
Writing to Fragments
Successfully wrote generated models to /Users/jared/gitlab/models
Generating support files
Successfully wrote generated support files to /Users/jared/gitlab/support

Breaking down the arguments I'm passing to Syrup are as follows,
generate: Option to generate both models and support files
graphql: Folder which contains *.graphql operations
models: Folder where generated queries, reponses, enums, etc are written to
support: Folder where support files are written to
~/dev/syrup/Templates/Swift: Path to location of Swift templates

Maybe your schema is in an incorrect format or not specified correctly? 🤔

Thanks that helped me! My schema did validate when I pasted it into this validator but I noticed that the gitlab sample you posted had a top level object with a single data key, which mine did not. My top level object had a single __schema key. So basically just had one less object container.

I'm not very familiar with the spec, but my schema file was generated using the Apollo CLI so will likely be a common format.

More digging :)

The GraphQL learn page on introspection all seem to contain the top level data key. And when I run this introspection query against my API it does return the top level data key as well. For some reason using apollo schema:download does not have the key in the final result though.

Thanks again for the help! Excited to play with this more 🤩 I do still think there is opportunity to improve the developer experience:

  • The README was initially confusing in that there should only be a single .syrup.yml file containing all of the different config values. The wording made it sound like there should be a separate project config and schema config. I think I get now that it can be if you specify different files via --project and --schema. Not sure if the ability to have these separate provides enough value to justify the additional complexity
  • Specifying some options via CLI arguments and others via the config yaml is a bit strange. Usually tools would support all settings in either place. I think a strategy like this would be a win here.
  • The run from Xcode path in the README isn't very realistic given all config paths seem to expect to be relative to your derived data.
  • Better error messages when things fail would obviously help :)

Hopefully that's constructive. Thanks for sharing this!!

Is there any documentation on what is necessary to get things compiling after running the generator?

image

You'll want to do something like this for your GraphAPI.

// These need to be set manually, to allow for custom configuration of the logger and decoder/encoder behaviour.
// Your generated code will not compile withou this.
extension GraphApiQuery {
public static var errorLogger: GraphApiLogger? {
nil
}
}
extension GraphApiResponse {
public static var errorLogger: GraphApiLogger? {
nil
}
}
extension StarWarsAPI {
public static var customDecoder: JSONDecoder {
JSONDecoder.init()
}
public static var customEncoder: JSONEncoder {
JSONEncoder.init()
}
}

Really appreciate the feedback and help with identifying gaps in our README. We'll iron out the kinks and improve the Getting Started experience.

Thanks! Was able to get it compiling :)

There was one additional change I had to make that was tricky to spot. This line needed to be changed from what is generated by default.

Seems like it would be better to just not generate that file and instruct the user somewhere to create a file with something like the following extension:

extension GraphApiQuery {
    public static var errorLogger: GraphApiLogger? {
        nil
    }
}

extension GraphApiResponse {
    public static var errorLogger: GraphApiLogger? {
        nil
    }
}

extension GraphAPI {
    public static var customDecoder: JSONDecoder {
        JSONDecoder()
    }
    
    public static var customEncoder: JSONEncoder {
        JSONEncoder()
    }
    
    public static var customScalarResolver = BaseCustomScalarResolver()
}

There seems to be some disconnect between the generated sample playground and the current templates. The support file in particular is not generating any query function.

Are you referring to

public func query<Q: GraphApiQuery, R: GraphApiResponse>(_ query: Q, responseType: R.Type, completionHandler: @escaping (R?, Error?) -> Void) -> URLSessionTask {
?

If so, this isn't part of the templates or generated code and considered specific to the client. The "support files" generated are strictly https://github.com/Shopify/syrup/blob/master/samples/swift/Sample.playground/Sources/Generated/GraphApi.swift.

Ah right, I was confusing the files. That makes more sense now. And I think it's desirable to have the client responsible for that code. Thanks!