graphql / graphql-spec

GraphQL is a query language and execution engine tied to any backend service.
https://spec.graphql.org
14.31k stars 1.12k forks source link

Consider allowing use of '-' & '/' characters in names, enums if possible #779

Open imaksp opened 4 years ago

imaksp commented 4 years ago

Currently name regex only allows limited characters, it would be good if it can add support for - & / characters.

data {
  "application/json": "test",
  "en-GB":  "test",
  "C-AR/A": "test value",
  "C-U": "test"
}
ccbrown commented 4 years ago

Names in GraphQL are limited to this ASCII subset of possible characters to support interoperation with as many other systems as possible.

https://spec.graphql.org/June2018/#sec-Names

A really nice property of GraphQL names is that they're also valid variable names for virtually all major programming languages. I'd hate to see that go.

softwareplumber commented 3 years ago

IMHO the character set constraint is unnecessarily onerous. Many JSON APIs out there already use all kinds of special characters - it's really common to see field names starting with $ or / which mark a field as having some special significance - for example the IPLD DAG for JSON uses '/' as a field name for links. Far from supporting interoperation, limiting the set of characters makes it harder to add graphQL any existing API. If interoperability is a design requirement for a new API, there is nothing that forces the developer to use these special characters. Recommend instead following the JSON rules for property names, and where issues exist in a given target language simply following whatever workarounds have already been developed for mapping in JSON.

mdecurtins commented 2 years ago

I'd also like to see additional characters allowed specifically in enum members, e.g. + (as well as - and /). (I'm less concerned with type names, but maybe someone else has a need for that.)

As an example, I need to represent letter grades (e.g. A+, A, A-, etc.), which seems like a natural fit for an enum, since letter grades are usually a fixed set of unique elements. What I'd like is to be able to write the obvious enum, i.e.

enum LetterGrade {
  A+
  A
  A-
  B+
  B
  B-
  C+
  etc...
}

I can't, however, because GraphQL doesn't allow + or - in enum members. Instead, I'd have to do something like this:

enum LetterGrade {
  A_PLUS
  A
  A_MINUS
  B_PLUS
  etc...
}

This is mildly annoying because now I need a client-side transform to change the enum value into the more common letter grade format (A+, A-, etc.).

Libraries like graphql-tools do let you specify resolvers for your enum values (see https://www.graphql-tools.com/docs/scalars#internal-values), but crucially the docs note that "These don't change the public API at all" (emphasis mine). This solves the internal side, because the letter grades will ultimately be stored in their common format, but it still leaves the public-facing side of the API with enum members that have to be manipulated for display to the user, even though they don't differ from how they will be stored.

rivantsov commented 2 years ago

This is mildly annoying because now I need a client-side transform to change the enum value into the more common letter grade format (A+, A-, etc.).

There is a generic principle that should be followed: internal 'code' names and user visible labels are completely different set of tokens, and live in separate universes, and should never be mixed up. I think most devs out there will agree.

There is a temptation sometimes to directly use the enum value (or some other internal code name) as a user-visible label/token in UI - why not, they are the same. But it is dangerous path; for one thing it never works with localization (when app supports multiple UI languages); the other example is when you need to add a two-word enum value to already existing enum.

Your case with grades, although seems reasonable, is a rare corner case. I do not think it's worth changing GraphQL syntax for this rare case. By the way, what if there are countries/colleges that use some other extra chars in grades? like A* ? should we then change syntax again?

mdecurtins commented 2 years ago

There is a generic principle that should be followed: internal 'code' names and user visible labels are completely different set of tokens, and live in separate universes, and should never be mixed up. I think most devs out there will agree.

Yes, I am completely aware of this, and I practice this elsewhere in my schema and my back-end code. I was going to mention something about that in my original comment but left it out because it didn't seem necessary. I was giving an example of a natural, and fairly common in real life, set of enumerated values, and how a slightly less restrictive character set for enum members would be helpful.

To be clear, I can accomplish what I need to do with GraphQL as it exists right now, just in a way that is more verbose.

jord1e commented 2 years ago

I think we should not do this, but regarding letter grades:

This is mildly annoying because now I need a client-side transform to change the enum value into the more common letter grade format (A+, A-, etc.).

You could do this:

type LetterGrade {
  normalized: NormalizedLetterGrade
  textRepresentation: String
}

enum NormalizedLetterGrade {
  A_PLUS
  A
  A_MINUS
  B_PLUS
  etc...
}

You can even add something like a hexColor: String to give even more control to your backend. When adding something like themes this can then be transformed to hexColor(theme: MyTheme = LIGHT): String - it will still be backwards-compatible

GraphQL is really expressive this way, just carefully consider what you want on the frontend, and what you want on the backend.