serverless教程5a:使用serverless开发GraphQL API


在开发无服务器应用的时候,通过纯手工方式创建各种资源的话,效率会非常低,因此需要借助一些框架来提高开发效率。下面介绍如何在serverless中开发GraphQL API(AWS + DynamoDB)。

serverless教程
serverless教程

注意:下面方式并没有使用AWS AppSync,而是创建一个普通的Lambda,在调用Lambda的时候会启动一个ApolloServer。

创建项目及设置

创建项目

首先创建一个项目并初始化:

bash
mkdir sls-graphql-demo
cd sls-graphql-demo
yarn init -y

添加依赖库

bash
yarn add apollo-server-lambda graphql
yarn add -D serverless-offline

GraphQL相关定义

添加文件src/schema.graphql:

JavaScript
type Query {
  item(id: ID!): Item
}

type Mutation {
  createItem(content: String!): Item
}

type Item {
  id: ID!
  content: String
}

添加文件src/graphql.js:

JavaScript
const fs = require('fs')
const { ApolloServer, gql } = require('apollo-server-lambda')

const schema = fs.readFileSync('./src/schema.graphql', 'utf8')

const resolvers = { 
  Query: {
    item: () => {},
  },

  Mutation: {
    createItem: () => {},
  }
};

const server = new ApolloServer({ typeDefs: schema, resolvers })

// 当Lambda被调用时启动服务器
exports.handler = server.createHandler();

serverless相关配置

添加文件:serverless.yml

yaml
service: sls-graphql-example

provider:
  name: aws
  runtime: nodejs14.x
  region: eu-west-1
  apiGateway:
    shouldStartNameWithService: true

functions:
  graphql:
    handler: src/graphql.handler
    events:
      - http:
          path: graphql
          method: any # 所有类型的HTTP请求都会访问这个Lambda
          cors: true

plugins:
  - serverless-offline

更新package.json

json
"scripts": {
  "local": "sls offline"
}

测试

运行如下命令启动服务:

bash
yarn local

在界面中进行简单查询:

graphql
query DemoQuery {
  item(id: "01") {
    id
  }
}

由于目前还没有任何数据,自然不能返回任何值了:

json
{
  "data": {
    "item": null
  }
}

连接DyanmoDB

添加依赖库:

bash
yarn add uuid
yarn add -D aws-sdk

定义serverless资源

首先更新serverless.yml:

yaml
service: sls-graphql-example

provider:
  name: aws
  runtime: nodejs14.x
  region: eu-west-1
  environment:
    TABLE_NAME: sls-graphql-table
  apiGateway:
    shouldStartNameWithService: true
  iam:
    role:
      statements:
        - Effect: Allow
          Action:
            - dynamodb:GetItem 
            - dynamodb:PutItem
          Resource: 'arn:aws:dynamodb:${self:provider:region, self:provider.region}:*:table/${self:provider.environment.TABLE_NAME}'

functions:
  graphql:
    handler: src/graphql.handler
    events:
      - http:
          path: graphql
          method: any 
          cors: true

resources:
  Resources:
    ItemsTable: 
      Type: 'AWS::DynamoDB::Table'
      Properties:
        AttributeDefinitions:
          - AttributeName: itemId
            AttributeType: S
        KeySchema:
          - AttributeName: itemId
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: ${self:provider.environment.TABLE_NAME}

plugins:
  - serverless-offline

更新GraphQL相关文件

安装新的依赖库:

none
yarn add uuid

更新graphql.js

JavaScript
const fs = require('fs')
const { ApolloServer, gql } = require('apollo-server-lambda')
const AWS = require('aws-sdk')
const { v4: uuidv4 } = require('uuid')

const schema = fs.readFileSync('./src/schema.graphql', 'utf8')

const resolvers = { 
  Query: {
    item: async (_, { id }) => {
      const dynamoDb = new AWS.DynamoDB.DocumentClient()

      const params = {
        TableName: process.env.TABLE_NAME,
        Key: {
          itemId: id,
        },
      }
      const { Item } = await dynamoDb.get(params).promise()
      return {
        ...Item,
        id: Item.itemId,
      }
    },
  },

  Mutation: {
    createItem: async (_, { content }) => {
      const dynamoDb = new AWS.DynamoDB.DocumentClient()
      const id = uuidv4()

      const params = {
        TableName: process.env.TABLE_NAME,
        Item: {
          itemId: id,
          content,
        },
      }
      await dynamoDb.put(params).promise()
      return {
        content,
        id,
      }
    },
  }
};

const server = new ApolloServer({ typeDefs: schema, resolvers })

exports.handler = server.createHandler();

测试

部署到AWS后,对应的URL类似于:https://xxxxxxxxx.execute-api.eu-west-1.amazonaws.com/dev/graphql

query

进行如下查询:

graphql
query Query {
  item(id: "01") {
    id
    content
  }
}

mutation

使用如下的GraphQL进行测试:

graphql
mutation CreateItem($content: String!) {
  createItem(content: $content) {
    content
  }
}

配套参数:

json
{
  "content":  "test content"
}

其返回值为:

json
{
  "data": {
    "createItem": {
      "content": "test content"
    }
  }
}

文章作者: 逻思
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 逻思 !