Absinthe returns an array that contains one null value instead of an empty array - graphql

I am confused by this behavior that I'm seeing with Absinthe.
For a top-level field, e.g.
field :projects, list_of(:project) do
arg :user_id, :string
resolve(&ProjectResolver.list_projects/2)
end
If ProjectResolver.list_projects/2 returns {:ok, []}, then the JSON result will correctly be
{
"data": {
"projects": []
}
}
However, for a subfield, e.g. the tags field in
object :task do
field :id, :string
# ... Other fields
field :tags, list_of(:tag) do
resolve(&TaskResolver.list_tags/3)
end
# ... Other subfields
end
If TaskResolver.list_tags/3 returns {:ok, []}, I get
{
"data": {
"task": {
"id": "ba156cde-8c5f-4806-b161-62071b0098b3",
"tags": [
null
]
}
}
}
instead of
{
"data": {
"task": {
"id": "ba156cde-8c5f-4806-b161-62071b0098b3",
"tags": []
}
}
}
which I think should be the reasonable response.
Now the non-empty array that contains one item (null) is causing headaches for me on the frontend (apollo), and I'm not sure if there's any way I can easily work around that. It would be ideal if the data returned is an empty array in the first place, and I don't see why it's not.

Immediately after posting this question I realized that it might well be that my resolver was not returning {:ok, []} after all... Indeed, it was returning {:ok [nil]} due to the Ecto query being wrong (:left_join instead of :join). That's why the returned JSON contains [null]. I just needed to fix my resolver function to actually return {:ok, []} in this case. I guess writing about an issue does help clear your thoughts on it.

Related

Match keys with sibling object JSONATA

I have an JSON object with the structure below. When looping over key_two I want to create a new object that I will return. The returned object should contain a title with the value from key_one's name where the id of key_one matches the current looped over node from key_two.
Both objects contain other keys that also will be included but the first step I can't figure out is how to grab data from a sibling object while looping and match it to the current value.
{
"key_one": [
{
"name": "some_cool_title",
"id": "value_one",
...
}
],
"key_two": [
{
"node": "value_one",
...
}
],
}
This is a good example of a 'join' operation (in SQL terms). JSONata supports this in a path expression. See https://docs.jsonata.org/path-operators#-context-variable-binding
So in your example, you could write:
key_one#$k1.key_two[node = $k1.id].{
"title": $k1.name
}
You can then add extra fields into the resulting object by referencing items from either of the original objects. E.g.:
key_one#$k1.key_two[node = $k1.id].{
"title": $k1.name,
"other_one": $k1.other_data,
"other_two": other_data
}
See https://try.jsonata.org/--2aRZvSL
I seem to have found a solution for this.
[key_two].$filter($$.key_one, function($v, $k){
$v.id = node
}).{"title": name ? name : id}
Gives:
[
{
"title": "value_one"
},
{
"title": "value_two"
},
{
"title": "value_three"
}
]
Leaving this here if someone have a similar issue in the future.

How can I remove dot from a nested object in logstash

We have a complex object with nested fields that the field names can be dynamic and contains dot.When I try to ingest data to elasticsearch it gives me the following error
Object mapping for [x] tried to parse field [x.y] as object, but found a concrete value
One record can have key/values like a.b.c:4 and in other record it can have a.b:3. We don't have control of the source of coming data so the only option can be changing the object in logstash. Here is an example of coming object:
{
"result": "https://www.yahoo.com",
"tags": {
"url": "https://www.yahoo.com",
"projectName": "monitor",
"host": "ttt",
"dd": 12345,
"vv": "kk"
},
"timestamp": 1586599441000,
"runId": 12345,
"performance": {
"x.y.z": 31307
},
"channel": "clientperf",
"asset": {
"a.b.c": 5,
"a.b":4
}
}
as you see values inside asset and performance has dot. The fields on the roots(like runId, performance and ...) are fine. How can I resolve this either with replacing the dot in logstash or anything that doesn't give me error. I'm aware of de_dot plugin but to use it we need to specifically tell what are the name of nested fields while we cannot enforce the naming for the coming records.I also know that we probably can achieve this with ruby plugin but I have zero knowledge of ruby. Any help can be appreciated.
Could use Hash#deep_transform_keys from ActiveSupport:
class Hash
def deep_transform_keys(&block)
result = {}
each do |key, value|
result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
end
result
end
end
puts hash.deep_transform_keys { |key| key.to_s.gsub(".", "" ) }

Questions with making calls to an API

