-
Notifications
You must be signed in to change notification settings - Fork 842
I want receive a empty string on mutation #183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I'm not sure I understand your question. What should return the empty string? |
I'm not sure, but I think @michelaquino may be referring to the issue I see. Which is that I tried this in the reference JS implementation and it doesn't treat the empty string as
is fine, where as
errors with I don't see anything in the graphql spec suggesting that empty strings are treated as null. Patches welcome? |
Thank you for explaining. Yes, that seems strange. |
Hi guys, sorry for delay. Yes, this is my problem. When I create a query with empty string, I receive the response: Is the issue #178 related? |
I suppose it could be beneficial to not use any zero values as var user = {
username: null,
email: null,
createdAt: new Date()
}; Perfectly legal. However, the Go version might look like: type User struct {
Username string `json:"username"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
func NewUser() User {
return User {
CreatedAt: time.Now(),
}
} So what do you think In reality, All in all, at some point Go is not Javascript, so matching the JS implementation 1:1 is not always going to be an option. Sometimes an idiomatic Go approach should be taken here, and I tend to agree that zero values are |
@bbuck, I'll respectfully disagree. I think you are assuming an implementation for a resolver which isn't required. As per The question isn't how do golang structs map to JS structs (the GraphQL spec is clear that it isn't attempting to bind directly to any language), it's how values returned by a golang resolver are converted to values over the transport. In this case, The mapping from Go to GraphQL is perfectly clean. The empty string and FWIW, I think if you are mapping a golang struct with string-valued fields to a grapql type, those string fields should be In JS, any variable (let, const, var, object property) can be null, but that's not the same as any type being null. JS is dynamically typed. GraphQL makes a clear distinction between |
I'm not talking about implementations of resolvers. I'm talking about zero values in the Go programming language. In other words, a Unfortunately this creates a little bit of a larger problem. On the one hand, zero values are usually considered "unset." You can see this with the type User struct {
Name string `json:",omitempty"`
Age int
}
func main() {
u1 := User{Age: 21}
u2 := User{Name: "Peter", Age: 22}
uj1, _ := json.Marshal(&u1)
uj2, _ := json.Marshal(&u2)
fmt.Println(string(uj1))
fmt.Println(string(uj2))
} This is just illustrating that treating zero values as "empty" or "blank" (or What I'm trying to say is that the best, and easiest way to handle this situation is in the client. Or use a non-zero length string with something like a zero-width Unicode space (ugly hacks, yes I know). Perhaps not treating zero values as is the ideal solution. Although it breaks the use of non-pointer structs where zero-values should be failure points. My whole point boils down to no handling of zero values will serve everyone. If we wanted to do something like this we'd have to potentially encourage all consumers of the library to write their Go structs using only pointers. Which may be undesired. I'm less concerned about the implications of the consumer of the eventual GraphQL server, as that is entirely unrelated to this library and this codebase's purpose -- in other words, this library supports A Go-friendly GraphQL implementation for the server, not the client side. |
@bbuck. I'm not especially interested in a debate here. I don't really have skin in the game. I've locally patched my vendored repo of this (extremely useful -- thank you) library to have the semantics I require. It's a bummer to have to keep applying a patch, but I actually need to be able to return the empty string to clients and at the moment graphql-go literally prevents a service from returning the empty string as a value to a field which is typed either Having said that, I just don't think there's any sense in which your assertion that the empty string is somehow equivalent to null (or nil) is correct. No type theory, language that I know of, nor graphql itself take this view. It's your library. If you think this behavior makes it somehow easier to create go graphql services, then by all means keep it. |
It's not mine, I just contributed to it.
Aside from the discussion about Go and zero values (which is the actual crux of the argument) this point of mine is centered around data. Not types. A value of Aside from that though, I think I made a decent attempt at discussing why making this kind of change isn't quite as simple as you make it out to be. I get that you're coming from your singular use case at the moment. But you have to think about the fact that you're fundamentally changing behavior of a library that people other than yourself are already employing and using (as well as you) and so breaking changes like this require careful consideration. Next you should also consider the implications it has in regards to how values are normally treated in Go (as opposed to other languages) and attempt to find a solution that lets both parties settle on behavior that best fits their desires. Struct tags work partially, adding return values or extra return data from a resolver is possible, but cumbersome, and so forth. I'm trying to initiate a discussion about how to best approach introducing something like this and that begins with first understanding why it behaves as it currently does and then how best to achieve the goal of how it can behave to behoove the rest of us. In regards to having to patch it, that is pretty much the case you'll find with most large scale projects. Libraries by others for the general group of consumers are never going to fit your use case perfectly. Unless it's the exact same as the creators of the library. It seems perfectly within your rights and is expected for you to have to make modifications to reach your specific goals. It's obviously not as easy as just grabbing something from somewhere else, but it's how things go. Best of luck to you. |
@bbuck I'm honestly not trying to be a dick. Just take a step back from being defensive and consider the prospect that your premise is wrong. If graphl-go currently coerces any empty string to Whether it's prudent to make a breaking change to an API in use is without question important, but you have to be clear about whether there is a problem before you can have that discussion. |
@rafael-atticlabs I've just encountered same problem with empty string, and I totally agree with you about this. The empty string value should not be treated as |
@vietthang Here is the change we did: attic-labs@676b0c8 |
@arv thank you |
To provide another perspective on this, I've got a similar issue but I came at it from the other angle. Our DB schema is also somewhat at odds with Go's My current solution doesn't require changing graphql-go at all, so maybe it'll be useful for someone else too. // In your database/models:
type User struct {
Name sql.NullString // Or any other maybe/option/nullable type
}
// In your graphql schema, use this helper to define a nullable string field:
func resolveNullableString(p graphql.ResolveParams) (interface{}, error) {
v := reflect.ValueOf(p.Source).Elem()
if !v.IsValid() {
return nil, fmt.Errorf("Invalid elem: %v", p.Source)
}
fieldName := convertFieldName(p.Info.FieldName)
f := v.FieldByName(fieldName)
if !f.IsValid() {
return nil, fmt.Errorf("Missing field: %v", fieldName)
}
nullString := f.Interface().(sql.NullString)
if nullString.Valid {
return nullString.String, nil
}
return nil, nil
}
// You could also create other nullable types if necessary
var nullableStringField = &graphql.Field{
Type: graphql.String,
Resolve: resolveNullableString,
}
// Then define your fields using that field:
fields := graphql.Fields{
"name": nullableStringField,
} This approach seems to be working for me for the time being, hope it helps someone else. Feedback appreciated. |
The "pop" library for working with databases solves this problem quite well in my opinion. They have a nulls package, with a These types hold a value of their respective primitive type, and a |
Parents: 1651039cf4 Author: Lee Byron <lee@leebyron.com> Date: 21 January 2016 at 3:10:44 PM SGT flow type the parser --- Commit: 6f2b66df332625a8f2269836f774e91d750e00ac [6f2b66d] Parents: 4bd4b33a5a Author: Lee Byron <lee@leebyron.com> Date: 1 October 2015 at 9:21:18 AM SGT Clearer lex errors for unprintable unicode Fixes graphql-go#183 --- Commit: 969095e9f6be0bb13a69c715c6ee4910814a065b [969095e] Parents: 5d4d531f23 Author: Lee Byron <lee@leebyron.com> Date: 25 September 2015 at 6:51:32 AM SGT Commit Date: 25 September 2015 at 6:53:31 AM SGT [RFC] Clarify and restrict unicode support This proposal alters the parser grammar to be more specific about what unicode characters are allowed as source, restricts those characters interpretted as white space or line breaks, and clarifies line break behavior relative to error reporting with a non-normative note. Implements graphql/graphql-spec#96 ---
It does not affect only String, but also Float and Int where 0 and 0.0 are considered nullable values. |
Hi guys,
I have a follow mutation structure:
I want to make a query with empty string, like this:
mutation { update(id:"abc", name: "New name", gender: "") {id}}
Is it possible?
The following function in file
value.go
does the validation:Thanks
The text was updated successfully, but these errors were encountered: