How to simplify HTTP post of JSON to GraphQL mutation resolver - json

I would like to HTTP POST values directly as JSON to an addBook resolver already declared in my GraphQL Mutation.
However, the examples I've seen (and proven) use serialisation of parameters from JSON to SDL or re-declaration of variables in SDL to bind from a Query Variable.
Neither approach makes sense because the addBook mutation already has all parameters and validation declared. Using these approaches would lead to unnecessary query serialisation logic having to be created, debugged and maintained.
I have well-formed (schema- edited and -validated) JSON being constructed in the browser which conforms to the data of a declared GraphQLObjectType.
Can anyone explain how to avoid this unnecessary reserialisation or duplication when posting against a mutation resolver?
I've been experimenting with multiple ways of mapping a JSON data structure against the addBook mutation but can't find an example of simply sending the JSON so that property names are be bound against addBook parameter names without apparently pointless reserialisation or boilerplate.
The source code at https://github.com/cefn/graphql-gist/tree/master/mutation-map is a minimal reproducible example which demonstrates the problem. It has an addBook resolver which already has parameter names, types and nullability defined. I can't find a way to use JSON to simply POST parameters against addBook.
I'm using GraphiQL as a reference implementation to HTTP POST values.
I could write code to serialise JSON to SDL. It would end up looking like this which works through GraphiQL:
mutation {addBook(id:"4", name:"Education Course Guide", genre: "Education"){
id
}}
Alternatively I can write code to explicitly alias each parameter of addBook to a different query which then allows me to post values as a JSON query variable, also proven through GraphiQL:
mutation doAdd($id: String, $name: String!, $genre: String){
addBook(id:$id, name:$name, genre:$genre){
id
}
}
...with the query variable...
{
name: "Jonathan Livingstone Seagull",
id: "6"
}
However, I am sure there's some way to directly post this JSON against addBook, telling it to take parameters from a Query Variable. I'm imagining something like...
mutation {addBook($*){
id
}}
I would like a mutation call against addBook to succeed, taking named values from a JSON Query Variable, but without reserialisation or redeclaration of the properties to parameter names.

This boils down to schema design. Instead of having three arguments on your field
type Mutation {
addBook(id: ID, name: String!, genre: String!): Book
}
you can have a single argument that takes an input object type
type Mutation {
addBook(input: AddBookInput!): Book
}
input AddBookInput {
id: ID
name: String!
genre: String!
}
Then your query only has to provide a single variable:
mutation AddBook($input: AddBookInput!) {
addBook(input: $input) {
id
}
}
and your variables look something like:
{
"input": {
"name": "Jonathan Livingstone Seagull",
"genre": "Fable"
}
}
Variables have to be explicitly defining as part of the operation definition because GraphQL and JSON are not interchangeable. A JSON string value could be a String, an ID or some custom scalar (like DateTime) in GraphQL. The variable definitions tell GraphQL how to correctly serialize and validate the provided JSON values. Because variables can be used multiple times throughout a document, their types likewise cannot simply be inferred from the types of the arguments they are used with.
EDIT:
Variables are only declared once per document. Once declared, they may be referred to any number of times throughout the document. Imagine a query like
mutation MyMutation ($id: ID!) {
flagSomething(somethingId: $id)
addPropertyToSomething(id: $id, property: "WOW")
}
We declare the variable once and tell GraphQL it's an ID scalar and it's non-nullable (i.e. required). We then use the variable twice -- once as the value of somethingId on flagSomething and again as the value of id on addPropertyToSomething. The same variable could also be used as the value to a directive's argument too -- it's not limited to just field arguments. Notice also that nothing says the variable name has to match the field name -- this is typically only done out of convenience.
The other notable thing here is that there's two validation steps happening here.
First, GraphQL will check if the provided variable (i.e. the JSON value) can be serialized into the type specified. Since we declared the variable as non-null (using !), GraphQL will also verify the variable actually exists and is not equal to null.
GraphQL will also verify that the type you specified for the variable matches the types of the arguments where it's actually used. So an Int variable will throw if it's passed to a String argument and so on. Moreover, nullability is checked here too. So an argument that is an Int! (non-null integer) will only accept variables that are also Int!. However, an argument that is Int (i.e. nullable) will accept either Int or Int! variables.
The syntax that exists is there for a reason. The kind of syntax you're imagining would only make sense in a specific scenario where you're only querying a single root field and using all the variables as arguments to that one field and the variable names match the argument names and you don't need to dynamically set any directive arguments.

