淘先锋技术网

首页 1 2 3 4 5 6 7

graphql解析器

In this article we’ll be looking into creating our own data structures in a GraphQL API. Everything we’ll be going over can be explored deeper in the official GraphQL docs.

在本文中,我们将研究在GraphQL API中创建自己的数据结构。 我们将要进行的所有操作都可以在GraphQL官方文档中进行更深入的探讨。

先决条件 (Prerequisites)

Since we are setting up a basic API, it would be best to first know how to make queries to test our data.

由于我们正在设置基本的API,因此最好首先知道如何进行查询以测试我们的数据。

安装 (Installation)

For the sake of simplicity I recommend using Prepros, or babel, so we can use some of the latest JavaScript features like import.

为了简单起见,我建议使用Preprosbabel ,这样我们就可以使用一些最新JavaScript功能,例如import

If you use Prepros, make sure the Babel and Auto Compile options are on for your server.js file

如果使用Prepros,请确保server.js文件的Babel和Auto Compile选项处于启用状态

For setting up our server, we’ll be using graphql-yoga, and nodemon. nodemon will allow us to have automatic serve reload on file changes and graphql-yoga gives us simple tooling to setup an Express-based GraphQL server.

为了设置我们的服务器,我们将使用graphql-yoganodemonnodemon将使我们能够在文件更改时自动重新加载服务,而graphql-yoga为我们提供了简单的工具来设置基于Express的GraphQL服务器。

$ npm i graphql-yoga nodemon

nodemon设置 (nodemon Setup)

Lets’ start with getting nodemon working. Under scripts in the project’s package.json file, we’ll just add "start": "nodemon server.js", so instead of running node server we’ll run npm run start.

让我们从让nodemon开始工作开始。 在项目的package.json文件中的scripts下,我们将仅添加"start": "nodemon server.js" ,因此,我们将运行npm run start而不是运行node server

package.json
package.json
{
  "name": "graphql-api",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "dependencies": {
    "graphql-yoga": "^1.16.7"
  },
  "devDependencies": {
    "nodemon": "^1.19.1"
  },
  "scripts": {
    "start": "nodemon server.js"
  },
  "author": "",
  "license": "ISC"
}

服务器设置 (Server Setup)

Over in our main file we’re going to import GraphQLServer from graphql-yoga to get our API working on localhost:4000. Our server is going to need two things, our type definitions, which will initialize and structure our data, and our resolvers, which tell the server how to get and filter the data. To keep things organized we’re going to create variables for our definitions and resolvers and pass those to our server function.

在我们的主文件中,我们将从graphql-yoga导入GraphQLServer ,以使我们的API在localhost:4000 。 我们的服务器将需要两件事,我们的类型定义将初始化和结构化我们的数据,我们的解析器将告诉服务器如何获取和过滤数据。 为了使事情井井有条,我们将为定义和解析器创建变量,并将其传递给服务器函数。

server.js
server.js
import { GraphQLServer } from 'graphql-yoga'

const typeDefs = ``; // Our definitions need to be in template literals

const resolvers = {};

const server = new GraphQLServer({ typeDefs, resolvers }) ;

server.start(() => console.log('server running'));

This will return an error for now since we haven’t set up a schema in typeDefs yet.

由于我们尚未在typeDefs设置架构, typeDefs这将暂时返回错误。

类型定义 (Type Definitions)

We can set up a basic query by simply adding type Query {} with a list of the data we want to make available with what type the return data will be. While we can make our own, GraphQL comes with a few baked in types; String, Int (all real numbers), Float (decimal numbers), Boolean, ID, and any of these placed in brackets is an array of that type. Any type ending with a ! is set as a non-nullable type, meaning it will return an error if nothing is sent back.

我们可以通过简单地在type Query {}上添加我们要提供的数据列表以及返回数据的类型来设置基本查询。 虽然我们可以自己制作,但GraphQL附带了一些烘焙的类型。 StringInt (所有实数), Float (十进制数), BooleanID以及放在方括号中的任何一种都是该类型的数组。 任何以!结尾的类型 设置为不可为null的类型,这意味着如果没有返回任何内容,它将返回错误。

Here’s an example of different possible variations. Note that you wouldn’t have multiple variations for the same field, as this is just for illustrative purposes:

这是一个不同的变化示例。 请注意,同一字段不会有多个变体,因为这只是出于说明目的:

server.js
server.js
const typeDefs = `
  type Query {
    user: String      # null
    user: String!     # error 'Cannot return null for non-nullable field Query.user'
    users: [String!]! # must return an array of non-null strings
  }
`;

Over in localhost:4000 you’ll notice that you no longer get an error when typing any of these, but will get an error or null when you run the query since we haven’t told it how to get the data yet.

localhost:4000您会注意到键入任何一个都不会再出现错误,但是运行查询时将得到错误或为null,因为我们还没有告诉它如何获取数据。

解析器 (Resolvers)

To be able to get data, we need to make a function with the same name as what we’re querying, and have it return what we want.

为了能够获取数据,我们需要创建一个与查询名称相同的函数,并使它返回我们想要的内容。

server.js
server.js
const resolvers = {
  Query: {
    user(){
      return 'I am a string';
    },
    users(){
      const names = ['Chomp', 'Jaws', 'Alli'];
      return names;
    }
  }
};

自定义类型 (Custom Types)

Types like String, Int, and Boolean are just what comes with GraphQL out-of-the-box, but we can also make our own types that will return much more intricate data and pass that type to our query to make it requestable.

现成的GraphQL都是StringIntBoolean类的类型,但是我们也可以使自己的类型返回更复杂的数据,并将该类型传递给我们的查询以使其可请求。

Outside of Query but still in typeDefs we can make our own type like User (it’s best practice for custom types to be capitalized) and set up the data we want it to have. Just like in Query, each item in our type must also be typed, like age: Int!, and we’ll have the data returned by the corresponding resolver.

Query之外,但仍在typeDefs我们可以创建自己的类型(如User (将大写的自定义类型设为最佳做法),并设置所需的数据。 就像在Query ,我们类型中的每个项目也必须键入,例如age: Int! ,我们将获得相应解析器返回的数据。

server.js
server.js
const typeDefs = `
  type Query {
    user: User! # Must be of our custom type, User
  }

  type User {
    name: String!
    age: Int!
    friends: [String]!
  }
`;

And over in our resolver we can just pass back an object with our data.

在解析器中,我们可以仅将对象与我们的数据一起传回。

const resolvers = {
  Query: {
    user(){
      return {
        name: 'Chomp',
        age: 47,
        friends: ['Alli', 'Jaws']
      };
    }
  }
};

资料设定 (Data Setup)

In a real-world scenario we wouldn’t be returning all of our data in the resolvers like this, but actually getting it from some other source like a database. Instead of worrying about a backend we’re just going to set up some dummy data to use.

在现实世界中,我们不会像这样在解析器中返回所有数据,而是实际上是从数据库等其他来源获取数据。 不用担心后端,我们只需要设置一些虚拟数据即可使用。

const users = [
  {
    name: 'Chomp',
    age: 47,
    friends: ['Alli', 'Jaws']
  },{
    name: 'Alli',
    age: 16,
    friends: ['Chomp', 'Jaws']
  },{
    name: 'Jaws',
    age: 35,
    friends: ['Alli', 'Chomp']
  },
];

Since we’re just going to get the whole array of users, we’ll tell typeDefs we want an array of type User and the resolver will just return the whole users array.

由于我们只是要获取整个用户数组,因此我们将告诉typeDefs我们想要一个类型为User的数组,而解析程序将仅返回整个users数组。

const typeDefs = `
 type Query {
    user: [User!]! 
  }

  type User {
    name: String!
    age: Int!
    friends: [String]!
  }
`;

const resolvers = {
  Query: {
    user(){
      return users;
    }
  }
};

争论 (Arguments)

Right now our only options are to return one specific piece of data, everything. What if we want to filter the response down to what we want?

现在,我们唯一的选择是返回一个特定的数据,所有数据。 如果我们想将响应过滤到想要的结果该怎么办?

We can do that by setting up arguments in our query and using them in conditional statements in the resolver. Our arguments must also be typed.

为此,我们可以在查询中设置参数,然后在解析器的条件语句中使用它们。 我们的论点也必须输入。

const typeDefs = `
 type Query {
    user(name: String!): [User!]! 
  }
`;

In our resolvers we have access to some very useful objects that GraphQl gives us. For now all we need are parent and args.

在解析器中,我们可以访问GraphQl给我们的一些非常有用的对象。 现在,我们需要的是parentargs

  • parent: Info on the parent element when you have nested custom types. So if we had a User type which accessed a Post type, each post would have access to the data on the user.

    parent :嵌套自定义类型时,有关parent元素的信息。 因此,如果我们有一个访问Post类型的User类型,则每个帖子都可以访问该用户上的数据。

  • args: All of our arguments passed into the query.

    args :所有我们传递给查询的参数。

  • ctx: Short for context, anything that the query made may need like authentication data.

    ctx : context的缩写,查询所需要的任何内容,例如身份验证数据。

  • info: Information about the state of the query.

    info :有关查询状态的信息。

Here, we’re going to check if there’s any argument at all on args and, if there is, use JavaScript’s filter() to return only the users whose name matches our argument.

在这里,我们将检查args上是否有任何参数,如果有,请使用JavaScript的filter()仅返回名称与我们的参数匹配的用户。

server.js
server.js
const resolvers = {
  Query: {
    user(parent, args, ctx, info){
      if (!args.name) return users;

      else return users.filter(user => {
        return user.name.toLowerCase().includes(args.name.toLowerCase());
      });
    }
  }
};

Over in localhost:4000 we can make use of our argument like this:

localhost:4000我们可以像这样使用我们的参数:

{
  user(name: "alli") {
    name
    friends
  }
}

关系数据 (Relational Data)

To allow more nested data we can add our custom types into other custom types. When we do that, we need to add another resolver outside of Query for that type of data.

为了允许更多的嵌套数据,我们可以将我们的自定义类型添加到其他自定义类型中。 这样做时,我们需要在Query之外为该类型的数据添加另一个解析器。

We’re going to make it so whenever we get a user we can get back the user data for each of their friends.

我们将做到这一点,以便每当我们有一个用户时,我们都可以取回他们每个朋友的用户数据。

server.js

server.js

Our resolver is going to create an empty object, loop over each friend on parent to put every matching user into the friends array, and return friends to our query.

我们的解析器将创建一个空对象,在parent对象上的每个朋友上循环,以将每个匹配的用户放入friends数组中,并将friends返回给我们的查询。

const typeDefs = `
 type Query {
    user(name: String!): [User!]!
  }

  type User {
    name: String!
    age: Int!
    friends: [User!]!
  }
`;

const resolvers {
  Query: { ... },
  User: { // The nested type that we're querying for
    friends(parent, args, ctx, info) { 
        const friends = [];

        parent.friends.forEach(friend => users.filter(user => {
          if (user.name.toLowerCase().includes(friend.toLowerCase())) friends.push(user);
        }));

        return friends;
    }
  }
};

结论 (Conclusion)

While there’s still much more to explore with GraphQL, I hope this worked as a thorough enough introduction to setting up our own API.

尽管GraphQL还有很多值得探索的地方,但我希望它能作为介绍如何设置我们自己的API的足够详尽的介绍。

If you had any difficulty getting our example to work properly you can always reference this repo for it.

如果您在使我们的示例正常工作方面遇到任何困难,则可以随时参考此仓库

翻译自: https://www.digitalocean.com/community/tutorials/graphql-schemas-resolvers-graphql

graphql解析器