graphql / graphql-js

A reference implementation of GraphQL for JavaScript
http://graphql.org/graphql-js/
MIT License
20.02k stars 2.02k forks source link

JSON-LD support? #271

Closed kevinSuttle closed 8 years ago

kevinSuttle commented 8 years ago

I know GraphQL theoretically has no problem fetching data in JSON-LD format, but I'm wondering if there could be more 1st-class support for:

etc.

akuckartz commented 8 years ago

:+1:

leebyron commented 8 years ago

Thanks for opening this. There are two topics this address that I'd like to tackle soon.

The first is normalized responses. While GraphQL operates over data modeled as a graph, it's response format looks decidedly tree-shaped not graph-shaped. The "-LD" part of JSON-LD is a critical addition to model a whole graph. There is a lot to this topic and decisions on how to address this will have implications both on how to model async and live queries where a server may want to issue "diffs" after an initial payload as well as implications on client code. Where JSON is widely accepted, anything other than vanilla JSON will require additional work by clients, so we want to settle on a common ground that weighs these things carefully.

The second is custom response formats. Right now graphql-js simply produces a (JSON compatible) JavaScript object given a GraphQL query, with the assumption that you'll call JSON.stringify before sending it back over the network. It's totally reasonable to think that you might want to produce a different output format, both for supporting normalized linked-data responses, but also for supporting other types of responses like creating Immutable.js collections to send via transit-js or for creating Protocol Buffers.

leebyron commented 8 years ago

Another interesting JSON format is jsongraph which represents more specific graph formalisms using JSON.

kevinSuttle commented 8 years ago

@leebyron I was thinking about support of JSON-LD specifically because of its relationship to the underlying tech that powers search engines.

https://schema.org/docs/about.html

kevinSuttle commented 8 years ago

Interesting comment in this article:

I'd be tempted to make the server send back some JSON-LD to help here: each object (the user object and the profileData subobject) can have an @id for its canonical URL and a @type as a type designator. A client-side cache could exploit this @id information to store information about the objects it already knows about. Client-side code could also use this information to deal with normalized APIs transparently: it can automatically fetch the sub-object for you if it's not embedded, at the cost of performance.

kevinSuttle commented 8 years ago

cc: @schrockn @dschafer

kevinSuttle commented 8 years ago

"Comparing GraphQL with SPARQL and JSON-LD Framing" https://lists.w3.org/Archives/Public/public-linked-json/2015Feb/0010.html

venturecommunism commented 8 years ago

+1 to JSON-LD

leebyron commented 8 years ago

Thanks for the link, that was an interesting read!

I think what would help enable next steps is to move backwards from the specific technology of JSON-LD and talk instead about the specific features and semantics we want to enable.

I'm only so familiar with JSON-LD so I defer to your experience with it, but my understanding is that the core premise is that various JSON documents served from URIs can refer to one another via IRI ids. I'm not sure I understand how that relates to GraphQL which is more of an RPC or query language that happens to return results in JSON by default. There is usually no concept of URIs or individual documents. So I'm a little concerned that the initial premise is flawed.

Some problems JSON-LD solves are very relevant though! Particularly interesting are "graph mode" which allows the representation of a true representation of a directed-graph (even containing cycles!) where plain JSON does not. That's also predicated on having a common ID format, which is something that we currently leave to the developer but could be valuable to standardize.

Another interesting element to JSON-LD is the notation for types and contexts for interpreting those types. GraphQL has this today by querying "__typename" and via introspection you can see the whole schema that applies (as I understand the equivalent to context)

Another question I have is if it's not just the individual features and semantics that interest you but the ability to inter-operate with non-GraphQL based JSON-LD. If so, I'm curious what you think this should look like.

I found a perhaps relevant presentation about MongoDB + JSON-LD. It's still a little too reliant on HTTP in particular to apply directly to our protocol agnostic spec, but perhaps can provide some insight: https://www.slideshare.net/mobile/gkellogg1/jsonld-and-mongodb

venturecommunism commented 8 years ago

I want to be able to say that two URIs are the same in some philosophical or practical sense as each other, in some context, for some purpose, and still know which one I'm looking at either by looking at the key or the key's namespace.

kevinSuttle commented 8 years ago

So, maybe let's focus on one major use case (which GraphQL may have its own methods of doing now—I'm not totally sure):

Formal relationship definitions

The expansion/compaction is confusing at first. Think of it like relative URLs. The @context is what allows that, and in a way that is both human-friendly, and machine-friendly.

Here's an example: npm uses a schema from http://schema.org to render package metadata on their site.

https://github.com/npm/newww/blob/master/templates/package/show.hbs#L232 https://www.npmjs.com/package/graphql

joshblack commented 8 years ago

I think it's important to note that in terms of what is machine/human-readable, this is the role of GraphQL's underlying type system. If we take a schema from schema.org, for example a person:

{
  "@context": "http://schema.org",
  "@type": "Person",
  "address": {
    "@type": "PostalAddress",
    "addressLocality": "Seattle",
    "addressRegion": "WA",
    "postalCode": "98052",
    "streetAddress": "20341 Whitworth Institute 405 N. Whitworth"
  },
  "colleague": [
    "http://www.xyz.edu/students/alicejones.html",
    "http://www.xyz.edu/students/bobsmith.html"
  ],
  "email": "mailto:jane-doe@xyz.edu",
  "image": "janedoe.jpg",
  "jobTitle": "Professor",
  "name": "Jane Doe",
  "telephone": "(425) 123-4567",
  "url": "http://www.janedoe.com"
}

We can easily model the type using GraphQL, as well as its relationships, using the underlying type system:

const personType = new GraphQLObjectType({
  name: 'Person',
  description: 'A person in our product',
  fields: () => ({
    address: {
      type:  addressType
    },
    colleagues: {
      // Note the recursive type in this case
      type: new GraphQLList(personType)
    },
    // ...
  })
});

These types are accessible to clients through introspection, and ultimately allow users to validate queries against the schema for the information that they are requesting.

Where JSON-LD will validate properties according to urls, http://schema.org/person for example, GraphQL leverages types that you define in your system. The expansion and compaction algorithms that change person to http://schema.org/person and http://schema.org/person to person respectively are unnecessary in a GraphQL context, as queries ask for the name that you would want to work with, person in this example. No mapping from name --> URI given a context is necessary.

venturecommunism commented 8 years ago

GraphQL is "leveraging" that everyone has to reinvent their own types as opposed to they have the option to swap out their own types that also have URLs that they also have the option to expose or not expose?

leebyron commented 8 years ago

I think @joshblack hit the nail on the head here with regards to your use case, @kevinSuttle.

For GraphQL clients, fields are already well defined with regards to their types. GraphQL has the same goal that JSON-LD has to maintain both human and computer legibility, but as far as I can understand from my reading on JSON-LD, GraphQL is accomplishing the same thing but just using a different mechanism. Instead of including information about the types inline with the response itself, it is accessible out of band via the introspection system.

You can kind of think about this like a programming language that has a type system. When passing values around, fields have meaning without requiring an additional step like expansion.

@venturecommunism I'm not sure I understand your question, but sort of regardless of who originally "defined" a type: schema.org or any developer, you still need to express the mapping between a type's fields and what execution behavior should occur within a GraphQL server. People are of course welcome to mirror a type defined by schema.org if they want to, but also by no means are they required to.

As far as URLs are concerned, GraphQL is agnostic to them. GraphQL is a protocol that is not defined by HTTP or even URLs. Introspection is our mechanism for exposing type information from a GraphQL server, similar to how you might use a URL to a schema.org type from a JSON-LD body.

leebyron commented 8 years ago

So @kevinSuttle I'm curious what you think the next steps should be for any kind of JSON-LD support. Here are my thoughts at this point:

It seems like there are two categories of things to tackle:

Can graphql-js in particular as a library support building responses in forms other than vanilla JSON?

I think this is a valuable task in it's own right. The GraphQL spec is written to say it is agnostic to response format but uses JSON in examples for simplicity's sake. It makes sense that for this library to support other response formats we need a mechanism for "plugging in" your own response building. That could enable others to build support for JSON-LD, json-graph, transit-js, not to mention non-JSON based formats like protocol buffers or the like.

JSON-LD would likely be one of the most simple formats to enable since it's such a small set of additions to vanilla JSON.

Does GraphQL support the features relevant to enabling the nicer features of JSON-LD?

Since GraphQL is agnostic to response format, it's not going to specify that you must return JSON-LD and therefore support for JSON-LD doesn't enable new features in GraphQL, instead it needs to be the opposite: features in JSON-LD are only possible if they're also already possible in GraphQL.

Regarding your suggestions in your original message:

Schema validation

From what I understand, this is just a matter of letting tools from Google have a look at your responses. If I understand correctly this means GraphQL doesn't need to do anything other than provide a response. Of course GraphQL should only provide valid responses and because GraphQL is backed by a type system and only executes validated queries, responses are be definitionally valid to the schema they were run against. You may not even need to use Google's validation tools other than making sure any added JSON-LD specific bits are correct.

expansion/contraction

I think we covered this above. Since GraphQL is already based on a strong type system, every field returned is already machine readable, the only thing that we need to do to enable a JSON-LD response plugin is ensure we're telling response builders what type we're using so the plugin can take responsibility for adding the @context and @type fields were appropriate.

@embed, @link

I'm a lot less clear on what these are used for in JSON-LD, it seems from your links that these are still under discussion and don't have firm semantics yet? Perhaps you could help me understand their purpose relative to JSON-LD as well as what GraphQL needs to do to enable support for it.

leebyron commented 8 years ago

Also, one thing I should make pretty clear - which maybe gets to your premise about a relationship to search engines - GraphQL is not about providing publicly accessible structured data on the internet, it's about providing access to data given the needs of a client (typically a mobile app or client-rendered website). Even if your GraphQL server seeks to be a publicly accessible API on the internet, those who use it will still need to know that it's a GraphQL server since accessing the URL serving a GraphQL server without supplying a query should not return any data. I doubt that any search engine will be making GraphQL queries any time soon, nor should they. Of course, if you are already using GraphQL and want to generate indexable URLs of structured data, it does seem like a cool idea to have a small layer of indirection that simply runs a GraphQL query and exposes the result as JSON-LD via a URL.

venturecommunism commented 8 years ago

Maybe if the client and the server accessed data in the same way we could just map the fields from types we have execution logic for to the fields for the types we don't instead of proliferating the number of fields and types everyone has to write execution logic for.

leebyron commented 8 years ago

I don't follow your suggestion @venturecommunism, could you offer an example of what you're referring to?

venturecommunism commented 8 years ago

You say "GraphQL is a protocol that is not defined by HTTP or even URLs."

Why not URIs which are also HTTP agnostic?

In fact, instead of a Resource let's call it a Bagel.

Is GraphQL agnostic about Bagel Universality?

I realize Google just bought Metaweb so this example subject to change: http://www.freebase.com/m/01fb_0

This one less so: https://www.w3.org/TR/2007/WD-curie-20070307/

Contrast with: http://graph.facebook.com/

{ "error": { "message": "Unsupported get request. Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api", "type": "GraphMethodException", "code": 100, "fbtrace_id": "Gq77cdGd3hi" } }

venturecommunism commented 8 years ago

This got cut out: http://www.markus-lanthaler.com/hydra/console/?url=http://www.markus-lanthaler.com/hydra/event-api/

It's a self-describing documentation Bagel.

leebyron commented 8 years ago

I think using URI/IRI is a good thing. GraphQL is currently agnostic to identifiers of any kind in order to allow people to use whatever kind they like, though some of our future proposals will need some form of unique identifiers and likely will tighten up what GraphQL expects vs what it is agnostic to.

My only point with my comment before that you quoted is that GraphQL is not originally intended to fill a role of being public internet available search engine indexable content. If someone wants to back a page that is search engine indexable with GraphQL then that's all well and good.

I'm just trying to help set expectations and goals to guide any discussion about new features.

venturecommunism commented 8 years ago

I didn't mean to imply that everything should be about the web. I merely linked you things using http URIs in an attempt to find a way to show you examples over Github of URI/IRI driven development such as Hydra-API :)

Thanks for explaining to me some of what we can look forward to!

Cheers,

VC

leebyron commented 8 years ago

Closing this issue since it's been fully discussed. I think it's safe to say that JSON-LD is still an interesting format and an interesting custom serialization format should someone wish to use it (as GraphQL is agnostic to serialization formats), but unlikely to replace vanilla JS for this reference library's default.

kevinSuttle commented 8 years ago

Great discussion. Thanks for the comprehensive explanations, all.

kevinSuttle commented 8 years ago

Amazon has just open sourced a new data interchange format called Ion. https://news.ycombinator.com/item?id=11546098

linonetwo commented 7 years ago

@kevinSuttle I think JSON-LD support is good for cascading GraphQL Schema.

What do you think?

https://github.com/graphql/graphql-js/issues/490#issuecomment-266207154

maximveksler commented 5 years ago

Hi,

Maintainer of https://github.com/semantalytics/awesome-semantic-web here.

I realise this issue has been closed, but since it's one of the top hits in Google for GraphQL & json-ld I would like to add a few data points to the discussion. I ask for input as I might end up implementing something internally that takes GraphQL as input and returns JSON-LD as output, which will eventually could get open sourced.

  1. There was recently a paper discussing exposing SPARQL endpoints using REST and returning using tree like JSON. Assuming the REST part is replaced with GraphQL, the return format could be adapted for when querying RDF end point. https://2018.eswc-conferences.org/files/posters-demos/paper_240.pdf also related to the discussing would be https://github.com/persvr/rql

  2. I've seen people mentioning schema exposing, here are 2 more data points that could be of interest https://github.com/common-workflow-language/schema_salad for defining data schema flows, 2. https://json-schema.org

akuckartz commented 5 years ago

See also:

GraphQL-LD: Linked Data Querying with GraphQL https://comunica.github.io/Article-ISWC2018-Demo-GraphQlLD/