I've been working on creating a CLI gem for a job board. I've been setting up my API class, but I have been struggling to get it to work correctly in terms of successful calls; I'm using HTTParty to parse. When I have been testing this, it keeps giving me a method error for "[]". I've gone over everything, made sure the syntax is correct but have hit a wall in figuring out what seems to break this. Here is the method I created to list all of the jobs on the specific board:
def all_jobs_call
url = "https://boards-api.greenhouse.io/v1/boards/flatironschoolcareers/jobs"
response = HTTParty.get(url)
response["absolute_url"]["location"]["metadata"]["id"]["title"].each do |job|
absolute_url = job["absolute_url"]
location = job["location"]
metadata = job["metadata"]
id = job["id"]
title = job["title"]
end
end
I would greatly appreciate any insight as to what I could be doing wrong or if I'm missing something glaring. Thanks!
The JSON response you get from https://boards-api.greenhouse.io/v1/boards/flatironschoolcareers/jobs looks like this:
{
"jobs": [
{
"absolute_url": "https://boards.greenhouse.io/flatironschoolcareers/jobs/4460392002",
"internal_job_id": 4375855002,
"location": {
"name": "New York, NY"
},
"metadata": [
{
"id": 4019377002,
"name": "Employment Type",
"value": "Full-time",
"value_type": "single_select"
},
...
HTTParty converts that response to Ruby objects. So just like in that JSON response, response has a top level "jobs" key which contains an array of jobs.
In order to get the 1st job you'd use:
response["jobs"][0]
#=> {"absolute_url"=>"https://boa...", "internal_job_id"=>4375855002, ...}
and to get it's absolute_url:
response["jobs"][0]["absolute_url"]
#=> "https://boards.greenhouse.io/flatironschoolcareers/jobs/4460392002"
And to traverse all jobs you call each on the array, i.e.:
response["jobs"].each do |job|
puts job["absolute_url"]
end
Output:
https://boards.greenhouse.io/flatironschoolcareers/jobs/4460392002
https://boards.greenhouse.io/flatironschoolcareers/jobs/4460383002
https://boards.greenhouse.io/flatironschoolcareers/jobs/4472889002
...

Parsing HTTParty response

I'm using HTTParty to pull a list of a Facebook user's books but I'm having trouble parsing the response:
Facebook returns data this way:
{
"data": [
{
"name": "Title",
"category": "Book",
"id": "21192118877902",
"created_time": "2011-11-11T20:50:47+0000"
},
{
"name": "Title 2",
"category": "Book",
"id": "1886126860176",
"created_time": "2011-11-05T02:35:56+0000"
},
And HTTParty parses that into a ruby object. I've tried something like this (where ret is the response) ret.parsed_response and that returns the data array, but actually accessing the items inside returns a method not found error.
This is a sample of what HTTParty actually returns:
#<HTTParty::Response:0x7fd0d378c188 #parsed_response={"data"=>
[{"name"=>"Title", "category"=>"Book", "id"=>"21192111877902", "created_time"=>"2011-11-11T20:50:47+0000"},
{"name"=>"Title 2", "category"=>"Book", "id"=>"1886126860176", "created_time"=>"2011-11-05T02:35:56+0000"},
{"name"=>"Thought Patterns", "category"=>"Book", "id"=>"109129539157186", "created_time"=>"2011-10-27T00:00:16+0000"},
Do you have any code that is throwing an error? The parsed_response variable from the HTTParty response is a hash, not an array. It contains one key, "data" (the string, NOT the symbol). The value for the "data" key in the hash is an array of hashes, so you would iterate as such:
data = ret.parsed_response["data"]
data.each do |item|
puts item["name"]
puts item["category"]
puts item["id"]
# etc
end
Just an additional info - It's Not Always a default JSON response
HTTParty's result.response.body or result.response.parsed_response does not always have form of a Hash
It just depends generally on the headers which you are using in your request. For e.g., you need to specify Accept header with application/json value while hitting GitHub API, otherwise it simply returns as string.
Then you shall have to use JSON.parse(data) for same to convert the string response into Hash object.

Efficiently check that a JSON response contains a specific element within an array

Given the JSON response:
{
"tags": [
{
"id": 81499,
"name": "sign-in"
},
{
"id": 81500,
"name": "user"
},
{
"id": 81501,
"name": "authentication"
}
]
}
Using RSpec 2, I want to verify that this response contains the tag with the name authentication. Being a fairly new to Ruby, I figured there is a more efficient way than iterating the array and checking each value of name using include? or map/collect. I could simply user a regex to check for /authentication/i but that doesn't seem like the best approach either.
This is my spec so far:
it "allows filtering" do
response = #client.story(15404)
#response.tags.
end
So, if
t = JSON.parse '{ ... }'
Then this expression will either return nil, which is false, or it will return the thing it detected, which has a boolean evaluation of true.
t['tags'].detect { |e| e['name'] == 'authentication' }
This will raise NoMethodError if there is no tags key. I think that's handled just fine in a test, but you can arrange for that case to also show up as false (i.e., nil) with:
t['tags'].to_a.detect { |e| e['name'] == 'authentication' }

Resources