Coder Social home page Coder Social logo

libgraphqlparser'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.

libgraphqlparser's People

Contributors

aarvay avatar andheiberg avatar brianwarner avatar dosten avatar dylanahsmith avatar eapache avatar erikwittern avatar gjtorikian avatar kenshaw avatar krytarowski avatar leebyron avatar leozz37 avatar mmatsa avatar rmosolgo avatar schloerke avatar steve384 avatar swolchok 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

libgraphqlparser's Issues

Missing support for extending schemas

GraphQL allows to extend schemas, i.e.:

[...] to represent a schema which has been extended from an original schema. For example, this might be used by a GraphQL service which adds additional operation types, or additional directives to an existing schema.

libgraphqlparser currently does not support the parsing schema definitions including schema extensions.

CMake 3.1.0 required, only used for setting C++11 standard

CMake 3.1.0 is required to configure the buildsystem.
From what I can tell 3.1.0 is only needed for setting the C++ standard to C++11.

Unfortunately, even a recent Ubuntu 15.04 only comes with CMake 3.0.2.

It would be great to make it work with older CMake versions by putting some code in to add the appropriate flag manually. Yes, I know this needs some lines of code, but otherwise you force the user to upgrade CMake only for setting the C++ standard (or, like me, comment the line out and set -std=c++11 manually).

License

I tried to publish libgraphqlparser bindings but they were rejected because you LICENSE says BSD but the reposity contains several GPL files...

Location Lines

I'm looking at the location values for https://github.com/graphql/libgraphqlparser/blob/master/test/schema-kitchen-sink.json and https://github.com/graphql/libgraphqlparser/blob/master/test/kitchen-sink.json.

Both the kitchen sink (request) and schema kitchen sink GraphQL test inputs have comments and white space for the first 7-8 lines. But the locations in the JSON output say the documents start at line 2 and finish before the definitions are done.

Does libgraphqlparser remove comment only lines? The JSON locations do not match the original text definition locations. (Trying to make my print statements match the error information)

(Thank you for the line number addition!)

  • Barret

Building / installing without sudo

I've been spending time improving my Travis build times, and my final remaining task to switch to their container infrastructure is to get rid of the sudo make install required by libgraphqlparser.

I've spelunked the Makefile a little but I don't see an obvious way to encourage the installer to build to a directory I have access to instead of /usr/local/include/graphqlparser. Any suggestions?

Package-config in Homebrew

I'm looking for libgraphqlparser.pc.in in the Cellar library from a homebrew (brew install libgraphqlparser) installation and can't find it. Would be useful to have this available. How can we make this available?

Missing support for extending interfaces

In addition to extending types, GraphQL also allows to extend interfaces. This seems currently not supported by libgraphqlparser, though, which fails with an exception of the type:

Parser failed with error: <line.column-length>: syntax error, unexpected interface, expecting type

Out of source build not possible, CMakeLists assumes building from root

The custom commands in the CmakeLists are hardcoded to expect building from the root directory.

Steps to reproduce:

> mkdir build && cd build
> cmake .. -DCMAKE_BUILD_TYPE=Release && cmake --build .

Filtered warnings:

python: can't open file './ast/ast.py': [Errno 2] No such file or directory

It would be great to allow or even prefer out of source builds.

better test instructions

The readme says:
To run tests, please download googletest from https://github.com/google/googletest/archive/release-1.8.0.zip and unzip it in the test subdirectory.

And that's it. I downloaded googletest in the test directory, ran cmake . and then tried with several make targets, but they all failed:

libgraphqlparser/test/ParserTests.cpp:13:10: fatal error: 'Ast.h' file not found

(after adding symlinks for the missing header files)

libgraphqlparser/test/Ast.h:237:43: error: a space is required between consecutive right angle brackets (use '> >')

I am pretty sure I missed a step here. Could some more detailed info be provided in the readme? Perhaps add a test/README.md?

Missing support for descriptions

Descriptions allow to annotate definitions in a GraphQL schema with human-readable content, which is also made available via introspection. It seems that libgraphqlparser currently fails when encountering descriptions with an exception of the following type:

Parser failed with error: <line.column-length>: syntax error, unexpected STRING, expecting EOF

Add support for building on Windows

Per the README.md Linux or Mac OS are listed as requirements. It would be useful to support building on Windoes.

I gave it a try and there's a few errors, but I was able to hack something together.

Structure of installation, includes and usages

@swolchok Great work, reached out to you on twitter as well.

I am doing OCaml bindings, https://github.com/fxfactorial/ocaml-graphql, and a server for graphql and have some questions.

(Installed from source)

  1. Doing: #include <graphqlparser/JsonVisitor.h> and getting
/usr/local/include/graphqlparser/JsonVisitor.h:13:10: fatal error: 'AstVisitor.h' file not found
#include "AstVisitor.h"
         ^
1 error generated.

Mistake in the cmake installation?

  1. Why is there a nested libgraphqlparser inside of graphqlparser in the installed headers?/

  2. Twitter question

  3. is graphql_ast_to_json intended just for debugging or is the graphql server intended to relevant info out of that and then do with the data as it wills, ie querying postgres, redis, etc. What are some more example C++ API based usages of the AST

Thread safety

The README should clarify about the thread safety of the library so it's clearer if/how to use on multithreaded environments.

Dependency on the graphql gem?

I'm wondering why the dependency on the graphql gem? If the only thing I want is to parse a query into that nice Ruby structure, why do I need the graphql gem?

Subscriptions

Not sure how much work this is to implement but support for graphql-js compatible subscriptions (maybe with an experimental flag or something?) would be super-useful and really appreciated.

I (very foolishly) assumed libgraphqlparser would support subscriptions when we started building on top of it. Now we've got a whole ruby GraphQL DSL built and nowhere to subscribe :(

Related Conversations:

visit_argument crashed. Need a few help to guide how to fix it.

I use Shopify/graphql-parser to write following ruby code but crashed in C

    def visit_argument(arg)
      key = arg.name.value
      # TODO crashed in C trace
      value_obj = arg.value
    end

I debug the C code in graphql-parser, the visit_argument should defined in https://github.com/Shopify/graphql-parser/blob/master/ext/graphql_parser/graphql_ruby.c#L220
I'm new on both C and C++, so I don't know how to debug them.
I report an issue on https://github.com/Shopify/graphql-parser/issues/14 with C error trace but the shopify seems not maintenance the lib anymore.
Btw, The problem seems related to https://github.com/Shopify/graphql-parser/issues/4. But I just not understand it well.

Thanks for any help.

ast::Node::accept() not const

Any reason that ast::Node::accept() is not const?

It would be great to create a nested visitor while visiting and we can't call accept() on any nested nodes because we always have const pointers or references to them.

Pure C API doesn't provide a way to access individual list-style subnodes

For example: Given I have a handle to a GraphQLAstSelectionSet, I can access the number of selections contained within it by calling GraphQLAstSelectionSet_get_selections_size. But how do I get a handle to a specific selection in the list? Is there a way to enumerate the selections contained within the selection set without resorting to visitors?

This also applies to other nodes with subnode lists, e.g. Document -> definitions, FragmentSpread -> directives etc.

Disclaimer: As I'm fairly new to all this stuff, I may be missing something really obvious here.

Multiple memory leaks as reported by clang's LeakSanitizer

Build dump_json_ast with -fsanitize=address on Linux x86_64:

$ clang --version
clang version 3.7.0 (https://github.com/llvm-mirror/clang.git 40b68b4c02b9d9e1e4138815747adf5589496240) (https://github.com/llvm-mirror/llvm.git dccade93466c50834dbaa5f4dabb81e90d768c40)
Target: x86_64-unknown-linux-gnu
Thread model: posix

$ mkdir build && cd build

$ env CXX=clang++ CXXFLAGS='-fsanitize=address -ggdb' cmake ..

$ make

and execute the following command:

$ echo -ne '\x7b\x0a\x20\x75\x30\x30\x30\x28\x69\x30\x3a\x20\x39\x30\x45' | ./dump_json_ast

Output:

Parser failed with error: 2.14: syntax error, unexpected EOF, expecting :

=================================================================
==5216==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 96 byte(s) in 2 object(s) allocated from:
    #0 0x4df280 in operator new(unsigned long) llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:62
    #1 0x7f5672faabc6 in yy::GraphQLParserImpl::parse() libgraphqlparser/build/parser.ypp:232:28
    #2 0x7f5672fd991b in facebook::graphql::doParse(char const**, void*) libgraphqlparser/GraphQLParser.cpp:26:17
    #3 0x7f5672fd9c0c in facebook::graphql::parseFile(_IO_FILE*, char const**) libgraphqlparser/GraphQLParser.cpp:48:17
    #4 0x4e222f in main libgraphqlparser/dump_json_ast.cpp:35:14
    #5 0x7f5671d89aa4 in __libc_start_main (/lib64/libc.so.6+0x21aa4)

Direct leak of 24 byte(s) in 1 object(s) allocated from:
    #0 0x4df280 in operator new(unsigned long) llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:62
    #1 0x7f5672fadc7f in yy::GraphQLParserImpl::parse() libgraphqlparser/build/parser.ypp:329:36
    #2 0x7f5672fd991b in facebook::graphql::doParse(char const**, void*) libgraphqlparser/GraphQLParser.cpp:26:17
    #3 0x7f5672fd9c0c in facebook::graphql::parseFile(_IO_FILE*, char const**) libgraphqlparser/GraphQLParser.cpp:48:17
    #4 0x4e222f in main libgraphqlparser/dump_json_ast.cpp:35:14
    #5 0x7f5671d89aa4 in __libc_start_main (/lib64/libc.so.6+0x21aa4)

Indirect leak of 56 byte(s) in 1 object(s) allocated from:
    #0 0x4df280 in operator new(unsigned long) llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:62
    #1 0x7f5672fadefd in yy::GraphQLParserImpl::parse() libgraphqlparser/build/parser.ypp:333:32
    #2 0x7f5672fd991b in facebook::graphql::doParse(char const**, void*) libgraphqlparser/GraphQLParser.cpp:26:17
    #3 0x7f5672fd9c0c in facebook::graphql::parseFile(_IO_FILE*, char const**) libgraphqlparser/GraphQLParser.cpp:48:17
    #4 0x4e222f in main libgraphqlparser/dump_json_ast.cpp:35:14
    #5 0x7f5671d89aa4 in __libc_start_main (/lib64/libc.so.6+0x21aa4)

Indirect leak of 48 byte(s) in 1 object(s) allocated from:
    #0 0x4df280 in operator new(unsigned long) llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:62
    #1 0x7f5672faebcb in yy::GraphQLParserImpl::parse() libgraphqlparser/build/parser.ypp:363:32
    #2 0x7f5672fd991b in facebook::graphql::doParse(char const**, void*) libgraphqlparser/GraphQLParser.cpp:26:17
    #3 0x7f5672fd9c0c in facebook::graphql::parseFile(_IO_FILE*, char const**) libgraphqlparser/GraphQLParser.cpp:48:17
    #4 0x4e222f in main libgraphqlparser/dump_json_ast.cpp:35:14
    #5 0x7f5671d89aa4 in __libc_start_main (/lib64/libc.so.6+0x21aa4)

Indirect leak of 48 byte(s) in 1 object(s) allocated from:
    #0 0x4df280 in operator new(unsigned long) llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:62
    #1 0x7f5672faabc6 in yy::GraphQLParserImpl::parse() libgraphqlparser/build/parser.ypp:232:28
    #2 0x7f5672fd991b in facebook::graphql::doParse(char const**, void*) libgraphqlparser/GraphQLParser.cpp:26:17
    #3 0x7f5672fd9c0c in facebook::graphql::parseFile(_IO_FILE*, char const**) libgraphqlparser/GraphQLParser.cpp:48:17
    #4 0x4e222f in main libgraphqlparser/dump_json_ast.cpp:35:14
    #5 0x7f5671d89aa4 in __libc_start_main (/lib64/libc.so.6+0x21aa4)

Indirect leak of 10 byte(s) in 3 object(s) allocated from:
    #0 0x477266 in __interceptor_strdup llvm/projects/compiler-rt/lib/asan/asan_interceptors.cc:590
    #1 0x7f5672faac75 in yy::GraphQLParserImpl::parse() libgraphqlparser/build/parser.ypp:232:59
    #2 0x7f5672fd991b in facebook::graphql::doParse(char const**, void*) libgraphqlparser/GraphQLParser.cpp:26:17
    #3 0x7f5672fd9c0c in facebook::graphql::parseFile(_IO_FILE*, char const**) libgraphqlparser/GraphQLParser.cpp:48:17
    #4 0x4e222f in main libgraphqlparser/dump_json_ast.cpp:35:14
    #5 0x7f5671d89aa4 in __libc_start_main (/lib64/libc.so.6+0x21aa4)

Indirect leak of 8 byte(s) in 1 object(s) allocated from:
    #0 0x4df280 in operator new(unsigned long) llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:62
    #1 0x7f5672fc307b in __gnu_cxx::new_allocator<std::unique_ptr<facebook::graphql::ast::Argument, std::default_delete<facebook::graphql::ast::Argument> > >::allocate(unsigned long, void const*) /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/ext/new_allocator.h:104:27
    #2 0x7f5672fc2c96 in std::_Vector_base<std::unique_ptr<facebook::graphql::ast::Argument, std::default_delete<facebook::graphql::ast::Argument> >, std::allocator<std::unique_ptr<facebook::graphql::ast::Argument, std::default_delete<facebook::graphql::ast::Argument> > > >::_M_allocate(unsigned long) /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/stl_vector.h:168:27
    #3 0x7f5672fc20bb in void std::vector<std::unique_ptr<facebook::graphql::ast::Argument, std::default_delete<facebook::graphql::ast::Argument> >, std::allocator<std::unique_ptr<facebook::graphql::ast::Argument, std::default_delete<facebook::graphql::ast::Argument> > > >::_M_emplace_back_aux<facebook::graphql::ast::Argument*&>(facebook::graphql::ast::Argument*&) /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/vector.tcc:404:22
    #4 0x7f5672fb4d6a in void std::vector<std::unique_ptr<facebook::graphql::ast::Argument, std::default_delete<facebook::graphql::ast::Argument> >, std::allocator<std::unique_ptr<facebook::graphql::ast::Argument, std::default_delete<facebook::graphql::ast::Argument> > > >::emplace_back<facebook::graphql::ast::Argument*&>(facebook::graphql::ast::Argument*&) /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/vector.tcc:101:4
    #5 0x7f5672fadd6b in yy::GraphQLParserImpl::parse() libgraphqlparser/build/parser.ypp:329:82
    #6 0x7f5672fd991b in facebook::graphql::doParse(char const**, void*) libgraphqlparser/GraphQLParser.cpp:26:17
    #7 0x7f5672fd9c0c in facebook::graphql::parseFile(_IO_FILE*, char const**) libgraphqlparser/GraphQLParser.cpp:48:17
    #8 0x4e222f in main libgraphqlparser/dump_json_ast.cpp:35:14
    #9 0x7f5671d89aa4 in __libc_start_main (/lib64/libc.so.6+0x21aa4)

Indirect leak of 3 byte(s) in 1 object(s) allocated from:
    #0 0x477266 in __interceptor_strdup llvm/projects/compiler-rt/lib/asan/asan_interceptors.cc:590
    #1 0x7f5672faec59 in yy::GraphQLParserImpl::parse() libgraphqlparser/build/parser.ypp:363:61
    #2 0x7f5672fd991b in facebook::graphql::doParse(char const**, void*) libgraphqlparser/GraphQLParser.cpp:26:17
    #3 0x7f5672fd9c0c in facebook::graphql::parseFile(_IO_FILE*, char const**) libgraphqlparser/GraphQLParser.cpp:48:17
    #4 0x4e222f in main libgraphqlparser/dump_json_ast.cpp:35:14
    #5 0x7f5671d89aa4 in __libc_start_main (/lib64/libc.so.6+0x21aa4)

SUMMARY: AddressSanitizer: 293 byte(s) leaked in 11 allocation(s).

afl

Allow building C binding out of the box

If I missed something, my apologies, please point me in the right direction.

I would like to wrap this library in Perl. For that I need the C binding built as a dynamic library. This seems not to be supported out of the box.

I added a simple Makefile for my own purposes, and have no problem in creating a pull request for it. But since the project uses cmake, perhaps you would rather do this differently?

Thanks!

SWIG bindings?

The readme for libgraphqlparser includes this snippet:

you can use it as the basis for an extension module for your favorite programming language instead of writing your own parser from scratch.

SWIG may help with this use case. It's a tool that generates glue code to call C++ APIs from other languages. It supports lots of different languages, including C#, Java, Python, Go, PHP, and Ruby. I've used it before to call a C++ API from Java and it worked pretty well for that use case.

It would be cool to include 'official' SWIG bindings to more easily allow this library to be used from other languages.

Various compiler warnings

And GCC6:

c:/Rtools/mingw_64/bin/g++  -std=gnu++11 -I"C:/PROGRA~1/R/R-devel/include" -DNDEBUG -I. -Ic   -I"C:/Users/Jeroen/Documents/R/win-library/3.4/Rcpp/include" -I"d:/Compiler/gcc-4.9.3/local330/include"  -D__USE_MINGW_ANSI_STDIO   -O2 -Wall  -mtune=core2 -c JsonVisitor.cpp -o JsonVisitor.o
JsonVisitor.cpp: In member function 'void facebook::graphql::ast::visitor::JsonVisitor::printChildList(const const_iterator&, size_t)':
JsonVisitor.cpp:41:23: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
   for (int ii = 0; ii < numChildren; ++ii) {
                       ^
g++ -fsanitize=address,undefined,bounds-strict -fno-omit-frame-pointer -fno-sanitize=object-size,vptr -std=gnu++11 -I/usr/local/lib/R/include -DNDEBUG -I. -Ic -I/usr/local/include -I"/usr/local/lib/R/site-library/Rcpp/include"   -fpic  -pipe -Wall -pedantic -O2 -mtune=native -c lexer.cpp -o lexer.o
lexer.lpp: In function ‘int yylex(yystype*, yy::location*, yyscan_t)’:
lexer.lpp:89:33: warning: format ‘%x’ expects argument of type ‘unsigned int*’, but argument 3 has type ‘int*’ [-Wformat=]
     sscanf(yytext + 1, "%x", &ch);

And on Xcode8:

lexer.cpp:796:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register yy_state_type yy_current_state;
        ^~~~~~~~~
lexer.cpp:797:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register char *yy_cp, *yy_bp;
        ^~~~~~~~~
lexer.cpp:797:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register char *yy_cp, *yy_bp;
        ^~~~~~~~~
lexer.cpp:798:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register int yy_act;
        ^~~~~~~~~
lexer.cpp:856:4: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
                        register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
                        ^~~~~~~~~
lexer.cpp:1326:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
        ^~~~~~~~~
lexer.cpp:1327:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register char *source = yyg->yytext_ptr;
        ^~~~~~~~~
lexer.cpp:1328:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register int number_to_move, i;
        ^~~~~~~~~
lexer.cpp:1328:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register int number_to_move, i;
        ^~~~~~~~~
lexer.cpp:1460:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register yy_state_type yy_current_state;
        ^~~~~~~~~
lexer.cpp:1461:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register char *yy_cp;
        ^~~~~~~~~
lexer.cpp:1468:3: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
                register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
                ^~~~~~~~~
lexer.cpp:1493:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register int yy_is_jam;
        ^~~~~~~~~
lexer.cpp:1495:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register char *yy_cp = yyg->yy_c_buf_p;
        ^~~~~~~~~
lexer.cpp:1497:2: warning: 'register' storage class specifier is deprecated and incompatible with C++1z [-Wdeprecated-register]
        register YY_CHAR yy_c = 1;
        ^~~~~~~~~

Build fails with latest ctypesgen

Since ctypesgen 0.1.1 (now 1.0.0) it has installed as "ctypesgen" instead of "ctypesgen.py" so CMakeLists.txt can't find the executable.

The fix is trivial:

FIND_PROGRAM(CTYPESGEN_FOUND ctypesgen.py)
IF (NOT CTYPESGEN_FOUND)
  FIND_PROGRAM(CTYPESGEN_FOUND ctypesgen)
ENDIF()

If that's acceptable I'll push a PR.

Thanks

Issue trying with the go example

Hi,

I got two issues trying out this package

 ❯❯❯ go build                                                                                                                      master ◼
# _/Users/bsr/Work/Programming/cpp/sample/libgraphqlparser/go
In file included from ./gotest.go:16:
../c/GraphQLAstVisitor.h:12:10: fatal error: 'c/GraphQLAst.h' file not found
#include "c/GraphQLAst.h"
         ^
1 error generated.

I corrected it by changing

#include "./GraphQLAst.h"

#include "./GraphQLAstForEachConcreteType.h"

from 

#include "c/GraphQLAst.h"

#include "c/GraphQLAstForEachConcreteType.h"

then

go build                                                                                                                      master ◼
# _/Users/bsr/Work/Programming/cpp/sample/libgraphqlparser/go
./callbacks.go:14:10: warning: implicit declaration of function 'printField' is invalid in C99 [-Wimplicit-function-declaration]
~/W/P/c/s/l/go ❯❯❯ ls                                                                                                                          master ✱ ◼
README.md    callbacks.go go           gotest.go
~/W/P/c/s/l/go ❯❯❯ ./go                                                                                                                        master ✱ ◼
field : myfield
Example error: 1.18-19: syntax error, unexpected on, expecting ( or @ or {

comple log is below

~/W/P/c/sample ❯❯❯ git clone https://github.com/graphql/libgraphqlparser.git                                                                            ⏎
Cloning into 'libgraphqlparser'...
remote: Counting objects: 161, done.
remote: Total 161 (delta 0), reused 0 (delta 0), pack-reused 161
Receiving objects: 100% (161/161), 105.33 KiB | 0 bytes/s, done.
Resolving deltas: 100% (80/80), done.
Checking connectivity... done.
~/W/P/c/sample ❯❯❯ cd libgraphqlparser
AstNode.h         GraphQLParser.h   PATENTS           dump_json_ast.cpp lexer.lpp         parser.ypp        syntaxdefs.h
CMakeLists.txt    JsonVisitor.cpp   README.md         go                location.hh       position.hh       test
CONTRIBUTING.md   JsonVisitor.h     ast               lexer.cpp         parser.tab.cpp    python
GraphQLParser.cpp LICENSE           c                 lexer.h           parser.tab.hpp    stack.hh
~/W/P/c/s/libgraphqlparser ❯❯❯ make install                                                                                                        master
make: *** No rule to make target `install'.  Stop.

~/W/P/c/s/libgraphqlparser ❯❯❯ cmake .                                                                                                           ⏎ master
-- The C compiler identification is AppleClang 5.1.0.5030040
-- The CXX compiler identification is AppleClang 5.1.0.5030040
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found PythonInterp: /usr/bin/python (found version "2.7.5") 
-- Found BISON: /usr/local/bin/bison (found suitable version "3.0.4", minimum required is "3") 
-- Found FLEX: /usr/bin/flex (found version "2.5.35") 
-- Configuring done
CMake Warning (dev):
  Policy CMP0042 is not set: MACOSX_RPATH is enabled by default.  Run "cmake
  --help-policy CMP0042" for policy details.  Use the cmake_policy command to
  set the policy and suppress this warning.

  MACOSX_RPATH is not specified for the following targets:

   graphqlparser

This warning is for project developers.  Use -Wno-dev to suppress it.

-- Generating done
-- Build files have been written to: /Users/bsr/Work/Programming/cpp/sample/libgraphqlparser
~/W/P/c/s/libgraphqlparser ❯❯❯ make install                                                                                                        master
[  5%] Generating Ast.h
[ 10%] Generating Ast.cpp
[ 15%] Generating AstVisitor.h
[ 20%] Generating c/GraphQLAst.h
[ 25%] Generating c/GraphQLAst.cpp
[ 30%] Generating c/GraphQLAstForEachConcreteType.h
Scanning dependencies of target graphqlparser
[ 35%] Building CXX object CMakeFiles/graphqlparser.dir/JsonVisitor.cpp.o
[ 40%] Building CXX object CMakeFiles/graphqlparser.dir/Ast.cpp.o
[ 45%] Building CXX object CMakeFiles/graphqlparser.dir/c/GraphQLAst.cpp.o
[ 50%] Building CXX object CMakeFiles/graphqlparser.dir/c/GraphQLAstNode.cpp.o
[ 55%] Building CXX object CMakeFiles/graphqlparser.dir/c/GraphQLAstToJSON.cpp.o
[ 60%] Building CXX object CMakeFiles/graphqlparser.dir/c/GraphQLAstVisitor.cpp.o
[ 65%] Building CXX object CMakeFiles/graphqlparser.dir/c/GraphQLParser.cpp.o
[ 70%] Building CXX object CMakeFiles/graphqlparser.dir/parser.tab.cpp.o
In file included from parser.tab.cpp:46:
parser.ypp:62:58: warning: backslash and newline separated by space [-Wbackslash-newline-escape]
    const char *heapStr;                                \                               
                                                         ^
1 warning generated.
[ 75%] Building CXX object CMakeFiles/graphqlparser.dir/lexer.cpp.o
In file included from lexer.lpp:17:
parser.ypp:62:58: warning: backslash and newline separated by space [-Wbackslash-newline-escape]
    const char *heapStr;                                \                               
                                                         ^
lexer.cpp:788:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register yy_state_type yy_current_state;
        ^~~~~~~~~
lexer.cpp:789:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register char *yy_cp, *yy_bp;
        ^~~~~~~~~
lexer.cpp:789:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register char *yy_cp, *yy_bp;
        ^~~~~~~~~
lexer.cpp:790:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register int yy_act;
        ^~~~~~~~~
lexer.cpp:848:4: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
                        register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
                        ^~~~~~~~~
lexer.cpp:1313:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
        ^~~~~~~~~
lexer.cpp:1314:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register char *source = yyg->yytext_ptr;
        ^~~~~~~~~
lexer.cpp:1315:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register int number_to_move, i;
        ^~~~~~~~~
lexer.cpp:1315:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register int number_to_move, i;
        ^~~~~~~~~
lexer.cpp:1447:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register yy_state_type yy_current_state;
        ^~~~~~~~~
lexer.cpp:1448:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register char *yy_cp;
        ^~~~~~~~~
lexer.cpp:1455:3: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
                register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
                ^~~~~~~~~
lexer.cpp:1480:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register int yy_is_jam;
        ^~~~~~~~~
lexer.cpp:1482:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register char *yy_cp = yyg->yy_c_buf_p;
        ^~~~~~~~~
lexer.cpp:1484:2: warning: 'register' storage class specifier is deprecated [-Wdeprecated-register]
        register YY_CHAR yy_c = 1;
        ^~~~~~~~~
16 warnings generated.
[ 80%] Building CXX object CMakeFiles/graphqlparser.dir/GraphQLParser.cpp.o
In file included from /Users/bsr/Work/Programming/cpp/sample/libgraphqlparser/GraphQLParser.cpp:14:
parser.ypp:62:58: warning: backslash and newline separated by space [-Wbackslash-newline-escape]
    const char *heapStr;                                \                               
                                                         ^
1 warning generated.
Linking CXX shared library libgraphqlparser.dylib
[ 90%] Built target graphqlparser
Scanning dependencies of target dump_json_ast
[ 95%] Building CXX object CMakeFiles/dump_json_ast.dir/dump_json_ast.cpp.o
Linking CXX executable dump_json_ast
[ 95%] Built target dump_json_ast
Scanning dependencies of target graphql-parser-python
[100%] Generating GraphQLParser.py
[100%] Built target graphql-parser-python
Install the project...
-- Install configuration: ""
-- Up-to-date: /usr/local/include/graphqlparser/c
-- Installing: /usr/local/include/graphqlparser/c/GraphQLAst.h
-- Installing: /usr/local/include/graphqlparser/c/GraphQLAstForEachConcreteType.h
-- Installing: /usr/local/include/graphqlparser/c/GraphQLAstNode.h
-- Installing: /usr/local/include/graphqlparser/c/GraphQLAstToJSON.h
-- Installing: /usr/local/include/graphqlparser/c/GraphQLAstVisitor.h
-- Installing: /usr/local/include/graphqlparser/c/GraphQLParser.h
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/hooks
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/info
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/logs
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/logs/refs
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/logs/refs/heads
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/logs/refs/remotes
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/logs/refs/remotes/origin
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/objects
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/objects/info
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/objects/pack
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/refs
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/refs/heads
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/refs/remotes
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/refs/remotes/origin
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/.git/refs/tags
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/ast
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/Ast.h
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/AstNode.h
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/AstVisitor.h
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/c
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/c/GraphQLAst.h
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/c/GraphQLAstForEachConcreteType.h
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/c/GraphQLAstNode.h
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/c/GraphQLAstToJSON.h
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/c/GraphQLAstVisitor.h
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/c/GraphQLParser.h
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/CMakeFiles
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/CMakeFiles/3.2.2
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/CMakeFiles/3.2.2/CompilerIdC
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/CMakeFiles/3.2.2/CompilerIdCXX
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/CMakeFiles/CMakeTmp
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/CMakeFiles/dump_json_ast.dir
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/CMakeFiles/graphqlparser.dir
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/CMakeFiles/graphqlparser.dir/c
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/go
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/GraphQLParser.h
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/JsonVisitor.h
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/lexer.h
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/python
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/python/CMakeFiles
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/python/CMakeFiles/graphql-parser-python.dir
-- Installing: /usr/local/include/graphqlparser/libgraphqlparser/syntaxdefs.h
-- Up-to-date: /usr/local/include/graphqlparser/libgraphqlparser/test
-- Up-to-date: /usr/local/include/graphqlparser/c
-- Installing: /usr/local/include/graphqlparser/c/GraphQLAst.h
-- Installing: /usr/local/include/graphqlparser/c/GraphQLAstForEachConcreteType.h
-- Installing: /usr/local/include/graphqlparser/c/GraphQLAstNode.h
-- Installing: /usr/local/include/graphqlparser/c/GraphQLAstToJSON.h
-- Installing: /usr/local/include/graphqlparser/c/GraphQLAstVisitor.h
-- Installing: /usr/local/include/graphqlparser/c/GraphQLParser.h
-- Installing: /usr/local/include/graphqlparser/AstNode.h
-- Installing: /usr/local/include/graphqlparser/GraphQLParser.h
-- Installing: /usr/local/include/graphqlparser/JsonVisitor.h
-- Installing: /usr/local/include/graphqlparser/lexer.h
-- Installing: /usr/local/include/graphqlparser/location.hh
-- Installing: /usr/local/include/graphqlparser/parser.tab.hpp
-- Installing: /usr/local/include/graphqlparser/position.hh
-- Installing: /usr/local/include/graphqlparser/stack.hh
-- Installing: /usr/local/include/graphqlparser/syntaxdefs.h
-- Installing: /usr/local/lib/libgraphqlparser.dylib
~/W/P/c/s/libgraphqlparser ❯❯❯ cd go                                                                                                             master ◼
README.md    callbacks.go gotest.go
~/W/P/c/s/l/go ❯❯❯ cat README.md                                                                                                                 master ◼
This directory contains an example usage of the GraphQL parser and AST
library from Go. See [cgo's
documentation](https://github.com/golang/go/wiki/cgo), particularly
the "Function pointer callbacks" section, for explanation of the
mechanisms in use.

To build, first build the main GraphQLParser library in the parent
directory, and then set this directory to be your `GOPATH` and run `go
build`.
~/W/P/c/s/l/go ❯❯❯ export GOPATH-`pwd`                                                                                                           master ◼
export: not valid in this context: GOPATH-/Users/bsr/Work/Programming/cpp/sample/libgraphqlparser/go
~/W/P/c/s/l/go ❯❯❯ export GOPATH=`pwd`                                                                                                         ⏎ master ◼
~/W/P/c/s/l/go ❯❯❯ go build                                                                                                                      master ◼
# _/Users/bsr/Work/Programming/cpp/sample/libgraphqlparser/go
In file included from ./gotest.go:16:
../c/GraphQLAstVisitor.h:12:10: fatal error: 'c/GraphQLAst.h' file not found
#include "c/GraphQLAst.h"
         ^
1 error generated.
~/W/P/c/s/l/go ❯❯❯ atom ../c/GraphQLAstVisitor.h                                                                                               ⏎ master ◼
~/W/P/c/s/l/go ❯❯❯ go build                                                                                                                      master ◼
# _/Users/bsr/Work/Programming/cpp/sample/libgraphqlparser/go
./callbacks.go:14:10: warning: implicit declaration of function 'printField' is invalid in C99 [-Wimplicit-function-declaration]
~/W/P/c/s/l/go ❯❯❯ ls                                                                                                                          master ✱ ◼
README.md    callbacks.go go           gotest.go
~/W/P/c/s/l/go ❯❯❯ ./go                                                                                                                        master ✱ ◼
field : myfield
Example error: 1.18-19: syntax error, unexpected on, expecting ( or @ or {
~/W/P/c/s/l/go ❯❯❯                                                                                                                             master ✱ ◼

Statically linking library

I'm trying to write bindings for the Rust programming language. Is there a way to statically link this project?

New release with `make install`

Hello! Thank you for your open source contribution. We're trying to package this up for easy install through Homebrew and are using the 0.1.0 release tag for the tar.gz packaging. However 0.1.0 doesn't have the make install task. Could you please create a new release with the make install task?

Thanks!

Homebrew/legacy-homebrew#44389

Python version not used during install

I have both python 3.5 and 2.7 installed in my machine (Arch Linux) but whenever I run the cmake . command it always picks /usr/bin/python which links to 3.5.

Currently I just made /usr/bin/python to point into 2.7 but it would be better if the build script would pick the correct one.

Bison build error on MacOS

Using the latest bison and flex from homebrew:

Jeroens-MacBook-Pro:libgraphqlparser jeroen$ make
[  4%] [FLEX][GraphQLScanner] Building scanner with flex 2.6.4
[  8%] Generating Ast.h
[ 13%] Generating Ast.cpp
[ 17%] Generating AstVisitor.h
[ 21%] Generating c/GraphQLAst.h
[ 26%] Generating c/GraphQLAst.cpp
[ 30%] Generating c/GraphQLAstForEachConcreteType.h
[ 34%] Generating JsonVisitor.h.inc
[ 39%] Generating JsonVisitor.cpp.inc
[ 43%] [BISON][graphqlparser_bison] Building parser with bison 3.2.1
parser.ypp:8.10-12: error: invalid version requirement: 3
 %require "3"
          ^^^
make[2]: *** [parser.tab.cpp] Error 1
make[1]: *** [CMakeFiles/graphqlparser.dir/all] Error 2
make: *** [all] Error 2

I can change the require to from "3" to "3.0" which works but I still get these warnings:

[ 43%] [BISON][graphqlparser_bison] Building parser with bison 3.2.1
parser.ypp:298.17-43: warning: unset value: $$ [-Wother]
 start:          document  { *outAST = $1; }
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
parser.ypp:446.23-26: warning: unused value: $2 [-Wother]
                 "..." "on" type_condition directives_opt selection_set { $$ = new InlineFragment(@$, $3, $4, $5); }
                       ^^^^
parser.ypp:451.17-26: warning: unused value: $1 [-Wother]
                 "fragment" fragment_name "on" type_condition directives_opt selection_set { $$ = new FragmentDefinition(@$, $2, $4, $5, $6); }
                 ^^^^^^^^^^
parser.ypp:451.42-45: warning: unused value: $3 [-Wother]
                 "fragment" fragment_name "on" type_condition directives_opt selection_set { $$ = new FragmentDefinition(@$, $2, $4, $5, $6); }
                                          ^^^^
parser.ypp:488.17-20: warning: unused value: $1 [-Wother]
 boolean_value:  TRUE { $$ = new BooleanValue(@$, true); }
                 ^^^^
parser.ypp:489.17-21: warning: unused value: $1 [-Wother]
         |       FALSE { $$ = new BooleanValue(@$, false); }
                 ^^^^^
parser.ypp:492.17-20: warning: unused value: $1 [-Wother]
 null_value:     NULL { $$ = new NullValue(@$); }
                 ^^^^
parser.ypp:597.20-25: warning: unused value: $1 [-Wother]
 schema_definition: SCHEMA directives_opt "{" operation_type_definition_list "}" { $$ = new SchemaDefinition(@$, $2, $4); }
                    ^^^^^^
parser.ypp:609.25-30: warning: unused value: $1 [-Wother]
 scalar_type_definition: SCALAR name directives_opt { $$ = new ScalarTypeDefinition(@$, $2, $3); }
                         ^^^^^^
parser.ypp:612.25-28: warning: unused value: $1 [-Wother]
 object_type_definition: TYPE name implements_interfaces_opt directives_opt "{" field_definition_list "}" { $$ = new ObjectTypeDefinition(@$, $2, $3, $4, $6); }
                         ^^^^
parser.ypp:616.17-26: warning: unused value: $1 [-Wother]
         |       IMPLEMENTS type_name_list { $$ = $2; }
                 ^^^^^^^^^^
parser.ypp:644.28-36: warning: unused value: $1 [-Wother]
 interface_type_definition: INTERFACE name directives_opt "{" field_definition_list "}" { $$ = new InterfaceTypeDefinition(@$, $2, $3, $5); }
                            ^^^^^^^^^
parser.ypp:647.24-28: warning: unused value: $1 [-Wother]
 union_type_definition: UNION name directives_opt "=" union_members { $$ = new UnionTypeDefinition(@$, $2, $3, $5); }
                        ^^^^^
parser.ypp:654.23-26: warning: unused value: $1 [-Wother]
 enum_type_definition: ENUM name directives_opt "{" enum_value_definition_list "}" { $$ = new EnumTypeDefinition(@$, $2, $3, $5); }
                       ^^^^
parser.ypp:665.31-35: warning: unused value: $1 [-Wother]
 input_object_type_definition: INPUT name directives_opt "{" input_value_definition_list "}" { $$ = new InputObjectTypeDefinition(@$, $2, $3, $5); }
                               ^^^^^
parser.ypp:668.28-33: warning: unused value: $1 [-Wother]
 type_extension_definition: EXTEND object_type_definition { $$ = new TypeExtensionDefinition(@$, $2); }
                            ^^^^^^
parser.ypp:671.23-31: warning: unused value: $1 [-Wother]
 directive_definition: DIRECTIVE "@" name arguments_definition_opt ON directive_locations { $$ = new DirectiveDefinition(@$, $3, $4, $6); }
                       ^^^^^^^^^
parser.ypp:671.67-68: warning: unused value: $5 [-Wother]
 directive_definition: DIRECTIVE "@" name arguments_definition_opt ON directive_locations { $$ = new DirectiveDefinition(@$, $3, $4, $6); }
                                                                   ^^

tag name is missing `v`

Did you intentionally leave out the v in the tag name this time? I don't care either way but just wanted to check.

Support for defining a schema

Hi, thank you for this project!
I am very new to GraphQL so forgive me if I am asking naive questions :).
I am considering implementing a graphql server in C++, and while I see that libgraphqlparser offer parsing of a graphql query, I could not find if it offers creating of Schema and executing query against it?

I know that in other languages(js) the idea is to generate the schema and then when query arrives it is parsed, validated and executed against the schema, so that is why I am looking for the libraries that would support the same thing in C++.

If there is support, would you mind sharing some code examples? Thanks!

possible memory leak

Performing fuzzy testing on libgraphqlparser. Libfuzzer and Valgrind complain of memory leaks. For an input file with content

START FILE

{d }#s
b{a }

END FILE

376 (48 direct, 328 indirect)
yy::GraphQLParserImpl::parse() (parser.ypp:336)
facebook::graphql::doParse(char const**, void*, bool)(GraphQLParser.cpp:24)

Probably parser trying to create new document for second line without deleting first one which was created for line1 "{d }#s".

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.