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

Use GraphQL for your data #38 #40

Merged
merged 13 commits into from Jan 13, 2020
Merged
2 changes: 1 addition & 1 deletion Dockerfile
@@ -1,5 +1,5 @@
FROM ruby:2.6
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN apt-get update -qq && apt-get install -y postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
Expand Down
5 changes: 5 additions & 0 deletions Gemfile
Expand Up @@ -32,6 +32,9 @@ gem 'omniauth-google-oauth2'
gem 'omniauth-twitter'
gem 'omniauth-discord'

# Data Management (GraphQL)
gem 'graphql', '1.8.13'

group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
Expand All @@ -42,6 +45,8 @@ group :development do
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
# GraphQL Testing
gem 'graphiql-rails', '1.5.0'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
Expand Up @@ -79,6 +79,10 @@ GEM
ffi (1.11.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
graphiql-rails (1.5.0)
railties
sprockets-rails
graphql (1.8.13)
hashie (3.6.0)
i18n (1.7.0)
concurrent-ruby (~> 1.0)
Expand Down Expand Up @@ -205,6 +209,8 @@ DEPENDENCIES
bootsnap (>= 1.4.2)
byebug
devise_token_auth
graphiql-rails (= 1.5.0)
graphql (= 1.8.13)
listen (>= 3.0.5, < 3.2)
omniauth-discord
omniauth-facebook
Expand Down
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -7,6 +7,7 @@ The back-end of Kuru Anime

## Core Gems
- [Devise Token Auth](https://github.com/lynndylanhurley/devise_token_auth) (Authentication)
- [GraphQL](https://graphql-ruby.org/) (Data Management) [[Tutorial](https://www.howtographql.com/graphql-ruby/0-introduction/)]

## Set-up
You need to have **Docker** and **Docker Compose** installed on your machine to be able to run the following commands.
Expand Down
2 changes: 0 additions & 2 deletions app/controllers/application_controller.rb
@@ -1,4 +1,2 @@
class ApplicationController < ActionController::API
include DeviseTokenAuth::Concerns::SetUserByToken
before_action :authenticate_user!
end
46 changes: 46 additions & 0 deletions app/controllers/graphql_controller.rb
@@ -0,0 +1,46 @@
class GraphqlController < ApplicationController
include DeviseTokenAuth::Concerns::SetUserByToken
before_action :authenticate_user!

def execute
variables = ensure_hash(params[:variables])
query = params[:query]
operation_name = params[:operationName]
context = {
# Query context goes here, for example:
# current_user: current_user,
}
result = MyappSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
render json: result
rescue => e
raise e unless Rails.env.development?
handle_error_in_development e
end

private

# Handle form data, JSON body, or a blank value
def ensure_hash(ambiguous_param)
case ambiguous_param
when String
if ambiguous_param.present?
ensure_hash(JSON.parse(ambiguous_param))
else
{}
end
when Hash, ActionController::Parameters
ambiguous_param
when nil
{}
else
raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
end
end

def handle_error_in_development(e)
logger.error e.message
logger.error e.backtrace.join("\n")

render json: { error: { message: e.message, backtrace: e.backtrace }, data: {} }, status: 500
end
end
Empty file added app/graphql/mutations/.keep
Empty file.
6 changes: 6 additions & 0 deletions app/graphql/mutations/base_mutation.rb
@@ -0,0 +1,6 @@
module Mutations
# This class is used as a parent for all mutations, and it is the place to have common utilities
class BaseMutation < GraphQL::Schema::Mutation
null false
end
end
17 changes: 17 additions & 0 deletions app/graphql/mutations/create_link.rb
@@ -0,0 +1,17 @@
module Mutations
class CreateLink < BaseMutation
# arguments passed to the `resolved` method
argument :description, String, required: true
argument :url, String, required: true

# return type from the mutation
type Types::LinkType

def resolve(description: nil, url: nil)
Link.create!(
description: description,
url: url,
)
end
end
end
4 changes: 4 additions & 0 deletions app/graphql/myapp_schema.rb
@@ -0,0 +1,4 @@
class MyappSchema < GraphQL::Schema
mutation(Types::MutationType)
query(Types::QueryType)
end
Empty file added app/graphql/types/.keep
Empty file.
4 changes: 4 additions & 0 deletions app/graphql/types/base_enum.rb
@@ -0,0 +1,4 @@
module Types
class BaseEnum < GraphQL::Schema::Enum
end
end
4 changes: 4 additions & 0 deletions app/graphql/types/base_input_object.rb
@@ -0,0 +1,4 @@
module Types
class BaseInputObject < GraphQL::Schema::InputObject
end
end
5 changes: 5 additions & 0 deletions app/graphql/types/base_interface.rb
@@ -0,0 +1,5 @@
module Types
module BaseInterface
include GraphQL::Schema::Interface
end
end
4 changes: 4 additions & 0 deletions app/graphql/types/base_object.rb
@@ -0,0 +1,4 @@
module Types
class BaseObject < GraphQL::Schema::Object
end
end
4 changes: 4 additions & 0 deletions app/graphql/types/base_scalar.rb
@@ -0,0 +1,4 @@
module Types
class BaseScalar < GraphQL::Schema::Scalar
end
end
4 changes: 4 additions & 0 deletions app/graphql/types/base_union.rb
@@ -0,0 +1,4 @@
module Types
class BaseUnion < GraphQL::Schema::Union
end
end
7 changes: 7 additions & 0 deletions app/graphql/types/link_type.rb
@@ -0,0 +1,7 @@
module Types
class LinkType < Types::BaseObject
field :id, ID, null: false
field :url, String, null: false
field :description, String, null: false
end
end
5 changes: 5 additions & 0 deletions app/graphql/types/mutation_type.rb
@@ -0,0 +1,5 @@
module Types
class MutationType < Types::BaseObject
field :create_link, mutation: Mutations::CreateLink
end
end
12 changes: 12 additions & 0 deletions app/graphql/types/query_type.rb
@@ -0,0 +1,12 @@
module Types
class QueryType < Types::BaseObject
# queries are just represented as fields
# `all_links` is automatically camelcased to `allLinks`
field :all_links, [LinkType], null: false

# this method is invoked, when `all_link` fields is being resolved
def all_links
Link.all
end
end
end
2 changes: 2 additions & 0 deletions app/models/link.rb
@@ -0,0 +1,2 @@
class Link < ApplicationRecord
end
2 changes: 1 addition & 1 deletion config/application.rb
Expand Up @@ -12,7 +12,7 @@
require "action_text/engine"
require "action_view/railtie"
require "action_cable/engine"
# require "sprockets/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
Expand Down
11 changes: 10 additions & 1 deletion config/routes.rb
@@ -1,4 +1,13 @@
Rails.application.routes.draw do
mount_devise_token_auth_for 'User', at: 'auth'
# Base Redirect
root to: redirect("https://web.kuru-anime.com/")

# Authentication
mount_devise_token_auth_for 'User', at: 'auth'

# Data Management (GraphQL)
post "/data", to: "graphql#execute"
if Rails.env.development?
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/data"
end
end
10 changes: 10 additions & 0 deletions db/migrate/20200112101032_create_links.rb
@@ -0,0 +1,10 @@
class CreateLinks < ActiveRecord::Migration[6.0]
def change
create_table :links do |t|
t.string :url
t.text :description

t.timestamps
end
end
end
9 changes: 8 additions & 1 deletion db/schema.rb
Expand Up @@ -10,11 +10,18 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2019_10_09_000354) do
ActiveRecord::Schema.define(version: 2020_01_12_101032) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

create_table "links", force: :cascade do |t|
t.string "url"
t.text "description"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end

create_table "users", force: :cascade do |t|
t.string "provider", default: "email", null: false
t.string "uid", default: "", null: false
Expand Down
9 changes: 9 additions & 0 deletions test/fixtures/links.yml
@@ -0,0 +1,9 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html

one:
url: MyString
description: MyText

two:
url: MyString
description: MyText
18 changes: 18 additions & 0 deletions test/graphql/mutations/create_link_test.rb
@@ -0,0 +1,18 @@
require 'test_helper'

class Mutations::CreateLinkTest < ActiveSupport::TestCase
def perform(user: nil, **args)
Mutations::CreateLink.new(object: nil, context: {}).resolve(args)
end

test 'create a new link' do
link = perform(
url: 'http://example.com',
description: 'description',
)

assert link.persisted?
assert_equal link.description, 'description'
assert_equal link.url, 'http://example.com'
end
end
7 changes: 7 additions & 0 deletions test/models/link_test.rb
@@ -0,0 +1,7 @@
require 'test_helper'

class LinkTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end