New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate Swift operation IDs and operation <--> operation ID mapping file #147
Conversation
I think this is great, since we should unify these tools anyway. No reason to have two IMO. |
Yeah, I think adding support for persisted queries to Apollo iOS is great! I want to make sure we align the approaches and tooling for the different platforms though. As @stubailo mentions, we've discussed combining tools like It also seems there is an existing issue on |
@stubailo one reason I can think of for maintaining a standalone tool like persistgraphql is to cater to folks who aren't using Apollo. But you could make the counterargument "who's writing a bunch of |
Updated based on some helpful feedback by @lelandrichardson. Though operation names are guaranteed to be unique when running |
Maybe this PR could be part of a larger effort to standardize the usage of persisted queries (or persisted documents as some are calling it apparently). Basically, I'd like to avoid a situation where Apollo iOS does one thing, and other tools like One area in particular where I think standardization would be helpful is in the generated mapping file. Ideally, these mapping files would be supported by different servers and tools in the same way the So I'm not saying we should stick to what |
src/swift/codeGeneration.js
Outdated
@@ -376,6 +384,29 @@ export function structDeclarationForSelectionSet( | |||
}); | |||
} | |||
|
|||
function operationId(generator, { operationName, fragmentsReferenced, source }, fragments) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could be moved to compiler.js
and put in the IR file, so that Android can have access to the same id.
Huh, I didn’t know about I agree with you, @martijnwalraven, that there’s value in standardizing the format of the generated mapping file, for use with different backend platforms. I think that there are some good reasons to evolve this format from the one that’s currently output by
All that is to say - I propose we go with something like the format proposed in this PR. Perhaps we could support a command-line flag to output the format expected by Scaphold? What do you think? |
@BenSchwab per your suggestion, moved the source-with-fragments and operation id generation to the compilation phase. Let me know if that will make it reusable on Android! Also added support for deeply-nested fragment references, which thanks to you we realized was missing. |
…anteed by apollo-codegen to be unique) and providing values with both operation id and source
…compilation step rather than code generation step. Also, when generating operation source + fragments, handle possibility of nested fragment references.
… ids and sources on context (it's no longer done that way)
…ce function in Swif tests
…ted fragment refrences, the correct source + fragments is generated for the operation id mapping file
src/swift/codeGeneration.js
Outdated
@@ -69,7 +69,7 @@ export function generateSource(context, options) { | |||
}); | |||
|
|||
Object.values(context.operations).forEach(operation => { | |||
classDeclarationForOperation(generator, operation); | |||
classDeclarationForOperation(generator, operation, Object.values(context.fragments)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still needed? Or is sourceWithFragments
enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. I think you're right that we don't need this anymore.
src/swift/codeGeneration.js
Outdated
} | ||
|
||
generator.printNewlineIfNeeded(); | ||
generator.printOnNewline(`public static let operationId = "${operationId}"`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely a bit nitpicky, but would operationID
or even operationIdentifier
be more Swifty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, yeah, you're right. Let's go with operationIdentifier
instead (I'm looking at URLSessionTask.taskIdentifier
as inspiration).
namespace: argv.namespace | ||
namespace: argv.namespace, | ||
operationIdsPath: argv["operation-ids-path"], | ||
generateOperationIds: !!argv["operation-ids-path"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be a separate option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do think having this as a separate option reads a lot better, especially in codeGeneration.js
, which doesn't need to know or care about file paths.
- Improve CLI message - Remove unnecessary parameter in a function call - Rename Swift operationId to operationIdentifier
…file (apollographql#147) * Initial progress on Swift operationId generation * Add dependency on crypto library for SHA256 * In Swift, operationId is computed and output with every operation class * Factor out Swift operationId into its own function * Write to a JSON file the mapping between operations and their ids (Swift-only) * Update operationIds map to be keyed by operation name (which are guaranteed by apollo-codegen to be unique) and providing values with both operation id and source * OperationIds map is keyed by id, and operation name is part of the value * Use === instead of == * Update Swift Jest snapshots with new newline * Fix missing comma * Add fragments to classDeclarationForOperation invocation in Swift tests * Add unit tests exercising operation id generation in Swift * Move generation of operation IDs and operation source + fragments to compilation step rather than code generation step. Also, when generating operation source + fragments, handle possibility of nested fragment references. * Remove obsolete test checking for generated mapping between operation ids and sources on context (it's no longer done that way) * Improve readability of generateOperationIds option in compileFromSource function in Swif tests * Add Swift code generation test that verifies that, when there are nested fragment refrences, the correct source + fragments is generated for the operation id mapping file * Fix typescript error related to operation ids map * PR feedback and tweaks: - Improve CLI message - Remove unnecessary parameter in a function call - Rename Swift operationId to operationIdentifier * Update test snapshot
This introduces - to Swift only - the notion of
operationId
s, which are unique identifiers for operations. The primary use for these ids is registration with a server, to do query persistence and whitelisting.The operation id is generated by concatenating the formatting-normalized source of the operation with the formatting-normalized sorted sources of the fragments it references. It's a whitespace-agnostic "fingerprint" of the operation source that's sent to the server. Note, however, that it is not agnostic to field order.
When the
operation-ids-path
option is provided toapollo-codegen
, the following occurs:operationId
static property is added to the operation class definition.The updated operation class definitions looks like:
The generated map file looks like:
Why not use persistgraphql?
persistgraphql
concerns itself with is parsing and extraction, whichapollo-codegen
doesn't need (since it already does)persistgraphql
assigns an incrementing id to each operation; we want more of a unique "fingerprint"Remaining work
apollo-ios
repo (generate newAPI.swift
with operation ids and verify all unit tests pass)