serverless教程5b:使用serverless开发AppSync GraphQL API


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

serverless教程
serverless教程

在这个例子中,数据层选择的是DynamoDB,但AppSync的数据源是AWS_LAMBDA(除此之外,还能选择AMAZON_DYNAMODB, AMAZON_ELASTICSEARCH, or AMAZON_OPENSEARCH_SERVICE)。也就是说,所有针对DynamoDB的CRUD操作都是通过相应Lambda实现的。

创建项目及设置

创建项目

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

bash
mkdir sls-appsync-graphql-demo
cd sls-appsync-graphql-demo
serverless create --template aws-nodejs

添加依赖库

bash
yarn add serverless-appsync-plugin

serverless.yml

在这里需要定义如下信息:

  • DynamoDB相关信息
  • AppSync基本信息:resolver到具体Lambda函数的映射
  • Lambda函数

其源码:

yaml
service: sls-appsync-graphql-demo
frameworkVersion: '3'

provider:
  name: aws
  runtime: nodejs14.x
  stage: dev
  region: eu-west-1
  iam:
    role:
      statements:
        - Effect: "Allow"
          Action:            
            - "dynamodb:PutItem"
            - "dynamodb:UpdateItem"
            - "dynamodb:DeleteItem"
            - "dynamodb:GetItem"
            - "dynamodb:Scan"
          Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/${self:custom.STUDENT_TABLE_NAME}"

custom:
  STUDENT_TABLE_NAME: appsync-student-table

  appSync:
    name: appsync-student-demo
    authenticationType: API_KEY
    mappingTemplates:      
      - type: Mutation
        field: createStudent
        dataSource: createStudentFunction
        request: false
        response: false
      - type: Mutation
        field: updateStudent
        dataSource: updateStudentFunction
        request: false
        response: false
      - type: Mutation
        field: deleteStudent
        dataSource: deleteStudentFunction
        request: false
        response: false
      - type: Query
        field: getStudents
        dataSource: getStudentsFunction
        request: false
        response: false      
    dataSources:        
      - type: AWS_LAMBDA
        name: createStudentFunction
        config:
          functionName: createStudent

      - type: AWS_LAMBDA
        name: updateStudentFunction
        config:
          functionName: updateStudent

      - type: AWS_LAMBDA
        name: deleteStudentFunction
        config:
          functionName: deleteStudent

      - type: AWS_LAMBDA
        name: getStudentsFunction
        config:
          functionName: getStudents  

functions: 
  getStudents:
    handler: functions/getStudents.handler
    environment:
      STUDENT_TABLE_NAME: !Ref StudentTable

  createStudent:
    handler: functions/createStudent.handler
    environment:
      STUDENT_TABLE_NAME: !Ref StudentTable

  updateStudent:
    handler: functions/updateStudent.handler
    environment:
      STUDENT_TABLE_NAME: !Ref StudentTable

  deleteStudent:
    handler: functions/deleteStudent.handler
    environment:
      STUDENT_TABLE_NAME: !Ref StudentTable

resources:
  Resources:
    StudentTable:
      Type: "AWS::DynamoDB::Table"
      Properties:
        KeySchema:
          - AttributeName: id
            KeyType: HASH
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
        BillingMode: PAY_PER_REQUEST
        TableName: ${self:custom.STUDENT_TABLE_NAME}

plugins:
  - serverless-appsync-plugin

GraphQL schema

增加文件schema.graphql:

GraphQL
schema {
    query: Query
    mutation: Mutation
}

type Query {
    getStudents: [Get!]!
}

type Mutation {
    createStudent(id: ID!, name: String!, address: String!): Save
    updateStudent(id: ID!, name: String!, address: String!): Update
    deleteStudent(id: ID!): Delete
}

type Get {
    id: ID!
    name: String
    address: String 
}

type Save {
    id: ID!
    name: String
    address: String 
}

type Update {
    id: ID!
    name: String
    address: String 
}

type Delete {
    id: ID! 
}

GraphQL resolvers

functions/createStudent.js

JavaScript
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();

module.exports.handler = async (event) => {
  const id = event.arguments.id;
  const name = event.arguments.name;
  const address = event.arguments.address;

  const params = {
    Item: {
      id: {
        S: id,
      },
      name: {
        S: name,
      },
      address: {
        S: address,
      },
    },
    ReturnConsumedCapacity: "TOTAL",
    TableName: process.env.STUDENT_TABLE_NAME,
  };

  return dynamodb
    .putItem(params)
    .promise()
    .then((data) => {
      return {
        id,
        name,
        address,
      };
    })
    .catch((err) => {
      console.log(err);
    });
};

functions/deleteStudent.js

JavaScript
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();

module.exports.handler = async (event) => {
  const id = event.arguments.id;

  const params = {
    Key: {
      id: {
        S: id,
      },
    },
    TableName: process.env.STUDENT_TABLE_NAME,
  };

  return dynamodb
    .deleteItem(params)
    .promise()
    .then((data) => {
      return {
        id,
      };
    })
    .catch((err) => {
      console.log(err);
    });
};

functions/getStudents.js

JavaScript
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();

module.exports.handler = async (event) => {
  const params = {
    TableName: process.env.STUDENT_TABLE_NAME,
  };

  return dynamodb
    .scan(params)
    .promise()
    .then((data) => {
      const studentList = [];
      for (let i = 0; i < data.Items.length; i++) {
        studentList.push({
          id: data.Items[i].id.S,
          name: data.Items[i].name.S,
          address: data.Items[i].address.S,
        });
      }
      return studentList;
    })
    .catch((err) => {
      console.log(err);
    });
};

functions/updateStuent.js

JavaScript
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();

module.exports.handler = async (event) => {
  const id = event.arguments.id;
  const name = event.arguments.name;
  const address = event.arguments.address;

  const params = {
    ExpressionAttributeNames: {
      "#n": "name",
      "#d": "address",
    },
    ExpressionAttributeValues: {
      ":n": {
        S: name,
      },
      ":d": {
        S: address,
      },
    },
    Key: {
      id: {
        S: id,
      },
    },
    ReturnValues: "ALL_NEW",
    TableName: process.env.STUDENT_TABLE_NAME,
    UpdateExpression: "SET #n = :n, #d = :d",
  };

  return dynamodb
    .updateItem(params)
    .promise()
    .then((data) => {
      const body = data.Attributes;
      return {
        id: body.id.S,
        name: body.name.S,
        address: body.address.S,
      };
    })
    .catch((err) => {
      console.log(err);
    });
};

部署及测试

运行如下命令部署:

bash
sls deploy

进入AWS AppSync控制台,就可以进行测试了:

AWS AppSync
AWS AppSync

最后不要忘记删除这个APP对应的资源:

bash
sls remove

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