Related

A better solution to validate JSON unmarshal to nested structs

There appears to be few options to validate the source JSON used when unmarshalling to a struct. By validate I mean 3 main things:
a required field exists in the JSON
the field is the correct type (e.g. don't force a string into an integer)
the field contains a valid value (value range / enum)
For nested structs, I simply mean where an attribute in one struct has the type of another struct:
type Example struct {
Attr1 int `json:"attr1"`
Attr2 ExampleToo `json:"attr2"`
}
type ExampleToo struct {
Attr3 int `json:"attr3"`
}
And this JSON would be valid:
{"attr1": 5, "attr2": {"attr3": 0}}
To keep this simple, I'll focus simply on integers. The concept of "zero values" is the first issue. I could create an UnmarshalJSON method, which is detected by JSON packages, including the standard encoding/json package. The problem with this approach is that is that is does not support nested structs. If ExampleToo has an UnmarshalJSON method, the ExampleToo.UnmarshalJSON() method is never called if unmarshalling to an Example object. It would be possible to write a method Example.UnmarshalJSON() that recursively handled validation, but that seems extremely complex, especially if ExampleToo is reused in many places.
So there appears to be some packages like the go-playground/validator where validation can be specified both as functions and tags. However, this works on the struct created, and not the JSON itself. So if a field is tagged as validation:"required" on an integer, and the integer value is 0, this will return an error because 0 is both a valid value and the "zero value" for integers.
An example of the latter here: https://go.dev/play/p/zqSUksPzUiq
I could also use pointers for everything, checking for nil as missing values. The main problem with that is that it requires dereferencing on each use and is a pretty uncommon practice for things like integers and strings.
One thing that I have also considered is a "sister struct" that uses pointers to do validation for required fields. The process would basically be to write a validation method for each struct, then validate that sister struct. If it works, then deserialize the main struct (without pointers). I haven't started on this, just a concept I've thought about, but I'm hoping there are better validation options.
So... is there a better way to do JSON/YAML input validation on nested structs? I'm happy to mix methods where say UnmarshalJSON is used for doing some work like verifying fields exist, but I'd like to pass that back to the library to let it continue to call UnmarshalJSON on subsequent nested structs. I'd also rather defer to the JSON library for casting values into the struct, etc.

Parse value as int in HLC files

I am writing the template for a parametrized HashiCorp Nomad job. One of its parameters is priority, which is supposed to be an integer between 0 and 100.
Like other tools, Nomad supports variable interpolation, so that a variable can be defined at some point and later referenced. Nomad also allows to define "meta" variables, which are passed at runtime and can be used within the HLC file.
What I'm trying to do looks as follows:
job "my-job" {
parametrized {
meta_required = ["TASK_PRIORITY"]
}
priority = "${NOMAD_META_TASK_PRIORITY}"
...
}
The only way I have found to read those variables are within strings. Since the priority stanza expects an integer, the following error is thrown:
error parsing 'job': 1 error(s) decoding: * cannot parse 'Priority' as int: strconv.ParseInt: parsing "${NOMAD_META_TASK_PRIORITY}": invalid syntax
Is there any way to "cast" the string to an integer? Or, alternatively, is there any other way of referencing the variable that would work?
I ended up raising an issue on Github. Their response is that it's not yet possible to interpolate the priority field. See issue.

Excessive use of map[string]interface{} in go development?

The majority of my development experience has been from dynamically typed languages like PHP and Javascript. I've been practicing with Golang for about a month now by re-creating some of my old PHP/Javascript REST APIs in Golang. I feel like I'm not doing things the Golang way most of the time. Or more generally, I'm not use to working with strongly typed languages. I feel like I'm making excessive use of map[string]interface{} and slices of them to box up data as it comes in from http requests or when it gets shipped out as json http output. So what I'd like to know is if what I'm about to describe goes against the philosophy of golang development? Or if I'm breaking the principles of developing with strongly typed languages?
Right now, about 90% of the program flow for REST Apis I've rewritten with Golang can be described by these 5 steps.
STEP 1 - Receive Data
I receive http form data from http.Request.ParseForm() as formvals := map[string][]string. Sometimes I will store serialized JSON objects that need to be unmarshaled like jsonUserInfo := json.Unmarshal(formvals["user_information"][0]) /* gives some complex json object */.
STEP 2 - Validate Data
I do validation on formvals to make sure all the data values are what I expect before using it in SQL queries. I treat everyting as a string, then use Regex to determine if the string format and business logic is valid (eg. IsEmail, IsNumeric, IsFloat, IsCASLCompliant, IsEligibleForVoting,IsLibraryCardExpired etc...). I've written my own Regex and custom functions for these types of validations
STEP 3 - Bind Data to SQL Queries
I use golang's database/sql.DB to take my formvals and bind them to my Query and Exec functions like this Query("SELECT * FROM tblUser WHERE user_id = ?, user_birthday > ? ",formvals["user_id"][0], jsonUserInfo["birthday"]). I never care about the data types I'm supplying as arguments to be bound, so they're all probably strings. I trust the validation in the step immediately above has determined they are acceptable for SQL use.
STEP 4 - Bind SQL results to []map[string]interface{}{}
I Scan() the results of my queries into a sqlResult := []map[string]interface{}{} because I don't care if the value types are null, strings, float, ints or whatever. So the schema of an sqlResult might look like:
sqlResult =>
[0] {
"user_id":"1"
"user_name":"Bob Smith"
"age":"45"
"weight":"34.22"
},
[1] {
"user_id":"2"
"user_name":"Jane Do"
"age":nil
"weight":"22.22"
}
I wrote my own eager load function so that I can bind more information like so EagerLoad("tblAddress", "JOIN ON tblAddress.user_id",&sqlResult) which then populates sqlResult with more information of the type []map[string]interface{}{} such that it looks like this:
sqlResult =>
[0] {
"user_id":"1"
"user_name":"Bob Smith"
"age":"45"
"weight":"34.22"
"addresses"=>
[0] {
"type":"home"
"address1":"56 Front Street West"
"postal":"L3L3L3"
"lat":"34.3422242"
"lng":"34.5523422"
}
[1] {
"type":"work"
"address1":"5 Kennedy Avenue"
"postal":"L3L3L3"
"lat":"34.3422242"
"lng":"34.5523422"
}
},
[1] {
"user_id":"2"
"user_name":"Jane Do"
"age":nil
"weight":"22.22"
"addresses"=>
[0] {
"type":"home"
"address1":"56 Front Street West"
"postal":"L3L3L3"
"lat":"34.3422242"
"lng":"34.5523422"
}
}
STEP 5 - JSON Marshal and send HTTP Response
then I do a http.ResponseWriter.Write(json.Marshal(sqlResult)) and output data for my REST API
Recently, I've been revisiting articles with code samples that use structs in places I would have used map[string]interface{}. For example, I wanted to refactor Step 2 with a more standard approach that other golang developers would use. So I found this https://godoc.org/gopkg.in/go-playground/validator.v9, except all it's examples are with structs . I also noticed that most blogs that talk about database/sql scan their SQL results into typed variables or structs with typed properties, as opposed to my Step 4 which just puts everything into map[string]interface{}
Hence, i started writing this question. I feel the map[string]interface{} is so useful because majority of the time,I don't really care what the data is and it gives me to the freedom in Step 4 to construct any data schema on the fly before I dump it as JSON http response. I do all this with as little code verbosity as possible. But this means my code is not as ready to leverage Go's validation tools, and it doesn't seem to comply with the golang community's way of doing things.
So my question is, what do other golang developers do with regards to Step 2 and Step 4? Especially in Step 4...do Golang developers really encourage specifying the schema of the data through structs and strongly typed properties? Do they also specify structs with strongly typed properties along with every eager loading call they make? Doesn't that seem like so much more code verbosity?
It really depends on the requirements just like you have said you don't require to process the json it comes from the request or from the sql results. Then you can easily unmarshal into interface{}. And marshal the json coming from sql results.
For Step 2
Golang has library which works on validation of structs used to unmarshal json with tags for the fields inside.
https://github.com/go-playground/validator
type Test struct {
Field `validate:"max=10,min=1"`
}
// max will be checked then min
you can also go to godoc for validation library. It is very good implementation of validation for json values using struct tags.
For STEP 4
Most of the times, We use structs if we know the format and data of our JSON. Because it provides us more control over the data types and other functionality. For example if you wants to empty a JSON feild if you don't require it in your JSON. You should use struct with _ json tag.
Now you have said that you don't care if the result coming from sql is empty or not. But if you do it again comes to using struct. You can scan the result into struct with sql.NullTypes. With that also you can provide json tag for omitempty if you wants to omit the json object when marshaling the data when sending a response.
Struct values encode as JSON objects. Each exported struct field
becomes a member of the object, using the field name as the object
key, unless the field is omitted for one of the reasons given below.
The encoding of each struct field can be customized by the format
string stored under the "json" key in the struct field's tag. The
format string gives the name of the field, possibly followed by a
comma-separated list of options. The name may be empty in order to
specify options without overriding the default field name.
The "omitempty" option specifies that the field should be omitted from
the encoding if the field has an empty value, defined as false, 0, a
nil pointer, a nil interface value, and any empty array, slice, map,
or string.
As a special case, if the field tag is "-", the field is always
omitted. Note that a field with name "-" can still be generated using
the tag "-,".
Example of json tags
// Field appears in JSON as key "myName".
Field int `json:"myName"`
// Field appears in JSON as key "myName" and
// the field is omitted from the object if its value is empty,
// as defined above.
Field int `json:"myName,omitempty"`
// Field appears in JSON as key "Field" (the default), but
// the field is skipped if empty.
// Note the leading comma.
Field int `json:",omitempty"`
// Field is ignored by this package.
Field int `json:"-"`
// Field appears in JSON as key "-".
Field int `json:"-,"`
As you can analyze from above information given in Golang spec for json marshal. Struct provide so much control over json. That's why Golang developer most probably use structs.
Now on using map[string]interface{} you should use it when you don't the structure of your json coming from the server or the types of fields. Most Golang developers stick to structs wherever they can.

JSON undefined when looking with string

I'm not quite sure what my problem is here.
This is my json:
user = {
userdata: {
name: "Test"
}
}
And while user.userdata.name returns Test,
user["userdata.name"] returns undefined.
Also user["userdata"] is returning the userdata json just as well. And user["userdata"]["name"] is also returning Test.
I'm using the same method on another json, but not searching to deep. just for userdata. and there is works just fine...
And while user.userdata.name returns Test, user["userdata.name"] returns undefined.
Correct. The bit in quotes is used, in its entirety, as the property name to look up. It's not parsed. Since your user object doesn't have a property called userdata.name (it has userdata, which in turn has name), the value you get is undefined.
If you wanted to access that name with brackets notation it would be user["userdata"]["name"] (where the strings can be literal strings, as shown, or the result of any expression such as a variable lookup, string concatenation, etc.).
Can Access like this.
user["userdata"]["name"]

External Parameters in Swift

I am new on Swift, my question is where do we use and need External Parameter?
From the Apple's Swift Language Guide:
Sometimes it’s useful to name each parameter when you call a function,
to indicate the purpose of each argument you pass to the function.
If you want users of your function to provide parameter names when
they call your function, define an external parameter name for each
parameter, in addition to the local parameter name.
So, you don't "need" an external parameter name but it is a good practice to use them because they serve as documentation about the parameters at the point the method is called.
For example, without using external parameter names, you can define a join method like this:
func join(_ s1: String,_ s2: String,_ joiner: String) -> String {
return s1 + joiner + s2
}
which will then be called like this:
join("foo", "bar", ", ")
As you can see, each parameter's meaning is not very clear.
Using external parameter names, you could define the same method like below:
func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
return s1 + joiner + s2
}
which would then force the users to call it like this:
join(string: "foo", toString: "bar", withJoiner: ", ")
You can see that it makes the meaning of the parameters, along with what the method does, much more clear.
It might seem not so important in this simple example but when defining methods that take a lot of parameters with not-so-obvious meanings, using external parameter names will make your code much more easy to understand.
Update for Swift 3:
This has become even more meaningful with the introduction of Swift 3. Consider the append(contentsOf:) method of the Array class in Swift 3:
Not having different internal and external parameter names in this case would force us to change the label contentsOf to something like string in the call site, which wouldn't read as good as the former one. Swift 3 API guidelines rely on having different internal and external parameter names to create clear and concise methods.