How to add element on graphql return fields - ruby

Im a newbie in Ruby and GraphQL
Currently i have such Mutations module
module Mutations
class ProductCreate < BaseMutation
# TODO: define return fields
# field :post, Types::PostType, null: false
type Types::ProductType
# TODO: define arguments
argument :title, String, required: true
argument :vendor, String, required: false
argument :store, ID, required: true
# TODO: define resolve method
def resolve(title:, vendor:, store:)
Product.create!(title: title, vendor: vendor, store: store)
end
end
end
and when i call
mutation {
productCreate(input: {store:"61d6f33a58c4dc4e8a1a0536", title: "Sweet new product", vendor: "JadedPixel"})
{
_id
}
}
Result is
{
"data": {
"productCreate": {
"_id": "61de591c58c4dcb08dffafa9"
}
}
}
I would like to add additional paramenter to query and also get additional paramenter in result
So, my question is
What should i change in code
mutation {
productCreate(input: {title: "Sweet new product", productType: "Snowboard", vendor: "JadedPixel"}) {
product {
id
}
}
}
to get result like this
{
"productCreate": {
"product": {
"id": "1071559610"
}
}
}

I found solutions
Just need to change code like this
module Mutations
class ProductCreate < BaseMutation
field :product, Types::ProductType, null: true
# TODO: define arguments
argument :title, String, required: true
argument :vendor, String, required: false
argument :store, ID, required: true
# TODO: define resolve method
def resolve(title:, vendor:, store:)
record = Product.create!(title: title, vendor: vendor, store: store)
{ product: record }
end
end
end
source of an example
https://www.keypup.io/blog/graphql-the-rails-way-part-2-writing-standard-and-custom-mutations

Related

How do I accept field arguments for a nested query in Graphql Ruby?

I'm getting this error in GraphQl (Apollo JS/ Graphql Ruby):
Error Error: GraphQL error: Field 'pagination' doesn't accept argument 'pagination' GraphQL error: Variable $pagination is declared by Clients but not used. Reload the page and try again.
I have this query:
query Clients($pagination: PaginationInput) {
clients {
data {
....Fragment
}
pagination(pagination: $pagination) {
....Fragment
}
}
}
And I have this as my input type:
class PaginatedClientsType < Types::BaseObject
field :data, ...
field :pagination, PaginationType ... do
argument :pagination, PaginationInput, required: false
end
end
And this in my query_type.rb file:
field :clients, ::Types::Paginated::ClientsType, null: false do
argument :pagination, PaginationInput, required: false
end
def clients(pagination:)
...
end
// and i've added to no avail:
field :pagination ... do
argument :pagination, PaginationInput, required: false
end
def pagination(pagination:)
...
end
Any ideas on how I can pass the argument to something other than this top level client?
I've read docs here but can't figure it out.
Thanks!

passing arguments in graphQL queries

I'm just starting to learn GraphQL and I'm currently trying to create a clone of twitter. In the code below, is there a way I can pass the 81 from the id argument (e.g. user(id: 81)) automatically to the userId argument (e.g. tweets(userId: 81))?
I've copied my code below
{
user(id: 81) {
username
email
tweets(userId: 81) {
content
}
}
}
user_type.rb
module Types
class UserType < Types::BaseObject
field :username, String, null: false
field :email, String, null: false
field :bio, String, null: true
field :tweets, [Types::TweetType], null: true do
argument :user_id, ID, required: true
end
def tweets(user_id:)
Tweet.where(user_id: user_id)
end
end
end
tweet_type.rb
module Types
class TweetType < Types::BaseObject
field :id, ID, null: false
field :content, String, null: false
field :userId, ID, null: false
field :createdAt, GraphQL::Types::ISO8601DateTime, null: false
field :user, Types::UserType, null: false
end
end
query_type.rb
module Types
class QueryType < Types::BaseObject
field :tweets,
[Types::TweetType],
null: false,
description: "Returns a list of all tweets"
field :user,
Types::UserType,
null: false,
description: "Returns a list of all users" do
argument :id, ID, required: true
end
def tweets
Tweet.all
end
def user(id:)
User.find(id)
end
end
end
GraphQL has a first-class way to factor dynamic values out of the query, and pass them as a separate dictionary (variables). You would use syntax similar to that below, and can read more about it here.
query User($id: Int) {
user(id: $id) {
username
email
tweets(userId: $id) {
content
}
}
}

Ruby Nested Hash Merge

