Apollo-ios: Swift generation using field name vs GraphQL type for struct name

Created on 16 Aug 2019  路  5Comments  路  Source: apollographql/apollo-ios

Hi! First off, loving using Apollo and thanks for your hard work especially on the Swift integration.

Question/Issue: generated queries seem to use the name of a field as the name of the struct representing that field, rather than the name of the GraphQL type for the field, which is causing some namespacing headaches for me. For example, I have a project with a GraphQL query like below (types from schema included in query for context):

query getMyWidgets {
    widgets (type: WidgetsPayloadType) {
        widgetList (type: ListOf<WidgetType>) {
            id (type: String)
            name (type: String)
        }
    }
}

where the generated Swift is coming out as:

struct GetMyWidgetsQuery {
    struct Data {
        var widgets: Widget? { ... }
        struct Widget {
            var widgetList: [WidgetList?]? { ... }
            struct WidgetList {
                var id: String { ... }
                var name: String { ... }
            }
        }
    }
}

In my mind, it'd ideally come out as:

struct GetMyWidgetsQuery {
    struct Data {
        var widgets: WidgetsPayloadType? { ... }
        struct WidgetsPayloadType {
            var widgetList: [WidgetType?]? { ... }
            struct WidgetType {
                var id: String { ... }
                var name: String { ... }
            }
        }
    }
}

It's a bit of a style thing, but I've run into some namespacing issues with the fact that Widget is already defined (when writing an extension on the query struct), as well as it feeling weird to have a type called WidgetList which actually represents an element within a list of widgets. It'd also help me (and people onboarding to my project) maintain a clearer mental mapping between the types I'm viewing in something like GraphQL Voyager and the generated types.

Is there a reason to keep it in the current model? Would love to hear if the naming I'm proposing would break other scenarios. Thanks so much!

codegen question

All 5 comments

Good question! I'll try to break it down into a few separate points:

  • We don't necessarily want to have everything line up by the underlying type of the return value, since that can cause some confusion. This is particularly true when a type doesn't have all its required properties present because only one or two were requested. For example, if Widget has both id and name as required properties, but you've only requested id.
  • Responses may not have only one type, so it can be hard to say "this should be Widget" if, for instance, a search can return both Widget and Customer instances. It's much clearer to say it's a Search or something similar, and the fact that it's in something like SearchQuery.Data.Search rather than just Search floating out in space makes it clearer what that type is related to.
  • You can always use an alias to rename the property if you want - I _believe_ if you do something like this:

    query getMyWidgets($type: WidgetsPayloadType) {
      widgetPayload: widgets (type: $type) {
          widgets: widgetList {
              id
              name
      }
    }
    

    the updated code will generate like so:

    struct GetMyWidgetsQuery {
      struct Data {
          var widgetPayload: WidgetPayload? { ... }
          struct WidgetPayload {
              var widgets: [Widget?]? { ... }
              struct Widget {
                  var id: String { ... }
                  var name: String { ... }
              }
          }
      }
    }
    

    which I think is closer to what you're looking for.

@sashaweiss Did this answer your question? If it did, we can close this issue out. If not, let me know what else I can help with.

Yes! Thanks for the detailed response.

You're welcome!

Eventually got around to implementing the rename you mentioned, and wanted to follow up that that approach looks like it'll work great for me. Thanks again!

Was this page helpful?
0 / 5 - 0 ratings