在这篇文章中,咱们将学习如何使用Node.js开发一个比特币实时价格行情的GraphQL API。php
比特币开发相关连接:java
在终端中执行以下命令建立一个新目录并进入该目录:node
mkdir btc-gql-api && cd btc-gql-api
在终端中执行yarn init
初始化项目目录,获得的package.json相似如下内容:ios
{ "name": "my-new-project", "version": "1.0.0", "description": "My New Project description.", "main": "index.js", "repository": { "url": "https://example.com/your-username/my-new-project", "type": "git" }, "author": "Your Name <you@example.com>", "license": "MIT" }
在终端执行touch index.js
建立一个空的js文件,而后在package.json中添加以下内容:git
... "scripts": { "start": "node index.js" }, ...
最终的package.json文件看起来相似以下内容:json
{ "name": "my-new-project", "version": "1.0.0", "description": "My New Project description.", "main": "index.js","scripts": { "start": "node index.js" }, "repository": { "url": "https://example.com/your-username/my-new-project", "type": "git" }, "author": "Your Name <you@example.com>", "license": "MIT" }
在项目目录中建立一个graph目录,获得以下的目录结构:axios
+ btc-gql-api |__ graphql |__ package.json |__ index.json
在graph目录中建立3个js文件:types.js、resolver.js和request.js,最终获得以下的目录结构:c#
+ btc-gql-api |__+graphql |____request.js |____resolvers.js |____types.js |__ package.json |__ index.json
在这个项目中,咱们将须要axios和graphql-yoga,所以在项目根目录 执行以下命令:api
yarn add axios graphql-yoga
好了,能够开始写代码了。浏览器
在GraphQL Schema中最基础的组件就是对象类型,它标识你能够从服务中提取的对象类型,以及其中包含哪些字段。例如:
type User { name: String! email: String! }
GraphQL有一些内置的基础类型:
更详细的文档能够参考graphql schema。
如今让咱们定义类型。打开./graphql/types.js文件,输入以下内容:
const typeDefs = ` scalar JSON type Price { price:JSON! }`; module.exports = typeDefs;
在上面的代码中,咱们定义了一个类型Price,它只有一个非空字段price,字段类型为JSON:
type Price { price:JSON! }
JSON并非graphql的内置类型,是咱们自定义的:
scalar JSON
GraphQL是关于数据管理的,查询基本上就是请求对象的指定字段。 例如:
query { getPrices { price } }
获得以下结果:
{ "data": { "getPrices": { "price": { "USD": { "15m": 10436.54, "last": 10436.54, "buy": 10436.54, "sell": 10436.54, "symbol": "$" } ... } } } }
能够看到,查询结果和请求有相同的结构。
在一个schema内有两种类型:查询(query)与修改(mutation)。
每一个GraphQL服务至少有一个查询类型,可能有一个修改类型。这些类型和常规的对象类型同样,可是它们定义了每一个GraphQL查询的入口点。看起来像这样:
scalar JSON type Price { price:JSON! } type Query { getPrices: Price! getPrice(currency:String!): Price! }
上面代码的意思是,咱们的GraphQL服务有一个Query类型,其中包含 getPrices和getPrice字段,其类型都是Price。咱们也能够看到字段 getPrice有参数(currency:String!)
。在GraphQL对象类型中的每一个 字段均可以有0或多个参数。
参数能够是必需的或可选的,在上面的例子中,咱们要求一个必需的 参数currency用来选择要查询的币种。
在咱们继续GraphQL以前,咱们须要一个辅助工具来获取比特币实时价格。为此咱们将使用blockchain.com的API,可是你能够换成任何你喜欢的服务。
打开./graphql/request.js文件,输入如下内容:
const axios = require("axios");module.exports = { getPrices: async () => { const url = "https://blockchain.info/ticker"; try { return await axios.get(url); } catch (error) { console.error(error); } } };
上面的代码使用axios来构造GET请求,固然你也能够换成其余你熟悉的工具。
每一个类型的每一个字段背后都对应一个解析器函数,该函数应当由GraphQL服务端开发者提供。当一个字段执行时,对应的解析器就被调用并生成结果。
若是一个字段生成一个标量值例如字符串或数字,那么执行就结束了。然而,若是一个字段生成一个对象值,那么查询将包含另外的字段,这将继续解析直到最终获得的字段都是标量值。
每一个GraphQL服务的顶层是全部可能的入口类型,一般被称为根(Root)类型或查询(Query)类型。
打开文件./graphql/resolvers.js,输入如下内容:
const requests = require("./requests"); const resolvers = { Query: { // Get all available prices async getPrices(parent, args, ctx, info) { const prices = await requests.getPrices(); return { price: prices.data }; }, // Get the price of a given currency symbol async getPrice(parent, args, ctx, info) { const prices = await requests.getPrices(); return { price: { [args["currency"]]: prices.data[args["currency"]] } }; } } }; module.exports = resolvers;
让咱们分解说明下以上代码。
首先引入咱们查询比特币实时行情的辅助工具:
const request = require("./request");
而后定义解析器:
const resolvers = { Query: { // Get all available prices async getPrices(parent, args, ctx, info) { const prices = await requests.getPrices(); return { price: prices.data }; }, // Get the price of a given currency symbol async getPrice(parent, args, ctx, info) { const prices = await requests.getPrices(); return { price: { [args["currency"]]: prices.data[args["currency"]] } }; } } };
咱们的解析器有一个根字段Query,在该对象内咱们将定义GraphQL Schema中的全部解析器。注意这些解析器的命名与types.js中一致。
每一个解析器都是一个函数,有4个参数:
如今咱们已经有了类型、解析器和辅助工具,要作的就是整合起来。
打开index.js文件,输入如下内容:
const { GraphQLServer } = require("graphql-yoga"); const typeDefs = require("./graphql/types.js"); const resolvers = require("./graphql/resolvers.js"); const server = new GraphQLServer({ typeDefs, resolvers, context: { //if we pass anything here can be available in all resolvers } }); server.start(() => console.log("Server is running on localhost:4000☄"));
首先咱们建立GraphQLServer实例:
... const server = new GraphQLServer({ typeDefs, resolvers, context: { //if we pass anything here can be available in all resolvers } }); ...
而后运行该实例:
server.start(() => console.log("Server is running on localhost:4000☄"));
运行后能够看到以下输出:
Server is running on localhost:4000☄
如今打开浏览器访问http://localhost:4000,测试以下查询:
query($currency:String!){ getPrice(currency:$currency){ price } } # Variables: { "currency": "USD" }
获得以下结果:
很是好!