聚光灯
AWSets:简化AWS资源列表
宣布AWSets,这是一个新的开源实用程序,用于抓取AWS帐户并导出其所有资源以进行进一步分析。
注意:可以找到所有代码和信息 在GitHub上 。这是Trek10前团队成员的客座帖子,现为CTO GetVoxi ,。非常感谢!
我找到了一种将AWS生态系统提供的各种工具的某些最佳部分融合到一些我认为其中一些人可能会喜欢学习的东西上的方法。我们将从技术开始,然后转向我们所做的工作。
由于一些关键点,我们选择AppSync作为基础。 GraphQL是在客户端之上构建客户端的出色界面,AppSync是针对各种数据存储(例如DynamoDB)实施GraphQL服务的“ AWS本机”方式。此外,您还可以获得一些简洁的功能,例如 订阅。我们发现以AppSync作为API层进行构建可以为项目带来便利和可预测的结果。
如果您熟悉AppSync,就会知道构建完整的API,为模型,连接,过滤器,查询和变异编写模式的每个部分会多么令人沮丧。您不仅必须编写架构,还必须使用速度模板语言(VTL)编写每个解析器。一个简单的应用程序可以迅速成为数百行SDL,VTL和Cloudformation。
Amplify CLI引入了一些出色的程序包,以使用GraphQL架构定义语言(SDL)将AppSync架构转换为类型,查询,突变,订阅,表和解析器。使用 支持的指令 CLI转换插件会将您的SDL转换为可部署的模板,从而简化了创建AppSync API的过程。它将几乎所有必需的请求和响应VTL模板以及数据存储区设置并连接在一起,从而使原本相当费力的工作耗时数分钟。
An example directive for the @model
directive looks like this:
type Product
@model {
id: ID!
name: String!
description: String!
price: String!
active: Boolean!
added: AWSDateTime!
}
转换后,我们将获得以下架构以及DynamoDB表的解析器和CloudFormation。
type Product {
id: ID!
name: String!
description: String!
price: String!
active: Boolean!
added: AWSDateTime!
}
type ModelProductConnection {
items: [Product]
nextToken: String
}
input CreateProductInput {
id: ID
name: String!
description: String!
price: String!
active: Boolean!
added: AWSDateTime!
}
input UpdateProductInput {
id: ID!
name: String
description: String
price: String
active: Boolean
added: AWSDateTime
}
input DeleteProductInput {
id: ID
}
input ModelProductFilterInput {
id: ModelIDFilterInput
name: ModelStringFilterInput
description: ModelStringFilterInput
price: ModelStringFilterInput
active: ModelBooleanFilterInput
added: ModelStringFilterInput
and: [ModelProductFilterInput]
or: [ModelProductFilterInput]
not: ModelProductFilterInput
}
type Query {
getProduct(id: ID!): Product
listProducts(filter: ModelProductFilterInput, limit: Int, nextToken: String): ModelProductConnection
}
type Mutation {
createProduct(input: CreateProductInput!): Product
updateProduct(input: UpdateProductInput!): Product
deleteProduct(input: DeleteProductInput!): Product
}
type Subscription {
onCreateProduct: Product @aws_subscribe(mutations: ["createProduct"])
onUpdateProduct: Product @aws_subscribe(mutations: ["updateProduct"])
onDeleteProduct: Product @aws_subscribe(mutations: ["deleteProduct"])
}
使用GraphQL Transform插件,我们将带有声明的9行SDL转换为62行。将其推断为多种类型,我们开始了解自动转换如何不仅节省我们的时间,而且还为我们提供了一种简单的方式来声明围绕AppSync API的样板。
尽管Amplify CLI的许多功能都非常出色,但我发现我个人更喜欢使用Amplify CLI定义资源。 AWS云开发套件 (CDK),因为它更容易与其他现有系统和流程集成。对我来说不幸的是,转换插件仅存在于Amplify CLI中。我决定要模拟此功能,我将使用Amplify CLI中使用的相同转换包,并将其集成到我的CDK项目中!
在进一步说明之前,我确实要指出,Amplify具有可扩展性和内置的“逃生舱口”,以便人们在不需要所有组件时可以根据需要使用零件。实际上,本文剩下的部分我们将依靠 是有记录的做法!
为了模拟Amplify CLI转换器,我们必须有一个模式转换器并导入现有的转换器。幸运的是,Amplify文档向我们展示了一个实现 这里 。由于我们希望所有相同的指令都可用,因此我们必须实现上述相同的程序包和结构。这为我们提供了指令解析,解析器创建和模板生成!
我们最终得到这样的结果:
import { GraphQLTransform } from 'graphql-transformer-core';
import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer';
import { ModelConnectionTransformer } from 'graphql-connection-transformer';
import { KeyTransformer } from 'graphql-key-transformer';
import { FunctionTransformer } from 'graphql-function-transformer';
import { VersionedModelTransformer } from 'graphql-versioned-transformer';
import { ModelAuthTransformer, ModelAuthTransformerConfig } from 'graphql-auth-transformer'
const { AppSyncTransformer } = require('graphql-appsync-transformer')
import { normalize } from 'path';
import * as fs from "fs";
const outputPath = './appsync'
export class SchemaTransformer {
transform() {
// These config values do not even matter... So set it up for both
const authTransformerConfig: ModelAuthTransformerConfig = {
authConfig: {
defaultAuthentication: {
authenticationType: 'API_KEY',
apiKeyConfig: {
description: 'Testing',
apiKeyExpirationDays: 100
}
},
additionalAuthenticationProviders: [
{
authenticationType: 'AMAZON_COGNITO_USER_POOLS',
userPoolConfig: {
userPoolId: '12345xyz'
}
}
]
}
}
// Note: This is not exact as we are omitting the @searchable 变压器.
const 变压器 = new GraphQLTransform({
变压器s: [
new AppSyncTransformer(outputPath),
new DynamoDBModelTransformer(),
new VersionedModelTransformer(),
new FunctionTransformer(),
new KeyTransformer(),
new ModelAuthTransformer(authTransformerConfig),
new ModelConnectionTransformer(),
]
})
const schema_path = './schema.graphql'
const schema = fs.readFileSync(schema_path)
return 变压器.transform(schema.toString());
}
}
在实现了相同的模式转换器之后,我意识到它并不完全适合我们的CDK实现。例如,我们希望可以通过CDK创建的可迭代资源,而不是DynamoDB表的JSON CloudFormation输出。我们自己来 变压器!
在此自定义转换器中,我们做两件事-查找@nullable指令,并在完成后获取转换器上下文。
When creating a custom key using the @key
directive on a model, the associated resolver does not 所有 ow for using $util.autoId()
to 生成唯一的标识符和创建时间. There are a couple of existing options, but we wanted to provide a "consistent" behavior to our developers that was easy to implement, so I created the "nullable" directive to enable using a custom @key
directive that would autoId
the id
field if it wasn't passed in.
# We use my nullable tag so that the create can have an autoid on the ID field
type Order
@model
@key(fields: ["id", "productID"]) {
id: ID! @nullable
productID: ID!
total: String!
ordered: AWSDateTime!
}
我已经使用 graphql自动变压器 作为指导。这会使用我们的自定义指令为该字段输出一个经过修改的解析器。
After schema transformation is complete, our custom 变压器 grabs the context, searches for AWS::DynamoDB::Table
resources, and builds a table object for us to create a table from later. Later, we can loop over this output and create our tables and resolvers like so:
createTablesAndResolvers(api: GraphQLApi, tableData: any, resolvers: any) {
Object.keys(tableData).forEach((tableKey: any) => {
let table = this.createTable(tableData[tableKey]);
const dataSource = api.addDynamoDbDataSource(tableKey, `Data source for ${tableKey}`, table);
Object.keys(resolvers).forEach((resolverKey: any) => {
let resolverTableName = this.getTableNameFromFieldName(resolverKey)
if (tableKey === resolverTableName) {
let resolver = resolvers[resolverKey]
dataSource.createResolver({
typeName: resolver.typeName,
fieldName: resolver.fieldName,
requestMappingTemplate: MappingTemplate.fromFile(resolver.requestMappingTemplate),
responseMappingTemplate: MappingTemplate.fromFile(resolver.responseMappingTemplate),
})
}
})
});
}
要在生成CDK模板之前运行我们的转换器,我们必须导入我们的转换器,运行该转换器,并将数据传递给我们的堆栈!
#!/usr/bin/env node
import * as cdk from '@aws-cdk/core';
import { AppStack } from '../lib/app-stack';
import { SchemaTransformer } from '../lib/schema-transformer';
const 变压器 = new SchemaTransformer();
const outputs = 变压器.transform();
const resolvers = 变压器.getResolvers();
const STAGE = process.env.STAGE || 'demo'
const app = new cdk.App({
context: { STAGE: STAGE }
})
new AppStack(app, 'AppStack', outputs, resolvers);
可以找到所有代码 在Github上 。重要的是要注意是否要采用这种方法,请确保固定变压器的版本并在将来进行验证。由于我们是从现有的Amplify CLI借用的,因此没有既定的合同,Amplify可能不会随着事情的发展而改变。
我们认为,将其作为CDK插件或npm软件包会更好。不幸的是,目前CDK插件系统仅支持凭据提供程序。我曾尝试将其作为插件编写(它的工作原理),但是您必须将cfdoc写入文件并从应用程序中读取它才能引入资源。