Skip to content

Instantly share code, notes, and snippets.

@rmosolgo
Created February 1, 2016 16:00
Show Gist options
  • Select an option

  • Save rmosolgo/5deb22056c634bcc891f to your computer and use it in GitHub Desktop.

Select an option

Save rmosolgo/5deb22056c634bcc891f to your computer and use it in GitHub Desktop.
ETag idea for GraphQL + Ruby
# An untested idea to use objects' `update_at` properties to determine
# whether the query response has changed since a given time.
#
# Requires some setup, you must pass the `updated_at` from the incoming ETag into the query:
#
# ```
# # The `context` object itself is read-only, so use a nested hash, which may be modified during query execution:
# etags = {updated_at: last_etag}
#
# result = MySchema.execute(query_string, context: {etags: etags})
#
# # The middleware will modify the hash you passed in:
# new_etag = etags[:updated_at]
#
# if new_etag > last_etag
# # ... Profit!
# ```
#
#
# When you define your schema, you could add this middleware:
#
# ```
# MySchema.middleware << EtagMiddleware.new
# ```
#
# More about middlewares for the GraphQL gem: https://github.com/rmosolgo/graphql-ruby/blob/master/guides/defining_your_schema.md#middleware
#
class EtagMiddleware
def call(parent_type, parent_object, field_definition, field_args, query_context, next_middleware)
# Resolve the field as normal:
resolved_object = next_middleware.call
# If the object can yield some kind of `updated_at`, maybe use it for the etag:
new_updated_at = get_updated_at(resolved_object)
if new_updated_at && new_updated_at > query_context[:etags][:updated_at]
query_context[:etags][:updated_at] = new_updated_at
end
# Return the resolved object:
resolved_object
end
private
def get_updated_at(resolved_object)
if resolved_object.respond_to?(:updated_at)
resolved_object.updated_at
elsif resolved_object.is_a?(Array) # Extend this to handle other collection objects like `ActiveRecord::Relation`s
resolved_object
.map { |obj| get_updated_at(obj) }
.compact
.max
else
nil
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment