Skip to content
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

Usage of ParseIDs Middleware in Subscription #122

Open
maennchen opened this issue Sep 12, 2018 · 3 comments
Open

Usage of ParseIDs Middleware in Subscription #122

maennchen opened this issue Sep 12, 2018 · 3 comments

Comments

@maennchen
Copy link
Contributor

When trying to use the Absinthe.Relay.Node.ParseIDs middleware for arguments in subscriptions, the following error is thrown.

12:50:25.251 [error] Should have halted or suspended middleware
     Started with: #Absinthe.Resolution<[acc: %{Absinthe.Middleware.Async => false, Absinthe.Middleware.Batch => %{input: [], output: %{}}}, adapter: Absinthe.Adapter.LanguageConventions, arguments: %{}, context: %{pubsub: MetisApi.Endpoint}, definition: %Absinthe.Blueprint.Document.Field{alias: nil, argument_data: %{}, arguments: [%Absinthe.Blueprint.Input.Argument{errors: [], flags: %{}, input_value: %Absinthe.Blueprint.Input.Value{data: nil, normalized: nil, raw: %Absinthe.Blueprint.Input.RawValue{content: %Absinthe.Blueprint.Input.Variable{errors: [], flags: %{}, name: "incident", source_location: %Absinthe.Blueprint.Document.SourceLocation{column: nil, line: 2}}}, schema_node: %Absinthe.Type.Scalar{__private__: [], __reference__: %{identifier: :id, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/deps/absinthe/lib/absinthe/type/built_ins/scalars.ex", line: 44}, module: Absinthe.Type.BuiltIns.Scalars}, description: "The `ID` scalar type represents a unique identifier, often used to\nrefetch an object or as key for a cache. The ID type appears in a JSON\nresponse as a String; however, it is not intended to be human-readable.\nWhen expected as an input type, any string (such as `\"4\"`) or integer\n(such as `4`) input value will be accepted as an ID.", identifier: :id, name: "ID", parse: #Function<10.74440055/1 in Absinthe.Type.BuiltIns.Scalars.parse_with/2>, serialize: #Function<7.74440055/1 in Absinthe.Type.BuiltIns.Scalars.__absinthe_type__/1>}}, name: "incident", schema_node: %Absinthe.Type.Argument{__reference__: %{identifier: :incident, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema/incident.ex", line: 66}, module: MetisApi.Schema.Incident}, default_value: nil, deprecation: nil, description: nil, name: "incident", type: :id}, source_location: %Absinthe.Blueprint.Document.SourceLocation{column: nil, line: 2}, value: nil}], complexity: nil, directives: [], errors: [], flags: %{}, name: "incidentUpdated", schema_node: %Absinthe.Type.Field{__private__: [], __reference__: %{identifier: :incident_updated, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema/incident.ex", line: 65}, module: MetisApi.Schema.Incident}, args: %{incident: %Absinthe.Type.Argument{__reference__: %{identifier: :incident, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema/incident.ex", line: 66}, module: MetisApi.Schema.Incident}, default_value: nil, deprecation: nil, description: nil, name: "incident", type: :id}}, complexity: nil, config: &MetisApi.Schema.Incident.SubscriptionConfig.updated/2, default_value: nil, deprecation: nil, description: nil, identifier: :incident_updated, middleware: [{{Absinthe.Relay.Node.ParseIDs, :call}, [incident: :incident]}], name: "incident_updated", triggers: [], type: :incident_edge}, selections: [%Absinthe.Blueprint.Document.Field{alias: nil, argument_data: %{}, arguments: [], complexity: nil, directives: [], errors: [], flags: %{}, name: "cursor", schema_node: %Absinthe.Type.Field{__private__: [], __reference__: %{identifier: :cursor, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema/incident.ex", line: 0}, module: MetisApi.Schema.Incident}, args: %{}, complexity: nil, config: nil, default_value: nil, deprecation: nil, description: "A cursor for use in pagination", identifier: :cursor, middleware: [{Absinthe.Middleware.MapGet, :cursor}], name: "cursor", triggers: [], type: %Absinthe.Type.NonNull{of_type: :string}}, selections: [], source_location: %Absinthe.Blueprint.Document.SourceLocation{column: nil, line: 3}, type_conditions: []}, %Absinthe.Blueprint.Document.Field{alias: nil, argument_data: %{}, arguments: [], complexity: nil, directives: [], errors: [], flags: %{}, name: "node", schema_node: %Absinthe.Type.Field{__private__: [], __reference__: %{identifier: :node, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema/incident.ex", line: 0}, module: MetisApi.Schema.Incident}, args: %{}, complexity: nil, config: nil, default_value: nil, deprecation: nil, description: "The item at the end of the edge", identifier: :node, middleware: [{Absinthe.Middleware.MapGet, :node}], name: "node", triggers: [], type: :incident}, selections: [%Absinthe.Blueprint.Document.Field{alias: nil, argument_data: %{}, arguments: [], complexity: nil, directives: [], errors: [], flags: %{}, name: "id", schema_node: %Absinthe.Type.Field{__private__: [], __reference__: %{identifier: :id, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema/incident.ex", line: 0}, module: MetisApi.Schema.Incident}, args: %{}, complexity: nil, config: nil, default_value: nil, deprecation: nil, description: "The ID of an object", identifier: :id, middleware: [{{Absinthe.Resolution, ...}, #Function<2.20694165/2 in Absinthe.Relay.Node.global_id_resolver/2>}], name: "id", triggers: [], type: %Absinthe.Type.NonNull{...}}, selections: [], source_location: %Absinthe.Blueprint.Document.SourceLocation{column: nil, line: 5}, type_conditions: []}], source_location: %Absinthe.Blueprint.Document.SourceLocation{column: nil, line: 4}, type_conditions: []}], source_location: %Absinthe.Blueprint.Document.SourceLocation{column: nil, line: 2}, type_conditions: []}, errors: [], extensions: %{}, fields_cache: "#fieldscache<...>", fragments: %{}, middleware: [{{Absinthe.Relay.Node.ParseIDs, :call}, [incident: :incident]}], parent_type: %Absinthe.Type.Object{__private__: [], __reference__: %{identifier: :subscription, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema.ex", line: 56}, module: MetisApi.Schema}, description: nil, field_imports: [activity_subscriptions: [], message_subscriptions: [], incident_subscriptions: [], status_group_subscriptions: []], fields: %{activity_created: %Absinthe.Type.Field{__private__: [], __reference__: %{identifier: :activity_created, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema/activity.ex", line: 78}, module: MetisApi.Schema.Activity}, args: %{incident: %Absinthe.Type.Argument{__reference__: %{identifier: :incident, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema/activity.ex", line: 79}, module: MetisApi.Schema.Activity}, default_value: nil, deprecation: nil, description: nil, name: "incident", type: :id}}, complexity: nil, config: &MetisApi.Schema.Activity.SubscriptionConfig.created/2, default_value: nil, deprecation: nil, description: nil, identifier: :activity_created, middleware: [Absinthe.Middleware.PassParent], name: "activity_created", triggers: [], type: :activity_edge}, incident_created: %Absinthe.Type.Field{__private__: [], __reference__: %{identifier: :incident_created, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema/incident.ex", line: 59}, module: MetisApi.Schema.Incident}, args: %{status_group: %Absinthe.Type.Argument{__reference__: %{identifier: :status_group, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema/incident.ex", line: 60}, module: MetisApi.Schema.Incident}, default_value: nil, deprecation: nil, description: nil, name: "status_group", type: :id}}, complexity: nil, config: &MetisApi.Schema.Incident.SubscriptionConfig.created/2, default_value: nil, deprecation: nil, description: nil, identifier: :incident_created, middleware: [Absinthe.Middleware.PassParent], name: "incident_created", triggers: [], type: :incident_edge}, incident_updated: %Absinthe.Type.Field{__private__: [], __reference__: %{identifier: :incident_updated, location: %{file: "/Users/maennchen/Development/data-quest/metis/api/apps/metis_api/lib/metis_api/schema/incident.ex", line: 65}, module: MetisApi.Schema.Incident}, ar (truncated)

If you're interested I could build a PR to solve the issue.

@benwilson512
Copy link
Contributor

Right, this is a good question.

Here's the issue generally: Right now middleware doesn't work with subscription config at all. The reason is simple: Middleware runs during the resolution phase, but subscription documents don't run resolution on setup, they run resolution on publication.

Your specific error message is a slightly different problem, this happens because you've added middleware to the field but haven't added a resolver. If middleware is added to a field via the middleware macro, then no default resolver is applied. ParseIDs doesn't resolve the field (not its job to) so when the doc is published you get an error.

Possible solutions

Honestly I'm not entirely sure what the best approach here is. Perhaps the best option is to create a middleware like mechanic that operates directly on the AST for stuff like argument transformation, and move ParseIDs to using that.

@jcelliott
Copy link

jcelliott commented Feb 21, 2020

I just ran into this issue as well. It's easy enough to parse the global ID in the config function (or convert to a global ID in the trigger I guess), but it took me a few minutes to understand that the middleware wasn't working like I assumed it would. Perhaps adding a note in the moduledoc for ParseID would be worthwhile?

@benwilson512
Copy link
Contributor

@jcelliott PR welcome for that note!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants