Giter VIP home page Giter VIP logo

graphql-spec's Introduction

GraphQL

GraphQL Logo

The GraphQL specification is edited in the markdown files found in /spec the latest release of which is published at https://graphql.github.io/graphql-spec/.

The latest draft specification can be found at https://graphql.github.io/graphql-spec/draft/ which tracks the latest commit to the main branch in this repository.

Previous releases of the GraphQL specification can be found at permalinks that match their release tag. For example, https://graphql.github.io/graphql-spec/October2016/. If you are linking directly to the GraphQL specification, it's best to link to a tagged permalink for the particular referenced version.

Overview

This is a Working Draft of the Specification for GraphQL, a query language for APIs created by Facebook.

The target audience for this specification is not the client developer, but those who have, or are actively interested in, building their own GraphQL implementations and tools.

In order to be broadly adopted, GraphQL will have to target a wide variety of backend environments, frameworks, and languages, which will necessitate a collaborative effort across projects and organizations. This specification serves as a point of coordination for this effort.

Looking for help? Find resources from the community.

Getting Started

GraphQL consists of a type system, query language and execution semantics, static validation, and type introspection, each outlined below. To guide you through each of these components, we've written an example designed to illustrate the various pieces of GraphQL.

This example is not comprehensive, but it is designed to quickly introduce the core concepts of GraphQL, to provide some context before diving into the more detailed specification or the GraphQL.js reference implementation.

The premise of the example is that we want to use GraphQL to query for information about characters and locations in the original Star Wars trilogy.

Type System

At the heart of any GraphQL implementation is a description of what types of objects it can return, described in a GraphQL type system and returned in the GraphQL Schema.

For our Star Wars example, the starWarsSchema.ts file in GraphQL.js defines this type system.

The most basic type in the system will be Human, representing characters like Luke, Leia, and Han. All humans in our type system will have a name, so we define the Human type to have a field called "name". This returns a String, and we know that it is not null (since all Humans have a name), so we will define the "name" field to be a non-nullable String. Using a shorthand notation that we will use throughout the spec and documentation, we would describe the human type as:

type Human {
  name: String
}

This shorthand is convenient for describing the basic shape of a type system; the JavaScript implementation is more full-featured, and allows types and fields to be documented. It also sets up the mapping between the type system and the underlying data; for a test case in GraphQL.js, the underlying data is a set of JavaScript objects, but in most cases the backing data will be accessed through some service, and this type system layer will be responsible for mapping from types and fields to that service.

A common pattern in many APIs, and indeed in GraphQL is to give objects an ID that can be used to refetch the object. So let's add that to our Human type. We'll also add a string for their home planet.

type Human {
  id: String
  name: String
  homePlanet: String
}

Since we're talking about the Star Wars trilogy, it would be useful to describe the episodes in which each character appears. To do so, we'll first define an enum, which lists the three episodes in the trilogy:

enum Episode {
  NEWHOPE
  EMPIRE
  JEDI
}

Now we want to add a field to Human describing what episodes they were in. This will return a list of Episodes:

type Human {
  id: String
  name: String
  appearsIn: [Episode]
  homePlanet: String
}

Now, let's introduce another type, Droid:

type Droid {
  id: String
  name: String
  appearsIn: [Episode]
  primaryFunction: String
}

Now we have two types! Let's add a way of going between them: humans and droids both have friends. But humans can be friends with both humans and droids. How do we refer to either a human or a droid?

If we look, we note that there's common functionality between humans and droids; they both have IDs, names, and episodes in which they appear. So we'll add an interface, Character, and make both Human and Droid implement it. Once we have that, we can add the friends field, that returns a list of Characters.

Our type system so far is:

enum Episode {
  NEWHOPE
  EMPIRE
  JEDI
}

interface Character {
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]
}

type Human implements Character {
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]
  homePlanet: String
}

type Droid implements Character {
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]
  primaryFunction: String
}

One question we might ask, though, is whether any of those fields can return null. By default, null is a permitted value for any type in GraphQL, since fetching data to fulfill a GraphQL query often requires talking to different services that may or may not be available. However, if the type system can guarantee that a type is never null, then we can mark it as Non Null in the type system. We indicate that in our shorthand by adding an "!" after the type. We can update our type system to note that the id is never null.

Note that while in our current implementation, we can guarantee that more fields are non-null (since our current implementation has hard-coded data), we didn't mark them as non-null. One can imagine we would eventually replace our hardcoded data with a backend service, which might not be perfectly reliable; by leaving these fields as nullable, we allow ourselves the flexibility to eventually return null to indicate a backend error, while also telling the client that the error occurred.

enum Episode {
  NEWHOPE
  EMPIRE
  JEDI
}

interface Character {
  id: String!
  name: String
  friends: [Character]
  appearsIn: [Episode]
}

type Human implements Character {
  id: String!
  name: String
  friends: [Character]
  appearsIn: [Episode]
  homePlanet: String
}

type Droid implements Character {
  id: String!
  name: String
  friends: [Character]
  appearsIn: [Episode]
  primaryFunction: String
}

We're missing one last piece: an entry point into the type system.

When we define a schema, we define an object type that is the basis for all query operations. The name of this type is Query by convention, and it describes our public, top-level API. Our Query type for this example will look like this:

type Query {
  hero(episode: Episode): Character
  human(id: String!): Human
  droid(id: String!): Droid
}

In this example, there are three top-level operations that can be done on our schema:

  • hero returns the Character who is the hero of the Star Wars trilogy; it takes an optional argument that allows us to fetch the hero of a specific episode instead.
  • human accepts a non-null string as a query argument, a human's ID, and returns the human with that ID.
  • droid does the same for droids.

These fields demonstrate another feature of the type system, the ability for a field to specify arguments that configure their behavior.

When we package the whole type system together, defining the Query type above as our entry point for queries, this creates a GraphQL Schema.

This example just scratched the surface of the type system. The specification goes into more detail about this topic in the "Type System" section, and the type directory in GraphQL.js contains code implementing a specification-compliant GraphQL type system.

Query Syntax

GraphQL queries declaratively describe what data the issuer wishes to fetch from whoever is fulfilling the GraphQL query.

For our Star Wars example, the starWarsQueryTests.js file in the GraphQL.js repository contains a number of queries and responses. That file is a test file that uses the schema discussed above and a set of sample data, located in starWarsData.js. This test file can be run to exercise the reference implementation.

An example query on the above schema would be:

query HeroNameQuery {
  hero {
    name
  }
}

The initial line, query HeroNameQuery, defines a query with the operation name HeroNameQuery that starts with the schema's root query type; in this case, Query. As defined above, Query has a hero field that returns a Character, so we'll query for that. Character then has a name field that returns a String, so we query for that, completing our query. The result of this query would then be:

{
  "hero": {
    "name": "R2-D2"
  }
}

Specifying the query keyword and an operation name is only required when a GraphQL document defines multiple operations. We therefore could have written the previous query with the query shorthand:

{
  hero {
    name
  }
}

Assuming that the backing data for the GraphQL server identified R2-D2 as the hero. The response continues to vary based on the request; if we asked for R2-D2's ID and friends with this query:

query HeroNameAndFriendsQuery {
  hero {
    id
    name
    friends {
      id
      name
    }
  }
}

then we'll get back a response like this:

{
  "hero": {
    "id": "2001",
    "name": "R2-D2",
    "friends": [
      {
        "id": "1000",
        "name": "Luke Skywalker"
      },
      {
        "id": "1002",
        "name": "Han Solo"
      },
      {
        "id": "1003",
        "name": "Leia Organa"
      }
    ]
  }
}

One of the key aspects of GraphQL is its ability to nest queries. In the above query, we asked for R2-D2's friends, but we can ask for more information about each of those objects. So let's construct a query that asks for R2-D2's friends, gets their name and episode appearances, then asks for each of their friends.

query NestedQuery {
  hero {
    name
    friends {
      name
      appearsIn
      friends {
        name
      }
    }
  }
}

which will give us the nested response

{
  "hero": {
    "name": "R2-D2",
    "friends": [
      {
        "name": "Luke Skywalker",
        "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"],
        "friends": [
          { "name": "Han Solo" },
          { "name": "Leia Organa" },
          { "name": "C-3PO" },
          { "name": "R2-D2" }
        ]
      },
      {
        "name": "Han Solo",
        "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"],
        "friends": [
          { "name": "Luke Skywalker" },
          { "name": "Leia Organa" },
          { "name": "R2-D2" }
        ]
      },
      {
        "name": "Leia Organa",
        "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"],
        "friends": [
          { "name": "Luke Skywalker" },
          { "name": "Han Solo" },
          { "name": "C-3PO" },
          { "name": "R2-D2" }
        ]
      }
    ]
  }
}

The Query type above defined a way to fetch a human given their ID. We can use it by hard-coding the ID in the query:

query FetchLukeQuery {
  human(id: "1000") {
    name
  }
}

to get

{
  "human": {
    "name": "Luke Skywalker"
  }
}

Alternately, we could have defined the query to have a query parameter:

query FetchSomeIDQuery($someId: String!) {
  human(id: $someId) {
    name
  }
}

This query is now parameterized by $someId; to run it, we must provide that ID. If we ran it with $someId set to "1000", we would get Luke; set to "1002", we would get Han. If we passed an invalid ID here, we would get null back for the human, indicating that no such object exists.

Notice that the key in the response is the name of the field, by default. It is sometimes useful to change this key, for clarity or to avoid key collisions when fetching the same field with different arguments.

We can do that with field aliases, as demonstrated in this query:

query FetchLukeAliased {
  luke: human(id: "1000") {
    name
  }
}

We aliased the result of the human field to the key luke. Now the response is:

{
  "luke": {
    "name": "Luke Skywalker"
  }
}

Notice the key is "luke" and not "human", as it was in our previous example where we did not use the alias.

This is particularly useful if we want to use the same field twice with different arguments, as in the following query:

query FetchLukeAndLeiaAliased {
  luke: human(id: "1000") {
    name
  }
  leia: human(id: "1003") {
    name
  }
}

We aliased the result of the first human field to the key luke, and the second to leia. So the result will be:

{
  "luke": {
    "name": "Luke Skywalker"
  },
  "leia": {
    "name": "Leia Organa"
  }
}

Now imagine we wanted to ask for Luke and Leia's home planets. We could do so with this query:

query DuplicateFields {
  luke: human(id: "1000") {
    name
    homePlanet
  }
  leia: human(id: "1003") {
    name
    homePlanet
  }
}

but we can already see that this could get unwieldy, since we have to add new fields to both parts of the query. Instead, we can extract out the common fields into a fragment, and include the fragment in the query, like this:

query UseFragment {
  luke: human(id: "1000") {
    ...HumanFragment
  }
  leia: human(id: "1003") {
    ...HumanFragment
  }
}

fragment HumanFragment on Human {
  name
  homePlanet
}

Both of those queries give this result:

{
  "luke": {
    "name": "Luke Skywalker",
    "homePlanet": "Tatooine"
  },
  "leia": {
    "name": "Leia Organa",
    "homePlanet": "Alderaan"
  }
}

The UseFragment and DuplicateFields queries will both get the same result, but UseFragment is less verbose; if we wanted to add more fields, we could add it to the common fragment rather than copying it into multiple places.

We defined the type system above, so we know the type of each object in the output; the query can ask for that type using the special field __typename, defined on every object.

query CheckTypeOfR2 {
  hero {
    __typename
    name
  }
}

Since R2-D2 is a droid, this will return

{
  "hero": {
    "__typename": "Droid",
    "name": "R2-D2"
  }
}

This was particularly useful because hero was defined to return a Character, which is an interface; we might want to know what concrete type was actually returned. If we instead asked for the hero of Episode V:

query CheckTypeOfLuke {
  hero(episode: EMPIRE) {
    __typename
    name
  }
}

We would find that it was Luke, who is a Human:

{
  "hero": {
    "__typename": "Human",
    "name": "Luke Skywalker"
  }
}

As with the type system, this example just scratched the surface of the query language. The specification goes into more detail about this topic in the "Language" section, and the language directory in GraphQL.js contains code implementing a specification-compliant GraphQL query language parser and lexer.

Validation

By using the type system, it can be predetermined whether a GraphQL query is valid or not. This allows servers and clients to effectively inform developers when an invalid query has been created, without having to rely on runtime checks.

For our Star Wars example, the file starWarsValidationTests.js contains a number of demonstrations of invalid operations, and is a test file that can be run to exercise the reference implementation's validator.

To start, let's take a complex valid query. This is the NestedQuery example from the above section, but with the duplicated fields factored out into a fragment:

query NestedQueryWithFragment {
  hero {
    ...NameAndAppearances
    friends {
      ...NameAndAppearances
      friends {
        ...NameAndAppearances
      }
    }
  }
}

fragment NameAndAppearances on Character {
  name
  appearsIn
}

And this query is valid. Let's take a look at some invalid queries!

When we query for fields, we have to query for a field that exists on the given type. So as hero returns a Character, we have to query for a field on Character. That type does not have a favoriteSpaceship field, so this query:

# INVALID: favoriteSpaceship does not exist on Character
query HeroSpaceshipQuery {
  hero {
    favoriteSpaceship
  }
}

is invalid.

Whenever we query for a field and it returns something other than a scalar or an enum, we need to specify what data we want to get back from the field. Hero returns a Character, and we've been requesting fields like name and appearsIn on it; if we omit that, the query will not be valid:

# INVALID: hero is not a scalar, so fields are needed
query HeroNoFieldsQuery {
  hero
}

Similarly, if a field is a scalar, it doesn't make sense to query for additional fields on it, and doing so will make the query invalid:

# INVALID: name is a scalar, so fields are not permitted
query HeroFieldsOnScalarQuery {
  hero {
    name {
      firstCharacterOfName
    }
  }
}

Earlier, it was noted that a query can only query for fields on the type in question; when we query for hero which returns a Character, we can only query for fields that exist on Character. What happens if we want to query for R2-D2s primary function, though?

# INVALID: primaryFunction does not exist on Character
query DroidFieldOnCharacter {
  hero {
    name
    primaryFunction
  }
}

That query is invalid, because primaryFunction is not a field on Character. We want some way of indicating that we wish to fetch primaryFunction if the Character is a Droid, and to ignore that field otherwise. We can use the fragments we introduced earlier to do this. By setting up a fragment defined on Droid and including it, we ensure that we only query for primaryFunction where it is defined.

query DroidFieldInFragment {
  hero {
    name
    ...DroidFields
  }
}

fragment DroidFields on Droid {
  primaryFunction
}

This query is valid, but it's a bit verbose; named fragments were valuable above when we used them multiple times, but we're only using this one once. Instead of using a named fragment, we can use an inline fragment; this still allows us to indicate the type we are querying on, but without naming a separate fragment:

query DroidFieldInInlineFragment {
  hero {
    name
    ... on Droid {
      primaryFunction
    }
  }
}

This has just scratched the surface of the validation system; there are a number of validation rules in place to ensure that a GraphQL query is semantically meaningful. The specification goes into more detail about this topic in the "Validation" section, and the validation directory in GraphQL.js contains code implementing a specification-compliant GraphQL validator.

Introspection

It's often useful to ask a GraphQL schema for information about what queries it supports. GraphQL allows us to do so using the introspection system!

For our Star Wars example, the file starWarsIntrospectionTests.js contains a number of queries demonstrating the introspection system, and is a test file that can be run to exercise the reference implementation's introspection system.

We designed the type system, so we know what types are available, but if we didn't, we can ask GraphQL, by querying the __schema field, always available on the root type of a Query. Let's do so now, and ask what types are available.

query IntrospectionTypeQuery {
  __schema {
    types {
      name
    }
  }
}

and we get back:

{
  "__schema": {
    "types": [
      {
        "name": "Query"
      },
      {
        "name": "Character"
      },
      {
        "name": "Human"
      },
      {
        "name": "String"
      },
      {
        "name": "Episode"
      },
      {
        "name": "Droid"
      },
      {
        "name": "__Schema"
      },
      {
        "name": "__Type"
      },
      {
        "name": "__TypeKind"
      },
      {
        "name": "Boolean"
      },
      {
        "name": "__Field"
      },
      {
        "name": "__InputValue"
      },
      {
        "name": "__EnumValue"
      },
      {
        "name": "__Directive"
      }
    ]
  }
}

Wow, that's a lot of types! What are they? Let's group them:

  • Query, Character, Human, Episode, Droid - These are the ones that we defined in our type system.
  • String, Boolean - These are built-in scalars that the type system provided.
  • __Schema, __Type, __TypeKind, __Field, __InputValue, __EnumValue, __Directive - These all are preceded with a double underscore, indicating that they are part of the introspection system.

Now, let's try and figure out a good place to start exploring what queries are available. When we designed our type system, we specified what type all queries would start at; let's ask the introspection system about that!

query IntrospectionQueryTypeQuery {
  __schema {
    queryType {
      name
    }
  }
}

and we get back:

{
  "__schema": {
    "queryType": {
      "name": "Query"
    }
  }
}

And that matches what we said in the type system section, that the Query type is where we will start! Note that the naming here was just by convention; we could have named our Query type anything else, and it still would have been returned here if we had specified it as the starting type for queries. Naming it Query, though, is a useful convention.

It is often useful to examine one specific type. Let's take a look at the Droid type:

query IntrospectionDroidTypeQuery {
  __type(name: "Droid") {
    name
  }
}

and we get back:

{
  "__type": {
    "name": "Droid"
  }
}

What if we want to know more about Droid, though? For example, is it an interface or an object?

query IntrospectionDroidKindQuery {
  __type(name: "Droid") {
    name
    kind
  }
}

and we get back:

{
  "__type": {
    "name": "Droid",
    "kind": "OBJECT"
  }
}

kind returns a __TypeKind enum, one of whose values is OBJECT. If we asked about Character instead:

query IntrospectionCharacterKindQuery {
  __type(name: "Character") {
    name
    kind
  }
}

and we get back:

{
  "__type": {
    "name": "Character",
    "kind": "INTERFACE"
  }
}

We'd find that it is an interface.

It's useful for an object to know what fields are available, so let's ask the introspection system about Droid:

query IntrospectionDroidFieldsQuery {
  __type(name: "Droid") {
    name
    fields {
      name
      type {
        name
        kind
      }
    }
  }
}

and we get back:

{
  "__type": {
    "name": "Droid",
    "fields": [
      {
        "name": "id",
        "type": {
          "name": null,
          "kind": "NON_NULL"
        }
      },
      {
        "name": "name",
        "type": {
          "name": "String",
          "kind": "SCALAR"
        }
      },
      {
        "name": "friends",
        "type": {
          "name": null,
          "kind": "LIST"
        }
      },
      {
        "name": "appearsIn",
        "type": {
          "name": null,
          "kind": "LIST"
        }
      },
      {
        "name": "primaryFunction",
        "type": {
          "name": "String",
          "kind": "SCALAR"
        }
      }
    ]
  }
}

Those are our fields that we defined on Droid!

id looks a bit weird there, it has no name for the type. That's because it's a "wrapper" type of kind NON_NULL. If we queried for ofType on that field's type, we would find the String type there, telling us that this is a non-null String.

Similarly, both friends and appearsIn have no name, since they are the LIST wrapper type. We can query for ofType on those types, which will tell us what these are lists of.

query IntrospectionDroidWrappedFieldsQuery {
  __type(name: "Droid") {
    name
    fields {
      name
      type {
        name
        kind
        ofType {
          name
          kind
        }
      }
    }
  }
}

and we get back:

{
  "__type": {
    "name": "Droid",
    "fields": [
      {
        "name": "id",
        "type": {
          "name": null,
          "kind": "NON_NULL",
          "ofType": {
            "name": "String",
            "kind": "SCALAR"
          }
        }
      },
      {
        "name": "name",
        "type": {
          "name": "String",
          "kind": "SCALAR",
          "ofType": null
        }
      },
      {
        "name": "friends",
        "type": {
          "name": null,
          "kind": "LIST",
          "ofType": {
            "name": "Character",
            "kind": "INTERFACE"
          }
        }
      },
      {
        "name": "appearsIn",
        "type": {
          "name": null,
          "kind": "LIST",
          "ofType": {
            "name": "Episode",
            "kind": "ENUM"
          }
        }
      },
      {
        "name": "primaryFunction",
        "type": {
          "name": "String",
          "kind": "SCALAR",
          "ofType": null
        }
      }
    ]
  }
}

Let's end with a feature of the introspection system particularly useful for tooling; let's ask the system for documentation!

query IntrospectionDroidDescriptionQuery {
  __type(name: "Droid") {
    name
    description
  }
}

yields

{
  "__type": {
    "name": "Droid",
    "description": "A mechanical creature in the Star Wars universe."
  }
}

So we can access the documentation about the type system using introspection, and create documentation browsers, or rich IDE experiences.

This has just scratched the surface of the introspection system; we can query for enum values, what interfaces a type implements, and more. We can even introspect on the introspection system itself. The specification goes into more detail about this topic in the "Introspection" section, and the introspection file in GraphQL.js contains code implementing a specification-compliant GraphQL query introspection system.

Additional Content

This README walked through the GraphQL.js reference implementation's type system, query execution, validation, and introspection systems. There's more in both GraphQL.js and specification, including a description and implementation for executing queries, how to format a response, explaining how a type system maps to an underlying implementation, and how to format a GraphQL response, as well as the grammar for GraphQL.

Contributing to this repo

This repository is managed by EasyCLA. Project participants must sign the free (GraphQL Specification Membership agreement before making a contribution. You only need to do this one time, and it can be signed by individual contributors or their employers.

To initiate the signature process please open a PR against this repo. The EasyCLA bot will block the merge if we still need a membership agreement from you.

You can find detailed information here. If you have issues, please email [email protected].

If your company benefits from GraphQL and you would like to provide essential financial support for the systems and people that power our community, please also consider membership in the GraphQL Foundation.

graphql-spec's People

Contributors

alexandrebodin avatar andimarek avatar benjie avatar binaryseed avatar bjornbytes avatar brianwarner avatar ccbrown avatar clentfort avatar devknoll avatar dschafer avatar dugenkui03 avatar dylanahsmith avatar eapache avatar enaqx avatar gabrielf avatar glasser avatar ivangoncharov avatar leebyron avatar matprec avatar mjmahone avatar olegilyenko avatar rivantsov avatar robrichard avatar robzhu avatar simenbrekken avatar spawnia avatar sungam3r avatar tristanz avatar wincent avatar yaacovcr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphql-spec's Issues

Union type validation talks about inputs, but unions are never valid inputs

The last paragraph of this section: http://facebook.github.io/graphql/#sec-Union-type-validation

When expected as an input type, array input values are accepted only when each item in the input array can be accepted by the item type. If the input value is not an array but can be accepted by the item type, it is coerced by creating an array with the input value as the sole item. Other input values must raise a query error indicating an incorrect type.

Is this paragraph misplaced?

Custom Sorting

Didn't see anything in the spec about this. I assume it's coming?

Support of `Long` (64-bit integer) scalar

In my experience long is pretty common primitive data type. It also used to represent pretty common things like timestamps or cent amounts. As a result of it, most of modern programming languages naively support 64-bit integer values in one form or another. Is there particular reason why long scalar type was not included in the spec?

Inline introspection

Spec defines __typename as a way to get 'inline' introspection for any field. I was under impression that in previous versions of the GraphQL one could get the whole type definition inline with __type__ (which, I guess, would be __type nowadays). I think it was very handy, is there any particular reason why it was removed?

Pagination?

Hey facebook,

First of all, thanks for open sourcing this, I'm so excited I forgot how to even.

With that out of the way, I have a question, how is pagination implemented in the facebook schema? There is no mention of pagination in the spec so I assume is implemented adhoc using the primitives provided by the spec. A hint on how to model this common use case would be really appreciated.

What I have in mind is some is some Page type. Which yields the following question: is it possible to define generic types the same way that List is defined? Asking because ideally such Page type would be Page<T>

Also, I'd also appreciate some advice on how to model querying for the count of a list property or a paginated property. In 2.10.1 Types of fragments there is the following example:

query FragmentTyping
{
  profiles(handles: ["zuck", "cocacola"]) {
    handle
    ...userFragment
    ...pageFragment
  }
}

fragment userFragment on User {
  friends { count }
}

fragment pageFragment on Page {
  likers { count }
}

There is no schema attached for that example, but as far as I understand, those fragments are trying to get the total number of friends of a user and the total number of likes of a Page. It is hard to say without the schema, but if we assume that a User has a List of Users, the fist fragment is really querying for the property count in each individual User of said list, and not the property count in the list itself (which is the intention, arguably). Any light in this topic would be very much appreciated.

Thanks for open sourcing this and for your time.

Drop colon (:) for type definitions and $ from query variable

This is a totally stylistic, bikeshedding comment... but maybe worth considering if I'm not missing something obvious.

It seems like both the informal schema format and query variables could be simplified by eliminating the colon from type definitions and dollar sign from variables. Right now the colon is used in so many different contexts (variables, types, interfaces, aliases). The similarity between type definitions and passing arguments in particular is mildly confusing.

Why not change :

type Person : NamedEntity {
  name: String
  gravatar(height: Int, width: Int): Gravatar
}

to

type Person : NamedEntity {
  name String
  gravatar(height Int, width Int) Gravatar
}

The same with queries. Why not change:

query myQuery($someTest: Boolean, $size: Boolean) {
  gravatar(size: $size)
  experimentalField @include(if: $someTest)
}

to

query myQuery($someTest Boolean, $size Boolean) {
  gravatar(size: $size)
  experimentalField @include(if: $someTest)
}

so that outer type definitions and inner arguments don't look so similar.

Finally, is the dollar sign really required? Why not just:

query myQuery(someTest Boolean, size Boolean) {
  gravatar(size: size)
  experimentalField @include(if: someTest)
}

Input Coercion for Non-Null states that field(arg: null) is illegal, but it's not

From http://facebook.github.io/graphql/#sec-Non-Null :

NOTE that null is not a valid keyword in GraphQL, so a query cannot look like:
{
field(arg: null)
}
to indicate that the argument is null.

However, this example should actually parse, according to the given grammar. It is a valid Arguments with one Argument whose Value is an EnumValue with the Name "null". This is a consequence of the keywordless approach to grammar definition. I'm not sure how to succinctly explain that this example may be legal, but not because null is a pre-defined keyword that necessarily means the same thing as "unset variable", and that there isn't a way to get it to typecheck for all calls generally given the rest of the system.

Idea: Cost function on fields, to allow ballpark analysis of query complexity

const FooType = new GraphQLObjectType({
  name: 'Foo',
  fields: () => ({
    id: globalIdField('Food', obj => obj.id),
    bar: {
      type: new GraphQLList(BarType),
      resolve: obj => getBarsForFoo(obj.id),
      resolveCost: n => n * 5,
    },

In this example, n is the number of times this field is requested across all Foos within the query. This may not be possible in pure GraphQL, since the number of results requested is dependent on how the schema is configured, but with a standardised API for connections like in Relay, it might be possible. The 5 is arbitrary, cheap fields would probably have a 0 or 1.

The end result would be the ability to reject queries over a certain cost, but also allow IDEs to warn developers that a particular query is risky.

Custom Scalar types are not validated on query variables

I have a mutation which has a custom scalar type in the input field,

// Scalar Type
var PLString = new GraphQLScalarType({
    name: "PLString",
    serialize: value => {
      return value
    },
    parseValue: value => {
      return value
    },
    parseLiteral: ast => {
      throw new Error("This string is not valid")
      return ast.value
    }
  })
}

This is my mutation,

mutation: new GraphQLObjectType({
    name: 'Mutation',
    fields: {
      login: {
        type: GraphQLString,
        args: {
          text: { type: PLString }
        },
        resolve: () => "Immutant"
     }
    }
});

When I make a graphql mutation like this,

mutation PL {
  login(text: "this is text")
}

I get the error

{
  "errors": ["This string is not valid"]
}

But when I do this with query variables like this,

mutation PL($input: GraphQLString) {
  login(text: $input)
}

//variables
{
  "input": "this is text"
}

It succeeds

{
  "data": {
     "login": "Immutant" 
   }
}

Is this the expected behavior of GraphQL or is this a problem with the js implementation and maybe I should have posted there .. but its its too late now i guess..

Algebraic interface types

As originally discussed in graphql/graphql-js#45, it would be useful to be able to declare a field type to be a combination of interfaces.

As an example use-case, let's say I have an interface

interface Image {
  src: String
}

which represents an image I can display. Some images are stand-alone and I can link to them as a page, but other things share that capability (videos for instance). So I have another interface

interface Linkable {
  url: String
}

Now let's say that all users have profile pictures which are linkable. I'd like to be able to declare something like this

type User {
   profilePicture: Image + Linkable
}

When resolving such type, the only requirement is for the interfaces not to contain the same attributes. From there it should be possible to find the defining interface for each attribute and then the implementing type based on interface type resolution.

Case Sensitivity

The spec doesn't mention case sensitivity anywhere that I could find. The JavaScript reference implementation implies case sensitivity, but I figure that should probably be mentioned somewhere in the spec.

License

Hello, everybody there! At first, I want to say thanks to you guys, who invent this small, but powerful query language.

But the main article of this issue, that the license that apply to this specification is not fit this kind of things, I think, that BSD-3-Clause license better to apply to the source code, but the specification should be licensed with Creative Common License.

Creative Common License Attribution 4.0 Internation, I think, is better.

Thanks!

Polymorphic input types

We have an interface Customization and around 20 types implementing this interface. The number of subtypes of Customization will grow over time, we are even considering adding subtypes dinamically.

Each concrete type has it own set of attributes.

On the query side this is easy to represent. The problem is at the mutation side. We want to have a mutation method to add a customization to another object

addCustomizationToNode(nodeId: ID, customizationInput: CustomizationInput)

but this is not currently possible to express since Input Objects cannot have interfaces, we would rather not have one mutation field per subtype, specially since those can change dynamically, potentially.

Do you have any suggestions? Would make sense to have InputObjects take interfaces?

Thank you!

Allow to ignore optional query variables (with fragments)

For an example, have a look at following query:

query postAndComments($postCount: Int!) {
  getRecentPosts(count: $postCount) {
    title,
    content,
    ...comments
  }
}

fragment comments on Post {
  comments(limit: $commentLimit) {
    content,
    timestamp
  }
}

Now this throws an error:

{
  "errors": [
    {
      "message": "Variable \"$commentLimit\" is not defined by operation \"postAndComments\"."
    }
  ]
}

If we allow to this, I think it'd be great. Here's the use case.

With this, I can use comments fragments in queries where commentLimit query variable does not exists as well.

What you guys think about this?

Documentation for mutation

Thank you for this great work! The idea is awesome and README.md itself was interesting to me.

Is there any plan to write additional documentation for mutation on README.md?

Consider using data structures rather than a grammar to define the language

This just feels like SQL all over again where you have to do string concatenation rather than building real data structures to talk to a server. Using a data format (or formats) would be far friendlier and less error prone to implement in the long run. For example I was working with a .NET implementation recently that didn't quite have the grammar implemented correctly and allowed for strings to be provided to the server that didn't have correctly closing curly braces. Data structure formats basically prevent this kind of thing and many other easy to create problems with custom grammars.

If the syntax could be defined in terms of data structures rather than a custom grammar it would make implementations on both client and server simpler and more flexible. Versioning the spec would likely also be simpler. Testing is definitely simpler on both ends as well since you can use the native data structures of your environment with a little conversion to json, or EDN, or whatever you want for the wire format(s).

typo error

in section4.md ,

Take an example query for a trivial app. In this case there is a User type with
three fields: id, user, and birthday.

user should be name

Take an example query for a trivial app. In this case there is a User type with
three fields: id, name, and birthday.

sentence is not complete

in section 5 ### Field Selections on Objects, Interfaces, and Unions Types,
" Because fields are not declared on unions, direct field selection on union-typed selection set. This is true even if concrete implementors of the union define the fieldName."
what does "direct field selection on union-typed selection set." mean?

Fragment directive overriding is underspecified

The Fragment Directives section says that "At runtime, the directives provided on a fragment spread override those described on the definition.", but "override" here is not sufficiently precise. Consider the following example:

query example { ...F @bar }
fragment F on Query @foo { some_field }

Is this equivalent to using both @foo and @bar or just @bar? (Presumably, "neither" and "just @foo" wouldn't be consistent with "override.") Does it matter if @bar and @foo have any kind of interaction in their effects?

Inconsistent key between query and response on __schema

In IntrospectionQueryTypeQuery section, the query has a queryType key in __schema:

query IntrospectionQueryTypeQuery {
  __schema {
    queryType {
      name
    }
  }
}

But response with query key in __schema:

{
  "__schema": {
    "query": {
      "name": "Query"
    }
  }
}

Is there any reasons for Inconsistent keys or just a typo here?

Input Object fields

Should input objects return a keyed set when introspecting for inputFields the way object do for fields?

Currently, the spec on introspection says that input objects have an inputFields query that returns a list. Object, on the other hand, have a fields query that returns a keyed set. Both input objects and objects take maps, even if the keys are just 0, 1, 2, 3. Is there a reason that introspection does not return a keyed set of fields for input objects? In a similar vein, why not just have the introspection query be 'fields' for both?

Directive precedence should be explicit, not implicit

The draft states that if both the @Skip and @include directives are present, the @Skip directive should take precede. This strikes me as confusing as it opens the door to others creating directives with implicit precedence.

Wouldn't it be simpler and less confusing to say precedence is left to write in the order it was written?

If fragments are involved, then we could linearize the dependencies by saying depth first. Then there are no ambiguities.

Subscriptions

We need a way to listen to changes performed by someone else than the local client in order to build true real-time apps based on GraphQL. Similar to how Firebase and Meteor work.

I know this is being discussed on Slack but a proper ticket is missing.

Better error reporting when exception occurs in a fields' resolve function.

For my purpose I quickly hacked in resolveField (execute.js):

console.log("... resolveFn error:\n" + error + ": " + error.stack);

Such that I can see the error stack if there's an exception in a resolve() function. Without this the error is "silently" eaten, and only reported in the GQL result as "basic error desc" line/col in the "errors" which isn't very useful most of the time.

Is there a hook, or should a hook be added to report these type of errors in a more detailed manner?

Using resolved fields as input argument variables

I'm fairly certain this is not currently possible, and I'm not even sure it is desirable. That said, is there some way to specify an argument variable based on previously fetched data?

For example, lets assume we have a contentItem type. That contentItem has two fields, isLive and liveData. liveData includes a bunch of information about who set the contentItem to be live and when. We want that information, but only if the contentItem is actually live.

query content {
  contentItem {
    isLive
    liveData @include(if: $isLive) {
      liveTime
      user {
        username
      }
    }
  }
}

If it is not possible, is this a feature worth considering? I see three big downsides. First, it adds some complexity to the resolution of fields. Second, we lose some parallel execution in the query, though not all. Third, there are many use cases for such a variable that are really bad design.

I am going to admit that the original reason I wrote this issue was one of those mildly bad design decisions. Fortunately, I realized it was really bad design as I start writing it down. However, the isLive/liveData example stuck with me as useful. Granted, right now it would just return undefined or null, which is probably just as good. Still, something to think about.

Readable querying of arrays

If the idea is to write a query that reads as the outcome, wouldn't we want to fetch arrays differently? Right now we fetch data like this:

query HeroNameAndFriendsQuery {
  hero {
    id
    name
    friends {
      id
      name
    }
  }
}

This doesn't give me a visual indication friends will output an array. Why wouldn't we want to write it like:

query HeroNameAndFriendsQuery {
  hero {
    id
    name
    friends [
      id
      name
    ]
  }
}

Validations that cannot be ran on the client side and the errors object

Let's say you have a uniqueness constraint on a field in a mutation. For example the email field must not match any existing email in the database.

In graphql/graphql-js#179 it's been suggested that we shouldn't use the server to validate our forms. But in the case of our uniqueness constraint the server is the only place with enough information to determine if our form is valid.

The format of the errors response appears to be aimed at debugging. Specifically a line number is given as the only context for the error. Presumably this is so that a programmer can then use that line number to find the issue in their query/mutation. So to me the current errors array looks more analogous to a stack trace then an error object like we'd traditionally expect in a RESTful API (eg. {"errors": {"email": ["this email has been taken"]}}).

The advantage of the error object is that we can easily match the keys in the error to the names of the fields in our form to add an error message for our users next to the offending field.

I propose that changing the errors array to an errors object would give developers access to field names and error messages in a format that is easy to map on to their forms and display to users. Eg:

{
  "errors": {
    "email": {
      "messages": ["The email address [email protected] has already been taken"],
      "locations": []
    }
  }
}

Relevant Spec Section: https://facebook.github.io/graphql/#sec-Errors

Querying content with different priorities

Hi,

With GraphQL (and relay) there is the potential of fetching the data for an entire screen in one query. This is great because it is simple but sometimes (if not most of the times) you want to grab the main content first (article content) and then grab the surroundings (related content, comments, stats of the article, etc) to improve the user experience.

Of course there is the option of making two separate GraphQL queries but, since the idea (especially with relay) seems to be having everything declarative, I'd rather avoid this option.

I'm wondering if there is a way of doing this. If not, it may be interesting to consider this use case, maybe in conjunction with subscriptions (give me the article content now and send me the rest once it is computed?)

Thanks for your time.

Add tests for "context sensitivity" around on/fragment/query/mutation non-keywords

Name is context-sensitive in that, for example, the string "on" is a Name unless it appears in a place in the grammar that requires on specifically (e.g., right after an ellipsis, as in InlineFragment, or two tokens after fragment, as in FragmentDefinition). Naive application of tools like flex and bison seems likely to produce a system that doesn't allow apparent "keywords" like on/fragment/query/mutation to be used as Names (e.g., as the names of fields). We should add test cases in src/language/__tests__/parser.js that demonstrate that these are legal Names.

Map type

Should there be a map type?

I have a structure that looks like this:

  Item {
     title {
        de_DE,
        fr,
        pa,
        .....
     }
  }

The point here is that the number of language strings might be arbitrary. I find this hard to model using GraphQLObject, because:

  1. The number of locales is undefined. While the resolver could handle this dynamically, I think it's a problem in Relay that the schema cannot reflect these dynamic fields.
  2. I would like to query all the existing locales, which isn't allowed, it seems ("must have a sub-selection").

If I make my GraphQL server return a JSON object for "title", the Relay client doesn't complain (although maybe shouldComponentUpdate breaks), but I think I'm skirting by here. At the very least, I think I couldn't generate a schema that confirms to the spec.

Recursively nested objects

Suppose we have a forum where users can reply to comments recursively:

type RootQuery {
  message(id: String): Message
  messages: [Message]
}

type Message {
  id: String!
  content: String
  comments: [Message]
}

How could the client query for the nested comments?

This only goes three levels deep:

{
  messages {
    comments {
      id
      content
      comments {
        id
        content
        comments {
          id
          content       
        }
      }
    }   
  }
}

Would a consecutive query starting at the last comment be the right solution?

{
  message as comment($commentId) {
    comments {
      id
      content
      comments {
        ...
      }
    }
  }
}

Original SO post

allow "$" char in names

scala.js emits constructor names with$ chars , react-relay takes constructor name as mutation query name and resulting in failed transactions :(. i reported this in scala.js channel

@sjrd is it possible to remove $ in generated constructor/class names for scalajsdefined classes ? graphql supported names set /[_A-Za-z][_0-9A-Za-z]*/, with current constructor names graphql api requests are failing in fastOptJS mode

response from scala.js author :

@chandu0101 No it is not possible. graphql most be fixed to support all valid Javascript identifiers.

so is it possible to accept names that comply with javascript identifiers ?

Returning with lists

One thing is not clear - how should it be handled if the result is an array (like users, where age > 40) ? Should all query return with a GraphQL list type, or how do you make a difference?

What is the response format of a multi-operations query?

If we have a simple query, with only a SelectionSet:

{
    hero {
        name
    }
}

which is the same as

query HeroNameQuery {
    hero {
        name
    }
}

The tests in graphql.js show this expected answer:

{
    data: {
        hero: {
            name: 'R2-D2'
        }
    }
}

I know we can have many root in one query:

query FetchLukeAndLeiaAliased {
    luke: human(id: "1000") {
        name
    }
    leia: human(id: "1003") {
        name
    }
}

Resulting in this answer:

{
    data: {
        luke: {
            name: 'Luke Skywalker'
        },
        leia: {
            name: 'Leia Organa'
        }
    }
}

But, and it's my main concern, what if we have more that one operation in one query, which seems to be valid in the specifications (examples in http://facebook.github.io/graphql/#sec-All-Variable-Uses-Defined and http://facebook.github.io/graphql/#sec-All-Variables-Used).

For example what is the expected answer for this graphql query (dumb query just for the example):

query LukeAndLeiaNames {
    luke: human(id: "1000") {
        name
    }
    leia: human(id: "1003") {
        name
    }
}

query LukeAndLeiaHomePlanet {
    luke: human(id: "1000") {
        homePlanet
    }
    leia: human(id: "1003") {
        homePlanet
    }
}

I currently have no idea, except that there should be one more level between data and a query result using the name of the operation (which must be unique in the document, as said in the specification).

Or each query have its own "object" response, with data, errors... But in this case how are they "encapsulated"? In a main object with the operation names used as keys ? I could not find anything about this in the specification or the graphql.js tests.

Thanks for your answer, I'm currently writing a python graphql server and it will help me to know that ;)

Possibility of collaboration with LoopBack framework?

I'm a developer of LoopBack (http://www.loopback.io), an open source Node.js framework for building APIs with rich data integrations. I'm opening this issue to explore the possibility of collaboration as both projects try to solve similar problems.

LoopBack already provides a lot of capabilities as you outline in the GraphQL spec, including:

  1. A JSON based definition language for data models (types and validations) - http://docs.strongloop.com/display/LB/Model+definition+JSON+file
  2. Relations that connect models (BelongsTo, HasMany, HasOne, HasMany-Through, EmbedsMany, ReferencesMany, Polymorphic) to form data graphs - http://docs.strongloop.com/display/LB/Creating+model+relations
  3. A JSON based query language - http://docs.strongloop.com/display/LB/Querying+data
  4. A large list of connectors that implement the CRUD operations based on the specs - http://docs.strongloop.com/display/LB/Connecting+models+to+data+sources

What do you think?

PS: I'm not sure if this is a good way to reach out. Please let me know if we should take it offline. Thanks in advance.

Support adding examples inline for use in documentation

I was thinking through building a documentation explorer and something that'd be very useful is if you could define example queries alongside your type or field definition. These could then be auto expanded into embedded graphiql instances.

Whitespace treatment in grammar

Please correct me if I missed it in the spec, but I haven't found a formal definition of the whitespace treatment combined with some of the tokens. For example in the detective definition. It's not 100% clear whether whitespace is allowed between @ and Name. The same is for the variable: can I put a whitespace between $ and the Name like this?

$ myVariable

Intuition tells me that in most cases whitespaces are allowed, so query like this:

query    , FetchLukeAndLeiaAliased{
  luke:human(id   :  2.1e-7) {
    name,
  }
  leia       ,  : human   ,,, ( , id ,, : ,, "10103") {
    name
  }
}

is a valid query and should be parsed without any errors. Is my assumption correct?

Make non-null the default

I can understand why making types nullable by default might be a reasonable decision for growing systems adding new features but I think there are reasons why this might not be ideal:

  1. This conflates the idea of nullability with providing reasonable default values. By allowing new features to be nullable by default, we push more responsibility to the application logic for determining what might be the right behavior.

  2. Because making types nullable is so easy in practice, it promotes not considering if data should even be nullable or not. This could escalate the system's entropy more quickly making it hard to reason about the system's intended behaviour.

I'd love to hear other thoughts or ideas on this!

Cannot use interface implementation as a valid type

Let's say I have a schema for some translated content with a common interface for entries:

interface Entry {
  id: ID
  slug: String
  translations: [Entry]
}

type Page implements Entry {
  id: ID
  slug: String
  translations: [Page] # Page implements Entry, this should be ok
}

In graphql-js this errors, saying the translations on Page should be of type [Entry]. Since Page implements Entry and translations of a Page will only ever be Pages, this seems ok to me.

Tried the same with union types with the same result. It's not a disaster, I can widen it to the interface type and use a type fragment in queries, but it seems a little unwieldy.

Am I missing a reason why it's not valid to narrow down an interface type when implementing an interface which specifies a field of an interface type? (uh, sorry, can't make that sentence any simpler)

Compatibility Acceptance Tests

After creating scala GraphQL implementation I must admit, that the test quality and coverage of nodejs reference implemention is very good. In fact it helped me a lot during the development (as well as the reference implementation itself, of course). After re-implementing most of the tests in scala I now pretty confident, that most of the functionality is tested.

After seeing all these tests it become apparent to me, that there are a lot of edge cases and things that GraphQL library can get wrong, especially in terms of semantics, validation, execution, error handling, etc.. People are already created implementations in many different languages. I feel that it is important to create a TCK (Technology Compatibility Kit) for GraphQL specification in order to ensure success of GraphQL itself, higher adoption and growth of the ecosystem. Having implemented other specifications in the past, I must admit that a TCK makes specification implementation much easier and faster process. It also helps to adopt an implementation as specification evolves.

With TCK I mean a set of acceptance tests, that are distributed in some form (as a library, for instance) and can be used by library authors to verify, that their implementation confirms to the spec. Of course, TCK can't cover all of the cases, but at least it gives a good baseline and as ecosystem grows, it ensures that all parts of it remain compatible with each other or at least minimizes risk of incompatibility.

At the react-europe conference I had a short conversation with @schrockn about this topic. He said, that there are plans for something like this, so I wanted to follow-up here and ask for more information. Do you still have plans to create something like a TCK for GraphQL spec? If yes, do you already have an idea which form it will take? I guess implementing something like this can be a challenging task, considering that it suppose to test implementations written in different languages. As far as I saw, tests in the reference implementation are pretty generic - many of them take some query, execute it and then verify resulting JS object. At the moment they all implemented in terms of the nodejs implementation, but maybe they can be reused or extracted in the TCK somehow?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.