How can I parse JSON data in Lighthouse? - graphql

I have notification table , where data field stored as json :
{"data":{"description":"Event Status has been changed to pending","event_id":19}}
I get this error
"errors": [
{
"debugMessage": "Expected a value of type \"String\" but received: {\"data\":{\"description\":\"Event Status has been changed to pending\",\"event_id\":19}}",
I have tried to add the following on notifications model:
public function getDataAttribute($data)
{
return json_decode($data, true);
}
But no solution.
I tried to use [String] in GraphQL schema but nothing.

If you want arbitrary JSON data to be returned as a string there are 2 options:
The first is to use a JSON scalar, you can either built your own or use a composer package. It wil encode the data to a valid JSON string.
The second option is to make sure you are returning just the JSON and not the decoded JSON. I'm assuming your data is already decoded to JSON because you are using model casts, if not you could just remove the json_decode call. You could add a getter to re-encode it back to JSON or add a getter to get the value from the attributes property on your model.
public function getRawDataAttribute(): string
{
return $this->attributes['data'];
}
// or
public function getRawDataAttribute(): string
{
return json_encode($this->data);
}
You can use this in your schema like this:
type MyType {
data: String! #rename(attribute: "raw_data")
}
But the first option is definitely the easiest and the best in my opinion because it correctly indicates in the schema the field contains JSON and handles the encoding (and decoding when used in inputs) for you.

Add this package for implementing JSON type to your app:
https://github.com/mll-lab/graphql-php-scalars
then add this line to your schema.graphql file:
scalar JSON #scalar(class: "MLL\\GraphQLScalars\\JSON")
After than you can easily use JSON type like this:
type MyType {
data: JSON! #rename(attribute: "raw_data")
}

Related

Go omitempty bool field- not showing false type

I have a struct
type Settings struct {
Status bool `json:"status,omitempty"`
AvailableStatus bool `json:"available_status,omitempty"`
}
I am using this struct for saving the data and displaying the data in my GOAPis
for eg if for my save data my json body is like this
{"settings":{"status":true,
"available_status":false}}
after save I fetch data data using Get-API I am getting like this
"settings": {
"status": true
}
only true data is displaying I need to display both data and need to set omitempty also(omit empty for saving, after that json created and using json I am checking validation)
How can I do this?
for saving the data, all fields are not required.
I might be able to give json like below in my apis body.
{"settings":{"status":true,
"available_status":false}}
or
{"settings":{"status":true}}
I want to do this also. I created json for each model and validation is checking in json .. If I not added omitempty field it will show error available_status is required.
Or any other method for setting available_status as required filed..
"omitempty" is omitting only when value is equal to zerovalue of chosen type. If you want to create custom json from struct you can make map from struct and use json.Marshal or other lib like https://github.com/tidwall/sjson
Use pointers
type Settings struct {
Status *bool `json:"status,omitempty"`
AvailableStatus *bool `json:"available_status,omitempty"`
}

How to define an arbitrary scalar in apollo gql?

I have a type that needs to be like the following
type ActivityPayload {
action: String!
extra: AnythingAtAll
}
Where AnythingAtAll is an arbitrary JSON format. So that's as far as I get because all the tutorials I see expect you to have a type AnythingAtAll with fields defined inside of it. How do I allow {}, or {any properties in json format no matter what the property names and values are}
Use graphql-scalars:
A library of custom GraphQL scalar types for creating precise type-safe GraphQL schemas.
This library offers also the scalar type JSON:
The JSON scalar type represents JSON values as specified by ECMA-404.
Then you can do the following:
type ActivityPayload {
action: String!
extra: JSON
}
See also graphql-type-json (JSON is based on this one).

Passing exact parameters to Web API in ASP.NET Core

I have written a Web API in ASP.NET Core, for which I need to pass 2 parameters; of them one is a string with grade, the other is of type list of studentInfo as shown here:
[HttpPost]
[Route("UpdateActiveStudents")]
public Response UpdateActiveStudents(string grade, [FromBody] List<StudentsInfo> lststudents)
{
try
{
// My Logic
}
catch(Exception ex)
{
resp.flag = false;
resp.message = ex.Message;
}
return resp;
}
To test this API, I used ARC (Advanced Rest Client). I passed the data as like this in a POST request:
{
"grade": "B",
"lststudents": [
{ "StudentName": "abcdef", "RollNo": "user1"},
{ "StudentName": "abcdef", "RollNo": "user1"}
]
}
It throws a HTTP 400 status error with the following message :
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[SchoolHub.Model.StudentList]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly. To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. Path 'lststudents', line 2, position 13.
I'm unaware of this exception.
You have this issue because you are not sending the data in the format at which ASP.Net Web API expects. ASP.net Web API needs some special format when dealing with a value like string and value type (int, bool, etc) parameter are marked with FromBody attribute.
Just remove FromBody it will work. For better understanding go with this link.
Why do we have to specify FromBody and FromUri?
In Web API, general parameter binding rules for POST method are as follows -
Query string -> Primitive type
Request body -> Complex type
Now if you want to use POST method with Mixed parameters i.e in your case you are passing primitive (string) and complex (List), Web API will get the grade parameter from query string and student parameter from the request body.
Possible solutions to try -
In the ARC request it seems you are passing grade in request body instead of as a query string parameter. Try passing grade as a query string parameter.
Also add a class viz. StudentInfoRequest to wrap List<StudentsInfo> lststudents and then use StudentInfoRequest object to pass as parameter to UpdateActiveStudents method.
You dont need to mention [FromBody] in UpdateActiveStudents method as by default complex parameters are read from the request body by Web API.
Hope this helps!
You must add [ApiController] in the controller level. Code is as follows
[ApiController]
[Route("[controller]")]
public class studentController : ControllerBase
{
[HttpPost]
[Route("UpdateActiveStudents")]
public Response UpdateActiveStudents(string grade, List<StudentsInfo>
lststudents)
{
//code
}
}

AWS AppSync GraphQL input validation - ignore extra fields?

I have an input type in my schema that specifies lots of attributes, as it's intended to do. The issue is that what I'm sending to the mutation that will persist these objects is an object with arbitrary fields that may change. As it stands, if I send attributes not specified in the schema, I get the error:
Validation error of type WrongType: argument 'input' with value (...)
contains a field not in 'BotInput': 'ext_gps' # 'setBot'
Concretely, my input type did not specify the attribute exp_gps, and that field was provided.
My Question
Is there a way to make it so the input validation simply ignores any attributes not in the schema, so that it continues to perform the mutation with only whatever was specified in the schema? It'll be often that I don't want to persist the additional attributes, so dropping them is fine, as long as the other attributes get added.
GraphQL does not support arbitrary fields, there is a RFC to support a Map type but it has not been merged/approved into the specification.
I see two possible workarounds that both require to change your schema a little bit.
Say you have the following schema:
type Mutation {
saveBot(input: BotInput) : Boolean
}
input BotInput {
id: ID!
title: String
}
and the input object is:
{
"id": "123",
"title": "GoogleBot",
"unrelated": "field",
"ext_gps": "else"
}
Option 1: Pass the arbitrary fields as AWSJSON
You would change your schema to:
type Mutation {
saveBot(input: BotInput) : Boolean
}
input BotInput {
id: ID!
title: String
arbitraryFields: AWSJSON // this will contain all the arbitrary fields in a json string, provided your clients can pluck them from the original object, make a map out of them and json serialize it.
}
So the input in our example would be now:
{
"id": "123",
"title": "GoogleBot",
"arbitraryFields": "{\"unrelated\": \"field\", \"ext_gps\": \"else\"}"
}
In your resolver, you could take the arbitraryFields string, deserialize it, and hydrate the values on the BotInput object before passing it to the data source.
Option 2: Pass the input as AWSJSON
The principle is the same but you pass the entire BotInput as AWSJSON.
type Mutation {
saveBot(input: AWSJSON) : Boolean
}
You don't have to do the resolver hydration and you don't have to change your client, but you lose the GraphQL type validation as the whole BotInput is now a blob.

Populate an object and pass it in a request parameter in GraphQL

How can we populate an object and pass it in a request parameter in GraphQL. For example, i want to get rid of sequence of parameters here in the GraphQL request and want to create an object and pass it as a single parameter.
{
allBooks(first:20, orderBy:"myRating"){
isn
title
authors
publisher
}
}
You can use GraphQL Input Types.
In your schema definition you need to define the input into something like:
input BooksInput {
first: Int
orderBy: String
}
And require it as the args type in your query, then use it as:
{
allBooks($input: {first:20, orderBy:"myRating"}){
isn
title
authors
publisher
}
}

Resources