Add new GraphQL types, schema (with fields) & base mutation
The current consul GraphQL API has two problems. 1) It uses some unnecessary complicated magic to automatically create the GraphQL types and querys using an `api.yml` file. This approach is over-engineered, complex and has no benefits. It's just harder to understand the code for people which are not familiar with the project (like me, lol). 2) It uses a deprecated DSL [1] that is soon going to be removed from `graphql-ruby` completely. We are already seeing deprecation warning because of this (see References). There was one problem. I wanted to create the API so that it is fully backwards compatible with the old one, BUT the old one uses field names which are directly derived from the ruby code, which results in snake_case field names - not the GraphQL way. When I'm using the graphql-ruby Class-based syntax, it automatically creates the fields in camelCase, which breaks backwards-compatibility. So I've added deprecated snake_case field names to keep it backwards-compatible. [1] https://graphql-ruby.org/schema/class_based_api.html
This commit is contained in:
committed by
Javi Martín
parent
5c6ab81c38
commit
c984e666ff
29
app/graphql/types/base_object.rb
Normal file
29
app/graphql/types/base_object.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
module Types
|
||||
class BaseObject < GraphQL::Schema::Object
|
||||
def self.field(*args, **kwargs, &block)
|
||||
super(*args, **kwargs, &block)
|
||||
|
||||
# The old api contained non-camelized fields
|
||||
# We want to support these for now, but throw a deprecation warning
|
||||
#
|
||||
# Example:
|
||||
# proposal_notifications => Deprecation warning (Old api)
|
||||
# proposalNotifications => No deprecation warning (New api)
|
||||
field_name = args[0]
|
||||
|
||||
if field_name.to_s.include?("_")
|
||||
reason = "Snake case fields are deprecated. Please use #{field_name.to_s.camelize(:lower)}."
|
||||
kwargs = kwargs.merge({ camelize: false, deprecation_reason: reason })
|
||||
super(*args, **kwargs, &block)
|
||||
end
|
||||
|
||||
# Make sure associations only return public records
|
||||
# by automatically calling 'public_for_api'
|
||||
type_class = args[1]
|
||||
|
||||
if type_class.is_a?(Class) && type_class.ancestors.include?(GraphQL::Types::Relay::BaseConnection)
|
||||
define_method(field_name) { object.send(field_name).public_for_api }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
16
app/graphql/types/comment_type.rb
Normal file
16
app/graphql/types/comment_type.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
module Types
|
||||
class CommentType < Types::BaseObject
|
||||
field :ancestry, String, null: true
|
||||
field :body, String, null: true
|
||||
field :cached_votes_down, Integer, null: true
|
||||
field :cached_votes_total, Integer, null: true
|
||||
field :cached_votes_up, Integer, null: true
|
||||
field :commentable_id, Integer, null: true
|
||||
field :commentable_type, String, null: true
|
||||
field :confidence_score, Integer, null: false
|
||||
field :id, ID, null: false
|
||||
field :public_author, Types::UserType, null: true
|
||||
field :public_created_at, String, null: true
|
||||
field :votes_for, Types::VoteType.connection_type, null: true
|
||||
end
|
||||
end
|
||||
22
app/graphql/types/debate_type.rb
Normal file
22
app/graphql/types/debate_type.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
module Types
|
||||
class DebateType < Types::BaseObject
|
||||
field :cached_votes_down, Integer, null: true
|
||||
field :cached_votes_total, Integer, null: true
|
||||
field :cached_votes_up, Integer, null: true
|
||||
field :comments, Types::CommentType.connection_type, null: true
|
||||
field :comments_count, Integer, null: true
|
||||
field :confidence_score, Integer, null: true
|
||||
field :description, String, null: true
|
||||
field :hot_score, Integer, null: true
|
||||
field :id, ID, null: false
|
||||
field :public_author, Types::UserType, null: true
|
||||
field :public_created_at, String, null: true
|
||||
field :tags, Types::TagType.connection_type, null: true
|
||||
field :title, String, null: true
|
||||
field :votes_for, Types::VoteType.connection_type, null: true
|
||||
|
||||
def tags
|
||||
object.tags.public_for_api
|
||||
end
|
||||
end
|
||||
end
|
||||
6
app/graphql/types/geozone_type.rb
Normal file
6
app/graphql/types/geozone_type.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
module Types
|
||||
class GeozoneType < Types::BaseObject
|
||||
field :id, ID, null: false
|
||||
field :name, String, null: true
|
||||
end
|
||||
end
|
||||
4
app/graphql/types/mutation_type.rb
Normal file
4
app/graphql/types/mutation_type.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
module Types
|
||||
class MutationType < Types::BaseObject
|
||||
end
|
||||
end
|
||||
14
app/graphql/types/proposal_notification_type.rb
Normal file
14
app/graphql/types/proposal_notification_type.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module Types
|
||||
class ProposalNotificationType < Types::BaseObject
|
||||
field :body, String, null: true
|
||||
field :id, ID, null: false
|
||||
field :proposal, Types::ProposalType, null: true
|
||||
field :proposal_id, Integer, null: true
|
||||
field :public_created_at, String, null: true
|
||||
field :title, String, null: true
|
||||
|
||||
def proposal
|
||||
Proposal.public_for_api.find_by(id: object.proposal)
|
||||
end
|
||||
end
|
||||
end
|
||||
32
app/graphql/types/proposal_type.rb
Normal file
32
app/graphql/types/proposal_type.rb
Normal file
@@ -0,0 +1,32 @@
|
||||
module Types
|
||||
class ProposalType < Types::BaseObject
|
||||
field :cached_votes_up, Integer, null: true
|
||||
field :comments, Types::CommentType.connection_type, null: true
|
||||
field :comments_count, Integer, null: true
|
||||
field :confidence_score, Integer, null: true
|
||||
field :description, String, null: true
|
||||
field :geozone, Types::GeozoneType, null: true
|
||||
field :geozone_id, Integer, null: true
|
||||
field :hot_score, Integer, null: true
|
||||
field :id, ID, null: false
|
||||
field :proposal_notifications, Types::ProposalNotificationType.connection_type, null: true
|
||||
field :public_author, Types::UserType, null: true
|
||||
field :public_created_at, String, null: true
|
||||
field :retired_at, GraphQL::Types::ISO8601DateTime, null: true
|
||||
field :retired_explanation, String, null: true
|
||||
field :retired_reason, String, null: true
|
||||
field :summary, String, null: true
|
||||
field :tags, Types::TagType.connection_type, null: true
|
||||
field :title, String, null: true
|
||||
field :video_url, String, null: true
|
||||
field :votes_for, Types::VoteType.connection_type, null: true
|
||||
|
||||
def tags
|
||||
object.tags.public_for_api
|
||||
end
|
||||
|
||||
def geozone
|
||||
Geozone.public_for_api.find_by(id: object.geozone)
|
||||
end
|
||||
end
|
||||
end
|
||||
107
app/graphql/types/query_type.rb
Normal file
107
app/graphql/types/query_type.rb
Normal file
@@ -0,0 +1,107 @@
|
||||
module Types
|
||||
class QueryType < Types::BaseObject
|
||||
field :comments, Types::CommentType.connection_type, "Returns all comments", null: false
|
||||
field :comment, Types::CommentType, "Returns comment for ID", null: false do
|
||||
argument :id, ID, required: true, default_value: false
|
||||
end
|
||||
|
||||
field :debates, Types::DebateType.connection_type, "Returns all debates", null: false
|
||||
field :debate, Types::DebateType, "Returns debate for ID", null: false do
|
||||
argument :id, ID, required: true, default_value: false
|
||||
end
|
||||
|
||||
field :geozones, Types::GeozoneType.connection_type, "Returns all geozones", null: false
|
||||
field :geozone, Types::GeozoneType, "Returns geozone for ID", null: false do
|
||||
argument :id, ID, required: true, default_value: false
|
||||
end
|
||||
|
||||
field :proposals, Types::ProposalType.connection_type, "Returns all proposals", null: false
|
||||
field :proposal, Types::ProposalType, "Returns proposal for ID", null: false do
|
||||
argument :id, ID, required: true, default_value: false
|
||||
end
|
||||
|
||||
field :proposal_notifications, Types::ProposalNotificationType.connection_type, "Returns all proposal notifications", null: false
|
||||
field :proposal_notification, Types::ProposalNotificationType, "Returns proposal notification for ID", null: false do
|
||||
argument :id, ID, required: true, default_value: false
|
||||
end
|
||||
|
||||
field :tags, Types::TagType.connection_type, "Returns all tags", null: false
|
||||
field :tag, Types::TagType, "Returns tag for ID", null: false do
|
||||
argument :id, ID, required: true, default_value: false
|
||||
end
|
||||
|
||||
field :users, Types::UserType.connection_type, "Returns all users", null: false
|
||||
field :user, Types::UserType, "Returns user for ID", null: false do
|
||||
argument :id, ID, required: true, default_value: false
|
||||
end
|
||||
|
||||
field :votes, Types::VoteType.connection_type, "Returns all votes", null: false
|
||||
field :vote, Types::VoteType, "Returns vote for ID", null: false do
|
||||
argument :id, ID, required: true, default_value: false
|
||||
end
|
||||
|
||||
def comments
|
||||
Comment.public_for_api
|
||||
end
|
||||
|
||||
def comment(id:)
|
||||
Comment.find(id)
|
||||
end
|
||||
|
||||
def debates
|
||||
Debate.public_for_api
|
||||
end
|
||||
|
||||
def debate(id:)
|
||||
Debate.find(id)
|
||||
end
|
||||
|
||||
def geozones
|
||||
Geozone.public_for_api
|
||||
end
|
||||
|
||||
def geozone(id:)
|
||||
Geozone.find(id)
|
||||
end
|
||||
|
||||
def proposals
|
||||
Proposal.public_for_api
|
||||
end
|
||||
|
||||
def proposal(id:)
|
||||
Proposal.find(id)
|
||||
end
|
||||
|
||||
def proposal_notifications
|
||||
ProposalNotification.public_for_api
|
||||
end
|
||||
|
||||
def proposal_notification(id:)
|
||||
ProposalNotification.find(id)
|
||||
end
|
||||
|
||||
def tags
|
||||
Tag.public_for_api
|
||||
end
|
||||
|
||||
def tag(id:)
|
||||
Tag.find(id)
|
||||
end
|
||||
|
||||
def users
|
||||
User.public_for_api
|
||||
end
|
||||
|
||||
def user(id:)
|
||||
User.find(id)
|
||||
end
|
||||
|
||||
def votes
|
||||
Vote.public_for_api
|
||||
end
|
||||
|
||||
def vote(id:)
|
||||
Vote.find(id)
|
||||
end
|
||||
end
|
||||
end
|
||||
8
app/graphql/types/tag_type.rb
Normal file
8
app/graphql/types/tag_type.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
module Types
|
||||
class TagType < Types::BaseObject
|
||||
field :id, ID, null: false
|
||||
field :kind, String, null: true
|
||||
field :name, String, null: true
|
||||
field :taggings_count, Integer, null: true
|
||||
end
|
||||
end
|
||||
9
app/graphql/types/user_type.rb
Normal file
9
app/graphql/types/user_type.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
module Types
|
||||
class UserType < Types::BaseObject
|
||||
field :id, ID, null: false
|
||||
field :public_comments, Types::CommentType.connection_type, null: true
|
||||
field :public_debates, Types::DebateType.connection_type, null: true
|
||||
field :public_proposals, Types::ProposalType.connection_type, null: true
|
||||
field :username, String, null: true
|
||||
end
|
||||
end
|
||||
9
app/graphql/types/vote_type.rb
Normal file
9
app/graphql/types/vote_type.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
module Types
|
||||
class VoteType < Types::BaseObject
|
||||
field :id, ID, null: false
|
||||
field :public_created_at, String, null: true
|
||||
field :votable_id, Integer, null: true
|
||||
field :votable_type, String, null: true
|
||||
field :vote_flag, Boolean, null: true
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user