Given something like this:
hey = {
some_key: {
type: :object,
properties: {
id: { type: :string, example: '123', description: 'Id' },
created_at: { type: :string, example: '2019-02-14 14:13:55'},
updated_at: { type: :string, example: '2019-02-14 14:13:55'},
type: { type: :string, example: 'something', description: 'Resource type' },
token: { type: :string, example: 'token', description: 'Some description of token' }
}
}
}
I would like to go through all keys until I find one named properties, then mutate its content such that the keys become the value of a description key if it doesn't exit in its nested hash.
So for the example above, the hash would end up like this:
hey = {
some_key: {
type: :object,
properties: {
id: { type: :string, example: '123', description: 'Id' },
created_at: { type: :string, example: '2019-02-14 14:13:55', description: 'Created At'},
updated_at: { type: :string, example: '2019-02-14 14:13:55', description: 'Updated At'},
type: { type: :string, example: 'something', description: 'Resource type' },
token: { type: :string, example: 'token', description: 'Some description of token' }
}
}
}
created_at and updated_at didn't have a description.
It should also handle if token, for instance, had a properties property.
I came up with a solution that works but I am really curious on how I can improve it?
My solution below:
def add_descriptions(hash)
return unless hash.is_a?(Hash)
hash.each_pair do |key, value|
if key == :properties
value.each do |attr, props|
if props[:description].nil?
props.merge!(description: attr.to_s)
end
end
end
add_descriptions(value)
end
end
As I understand all you know about the hash hey is that it is comprised of nested hashes.
def recurse(h)
if h.key?(:properties)
h[:properties].each do |k,g|
g[:description] = k.to_s.split('_').map(&:capitalize).join(' ') unless
g.key?(:description)
end
else
h.find { |k,obj| recurse(obj) if obj.is_a?(Hash) }
end
end
recurse hey
#=> {:id=>{:type=>:string, :example=>"123", :description=>"Id"},
# :created_at=>{:type=>:string, :example=>"2019-02-14 14:13:55",
# :description=>"Created At"},
# :updated_at=>{:type=>:string, :example=>"2019-02-14 14:13:55",
# :description=>"Updated At"},
# :type=>{:type=>:string, :example=>"something",
# :description=>"Resource type"},
# :token=>{:type=>:string, :example=>"token",
# :description=>"Some description of token"}}
The return value is the updated value of hey.

How to populate the response model for http_code 400/401 in swagger ui using ruby?

How to populate the response model for http_code 400/401 in swagger ui using ruby? I want to add the response model for 401 error.My code looks something like this:
user_entity.rb:
module something
module V1
class UserEntity < Grape::Entity
expose :id, documentation: { type: "String", desc: "User id" }
expose :phone, documentation: { type: "String", desc: "Registered phone number" }
expose :email, documentation: { type: "String", desc: "Email" }
expose :created_at, documentation: { type: "String", desc: "format:yyyy-mm-ddThh:mm:ss.364+(gmt) for eg:\"2015-10-04T15:33:39.364+04:00\"" }
expose :updated_at, documentation: { type: "String", desc: "format:yyyy-mm-ddThh:mm:ss.364+(gmt) for eg:\"2015-10-04T15:33:39.364+04:00\"" }
expose :access_token, if: lambda { |object, options| options[:show_access_token] == true }
expose :access_token_expires, if: lambda { |object, options| options[:show_access_token] == true }
private
def id
object.id.to_s
end
end
end
end
user_resource.rb:
module something
module V1
class UsersResource < Grape::API
include something::V1::Defaults
resource :users, desc: 'Operations about users' do
desc "Returns all users", {
headers: {
"Authorization" => {description: "pass the access token as Bearer",
required: true
}
},
http_codes: [
[401, 'Not authorized: The access token does not exist or is invalid'],
[200, 'Success',UserEntity]
],
detail: 'This endpoint returns all the users that have successfully registered with a valid phone number.'
}
get do
User.all.to_a
end
.....
I figured it out myself. I just added all the error codes i needed in my defaults.rb and added it to my http_codes

how can I iterate through this json document using ruby?

I have a ruby code block, as follows:
require "elasticsearch"
require "json"
search_term = "big data"
city = "Hong Kong"
client = Elasticsearch::Client.new log: true
r = client.search index: 'candidates', body:
{
query: {
bool: {
must: [
{
match: {
tags: search_term
}
},
{
match: {
city: city
}
}
]
}
}
}
It produces multiple returns like this one:
{"_index":"candidates","_type":"data",
"_id":"AU3DyAmvtewNSFHuYn88",
"_score":3.889237,
"_source":{"first":"Kota","last":"Okayama","city":"Tokyo","designation":"Systems Engineer","email":"user#hotmail.co.jp","phone":"phone","country":"Japan","industry":"Technology","tags":["remarks","virtualization big data"]}}
I want to iterate through it and extract various elements. I have tried
data = JSON.parse(r)
data.each do |row|
puts row["_source"]["first"]
end
and the error is:
no implicit conversion of Hash into String (TypeError)
What's the best way forward on this chaps?
I have the solution, I hope it helps somebody else. It took me hours of fiddling and experimentation. Here it is:
require "elasticsearch"
require "json"
search_term = "big data"
city = "Tokyo"
client = Elasticsearch::Client.new log: true
h = client.search index: 'swiss_candidates', body:
{
query: {
bool: {
must: [
{
match: {
tags: search_term
}
},
{
match: {
city: city
}
}
]
}
}
}
data = JSON.parse(h.to_json)
data["hits"]["hits"].each do |r|
puts r["_id"]
puts r["_source"]["first"]
puts r["_source"]["tags"][1]
puts r["_source"]["screened"][0]
end
The important thing seems to be to convert the elasticsearch result into something ruby friendly.
JSON.parse expects a String containing a JSON document, but you are passing it the Hash which was returned from client.search.
I'm not entirely sure what you are trying to achieve with that, why you want to parse something which is already a Ruby Hash into a Ruby Hash.

Resources