• Original document address: graphql.org/learn/
  • Translation time: March 20, 2019
  • Translator: He Ruifeng (in-depth use of GraqhQL)
  • Purpose: to provide a more down-to-earth explanation of The Chinese language, as well as the author’s own experience with it plus: Other translations suck

Introduction to the

  • Client: GraphQL is a query language (for API) that sends GraphQL requests
  • Server-side: Use the Type System you pre-defined for your data at runtime to process Graphql requests sent from the client.

It doesn’t specify a specific database or storage, but relies entirely on your existing code and data

Setting up a GraphQL Service requires defining the types and internal fields, and then a parsing function to handle those types.

For example, a GraphQL service defines types and fields as shown below

//  who the logged in user is (me) 
typeQuery {me: User} // Query against Usertype User {
  id: ID
  name: String
}
Copy the code

The server side needs to parse each Field

function Query_me(request) {
  return request.auth.user;
}

function User_name(user) {
  return user.getName();
}
Copy the code

Once a GraphQL Service is started, you can accept GraphQL Queries and verify and execute them. Ensure that only queries related to predetermined types-fileds are processed, then execute the parse function and return the result, as shown in the following example

// Send the following query {me {name}}"me": {
    "name": "Luke Skywalker"}}Copy the code

2. Queries and Mutations

Original address:Graphql.org/learn/queri…

Fields

At its simplest, Graphql asks for a specific field on an object, so let’s start with a simple example

  • Query
    {
      hero {
        name
      }
    }
    Copy the code
  • Result
      {
      "data": {
          "hero": {
              "name": "R2-D2"}}}Copy the code

You can immediately see that the above query and result structures are identical. This is a feature of GraqhQL – you always get what you want, and the server knows exactly which fields the client wants.

The name field returns a String, in this case hero(“R2-D2”) of Star Wars.

In the above example, we just queried the name of hero and got a String, but fields can be a variable like name as well as a object, This allows you to sub-select the Fields in ‘Hero’. GraphQL Queries iterate over the related objects-fields, allowing the client to retrieve a large amount of relevant data in a single request. Often with REST architectures we might make multiple round-trip requests to achieve this effect. Here’s an example

  • Query

    {
      hero {
        name
        # Queries can have comments!
        # Friends is the secondary option mentioned above, enabling related queries 🐂🍺
        friends {
          name
        }
      }
    }
    Copy the code
  • Returns the result

    {
      "data": {
        "hero": {
          "name": "R2-D2"."friends": [{"name": "Luke Skywalker"
            },
            {
              "name": "Han Solo"},]}}}Copy the code

    Notice that the Friends field returns an array. GraphQL Queries are treated the same as individual items or lists, but we can deduce from the schema what type we expect to return.

    Arguments (Arguments)

    GraqhQL is already very useful for retrieving data, if only by iterating through related objects and their fields. But things get a lot more interesting when you can accept parameters in a query!

    In reST-style systems, you can pass only one set of parameters — query parameters and URL segments in HTTP requests. However, in GraphQL, each field or embedded object can fetch a set of parameters, which completely replaces the multiple API fetching method. You may even be able to send parameters to Scalar Fields for a one-off data conversion on the server rather than on each client separately.

  • Query

    {
      human(id: "1000") {
        name
        The height is in feet
        height(unit: FOOT)
      }
    }
    Copy the code
  • Returns the result

    {
      "data": {
        "human": {
          "name": "Luke Skywalker".# return to feet 🐂🍺
          "height": 5.6430448}}}Copy the code

Parameters can have many types. In the example above, we used an Enumeration type, which is a set of finite choices, namely meters or feet. GraphQL has a built-in set of types by default, as long as they can be serialized into your transport format.

Read more about the GraphQL type system here.

Aliases

If you’re observant, you might have noticed that since the object fields in the returned result match the related fields in the Query but contain no parameters, you can’t get different results by passing different parameters for the same field. That’s why we need aliases.

You need aliases when you need to fetch all the data in a Query with different parameters for a field

  • query
# Star Wars Beijing... Imperial Jedi, just focus on the nicknames here
{
  empireHero: hero(episode: EMPIRE) {
    name
  }
  jediHero: hero(episode: JEDI) {
    name
  }
}
Copy the code
  • result
{
  "data": {
    "empireHero": {
      "name": "Luke Skywalker"
    },
    "jediHero": {
      "name": "R2-D2"}}}Copy the code

The translator’s note: If you don’t have an alias, you can’t get two types of data from the hero field in the same request, so pass different parameters through the alias to get two types of data, and return empireHero and jediHero instead of hero, which makes it easier for the client.

Fragments: Reusable units

Add in the fact that our App has a complex page with two Hero camps occupying one side of the page, and you can see that query gets complicated all of a sudden because we repeatedly declare certain fields.

That’s why GraphQL includes reusable fragments that allow you to build a set of fields and reuse them over and over in Query. Here’s an example

  • query
{ leftComparison: hero(episode: EMPIRE) { ... comparisonFields } rightComparison: hero(episode: JEDI) { ... comparisonFields } } fragment comparisonFields on Character { name appearsIn friends { name } }Copy the code
  • result
{
  "data": {
    "leftComparison": {
      "name": "Luke Skywalker"."appearsIn": ["NEWHOPE"."EMPIRE"."JEDI"]."friends": [{"name": "Han Solo"},
        {  "name": "Leia Organa"}},],"rightComparison": {
      "name": "R2-D2"."appearsIn": ["NEWHOPE"."EMPIRE"."JEDI"]."friends": [{  "name": "Luke Skywalker"}]}}}Copy the code

You can see that without fragments, those fields will be repeated. The concept of fragmentation is often used when dividing complex application data, especially if you have multiple UI components (with different fragmentation) initializing data retrieval

Use variables in fragments

Here the usage is too simple please check out the official code: graphql.org/learn/queri…

Operation name

So far, we have used the syntactic sugar of query shorthand, omits the Query keyword and the query name, but it is necessary to specify a Query name in a production project.

Here is a complete example: the query keyword is a **operation type **, and HeroNameAndFriends is the operation name

query HeroNameAndFriends {
  hero {
    name
    friends {
      name
    }
  }
}
Copy the code

This operation type is neither Query,mutationm nor subscription, and simply describes what type of operation you want to do. This is necessary because you can’t pass variables to your query operations if you use ellipsis sugar

If you omit the operation name, you cannot pass the variable to the query

Give your query a good name. This is useful for debug and server logging. As an example of JavaScript, if you use anonymous functions all the time, it will be hard to debug when the function returns an error. Named Queries make it very easy to track

Variables

So far, we’ve written the parameters as strings in Query, but for the most part, these parameters are dynamic. For example, you might have a drop-down box to select a Star Wars episode, get its value, and pass it to Query as a query parameter.

!!!!! Please don’t do this!! Embed dynamic variables directly in your Query code, so that at Runtime the variables will be parsed into the corresponding string, and then serialize into graphQL-specific format. !!!!! Should be!! GraphQL handles external dynamic values like first-class citizens, and like a separate dictionary.

To use variables, there are three steps

  • Replace the static value in query with $variableName
  • The variable is named in parentheses after the query operation name
  • Give the variable a separate, mostly JSON-formatted variable table, and specify the type of the variable.
query HeroNameAndFriends($episode: Episode) {
  The # episode parameter accepts a $episode variable defined in advance in the query operation name and specifies the type of the $episode variable
  # In this case, the variable type is Episode
  hero(episode: $episode) {name friends {name}}} //"episode": "JEDI"
}
Copy the code

We can now pass the episode value to a Query dynamically, rather than repeatedly defining multiple static Queries. Again, the above usage is officially recommended. Do not build a Query in interpolation

Translator’s note: I used to do this a lot in JavaScript, for example

  const {episode} = outerParameter
  # Build with ES6 interpolation strings
  hero(episode: `${episode}`) {
    name
    friends {
      name
        }
      }
    }
Copy the code

Directives

We discussed above how variables can be used to avoid manually building dynamic queries using string interpolation. Using variables in parameters really solves a big class of problems. However, we will need to adjust our entire Query structure dynamically, the same way we use variables. For example, our UI component has a summary and detail view, one of which contains a lot more fields than the other.

query Hero($episode: Episode, $withFriends: Boolean!) {
  hero(episode: $episode) {
    name
    friends @include(if: $withFriends) {
      name
    }
  }
}
# variable
{
  "episode": "JEDI"."withFriends": false
}
# result{{"data": {
    "hero": {
      "name": "R2-D2"}}}}Copy the code

The example above is the use of the directive feature.

Directive: You can attach a field or fragment to your query, and the server will process your query based on the value of the passed variable.

There are two directives written into the core of the GraphQL standard, which should be supported in backend services implemented according to the standard

  • @include(if: Boolean), returns the result only if true is passed
  • @skip(if: Boolean) no result is returned when true is passed

Translator’s Note: In most cases, you won’t need to use it, but if you find that your Query builds are very complex, check to see if the instructions above can help you.

Mutations

In REST, a Request that has a side effect on the server does not use the HTTP Request Method. GraphQL is simpler – technically any query can be timed to write data. However, it is useful for any modification of data (new, modified, deleted) to be done by mutation by convention.

As with Query, if mutaion also returns an object, you can also retrieve the internal fields, almost in the same way as Query.

mutation CreateReviewForEpisode($ep: Episode! .$review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}
# variable
{
  "ep": "JEDI"."review": {
    "stars": 5,
    "commentary": "This is a great movie!"}}# the return value
{
  "data": {
    "createReview": {
      "stars": 5,
      "commentary": "This is a great movie!"}}}Copy the code

As you may notice, the particular parameter we pass to Review is an Object Type, which means that it will accept an object, not just a Scalar Type

Multiple fields in mutations

Query and mutation differ in one particular way. The query fields are executed in parallel, while the mutation fields are sequential, one after the other in order. This means that if we initiate two incrementCredits mutation operations in a request, the first request will be returned first, ensuring that our own application takes race condition into account.

Note: When your business is complex and your page may have complex asynchronous requests, consider not only the order in which the client requests are sent, but also the order in which the server returns each request.

Inline Fragments (Inline Fragments)

Similar to other type systems, GraphQL Schemas also support interface and collection types

If the field you want to query returns an interface or collection type, then you need to use the collected fragment to retrieve the actual data, as in the following example:

  • request
    query HeroForEpisode($ep: Episode!) {
      hero(episode: $ep) { name ... on Droid { primaryFunction } ... On Human {height}}}"ep": "JEDI"
    }
    Copy the code
  • result
{
  "data": {
    "hero": {
      "name": "R2-D2"."primaryFunction": "Astromech"}}}Copy the code

In the above query, the hero field returns a Character type, depending on the episode parameter to return Human or Droid. If there is no inline fragment, you can only query for fields built into Character, such as name

Meta fields

When using inline fragments, clients cannot identify the source of the data without a __typename meta field, as you can see in the following example

  • query
    {
      search(text: "an") {
        __typename
        ... on Human {
          name
        }
        ... on Droid {
          name
        }
        ... on Starship {
          name
        }
      }
    }
    Copy the code
  • result
    {
      "data": {
        "search": [{"__typename": "Human"."name": "Han Solo"
          },
          {
            "__typename": "Human"."name": "Leia Organa"
          },
          {
            "__typename": "Starship"."name": "TIE Advanced x1"}}}]Copy the code

Translator’s note: Without the flag, the data returned would look like this. You can’t handle it

{
  "data": {
    "search": [{"name": "Han Solo"
      },
      {
        "name": "Leia Organa"
      },
      {
        "name": "TIE Advanced x1"}}}]Copy the code

GraphQL provides some meta-fields, see the link below

!!!!!!!!! Complete!!

The Server side translation of the document is also ready: juejin.cn/post/684490…