Skip to content

Instantly share code, notes, and snippets.

View nickpoorman's full-sized avatar
Verified

Nick Poorman nickpoorman

Verified
View GitHub Profile
@nickpoorman
nickpoorman / Gemfile
Created June 24, 2020 23:41 — forked from dhh/Gemfile
HEY's Gemfile
ruby '2.7.1'
gem 'rails', github: 'rails/rails'
gem 'tzinfo-data', '>= 1.2016.7' # Don't rely on OSX/Linux timezone data
# Action Text
gem 'actiontext', github: 'basecamp/actiontext', ref: 'okra'
gem 'okra', github: 'basecamp/okra'
# Drivers
@nickpoorman
nickpoorman / flattenSchema.scala
Created September 5, 2019 20:19
Scale Flatten DataFrame - what explode should be
def flattenSchema(schema: StructType, prefix: String = null) : Array[Column] = {
schema.fields.flatMap(f => {
val colName = if (prefix == null) f.name else (prefix + "." + f.name)
f.dataType match {
case st: StructType => flattenSchema(st, colName)
case _ => Array(col(colName).alias(colName))
}
})
}
@nickpoorman
nickpoorman / ACollectionOfGoPlaygroundSnippets.md
Last active December 6, 2019 20:45
A Collection of Go Playground Snippets

Go Playground Snippets

This is a simple collection of my Go Playground snippets for reference later.

@nickpoorman
nickpoorman / association_loader.rb
Created April 28, 2017 19:32 — forked from theorygeek/association_loader.rb
Preloading Associations with graphql-batch
# frozen_string_literal: true
class AssociationLoader < GraphQL::Batch::Loader
attr_reader :klass, :association
def initialize(klass, association)
raise ArgumentError, "association to load must be a symbol (got #{association.inspect})" unless association.is_a?(Symbol)
raise ArgumentError, "cannot load associations for class #{klass.name}" unless klass < ActiveRecord::Base
raise TypeError, "association #{association} does not exist on #{klass.name}" unless klass.reflect_on_association(association)
@klass = klass

Scaling your API with rate limiters

The following are examples of the four types rate limiters discussed in the accompanying blog post. In the examples below I've used pseudocode-like Ruby, so if you're unfamiliar with Ruby you should be able to easily translate this approach to other languages. Complete examples in Ruby are also provided later in this gist.

In most cases you'll want all these examples to be classes, but I've used simple functions here to keep the code samples brief.

Request rate limiter

This uses a basic token bucket algorithm and relies on the fact that Redis scripts execute atomically. No other operations can run between fetching the count and writing the new count.

# app/graph/mutations/post_mutations/create.rb
module PostMutations
Create = GraphQL::Relay::Mutation.define do
# Used to name derived types, eg `"CreatePostInput"`:
name 'CreatePost'
description 'Create post with a title and return a post'
# Define input parameters
# Accessible from `input` in the resolve function:
input_field :title, !types.String
# app/graph/fields/fetch_field.rb
class FetchField < GraphQL::Field
def initialize(model:, type:)
self.type = type
@model = model
self.description = 'Find a #{model.name} by ID'
self.arguments = {
'id' => GraphQL::Argument.define do
name 'id'
type !GraphQL::INT_TYPE
# app/controllers/graphql_controller.rb
class GraphqlController < ApplicationController
def create
query_string = params[:query]
query_variables = ensure_hash(params[:variables])
context = { current_user: current_user, pundit: self }
result = ApplicationSchema.execute(query_string, variables: query_variables, context: context)
render json: result
end
# app/graph/application_schema.rb
ApplicationSchema = GraphQL::Schema.define do
query QueryType
mutation MutationType
resolve_type -> (object, _ctx) { ApplicationSchema.types[object.class.name] }
# These are used by relay
object_from_id -> (id, ctx) { decode_object(id, ctx) }
id_from_object -> (obj, type, ctx) { encode_object(obj, type, ctx) }
# app/controllers/application_controller.rb
class ApplicationController < ActionController::API
include Pundit
# set current_user from token
include DeviseTokenAuth::Concerns::SetUserByToken
# For this example we will stub out `current_user`
# For Pundit, you may want to override `pundit_user`
def current_user