Created
December 3, 2019 02:28
-
-
Save buggy/4d75dde357b6771d3050dcccf41ca026 to your computer and use it in GitHub Desktop.
Generate SAM Project Using Amplify Transformers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as fs from "fs"; | |
import * as yaml from "js-yaml"; | |
import GraphQLTransform from "graphql-transformer-core"; | |
import DynamoDBModelTransformer from "graphql-dynamodb-transformer"; | |
import ModelAuthTransformer from "graphql-auth-transformer"; | |
import ModelConnectionTransformer from "graphql-connection-transformer"; | |
import SearchableModelTransformer from "graphql-elasticsearch-transformer"; | |
import VersionedModelTransformer from "graphql-versioned-transformer"; | |
import FunctionTransformer from "graphql-function-transformer"; | |
import HTTPTransformer from "graphql-http-transformer"; | |
import KeyTransformer from "graphql-key-transformer"; | |
import cloudform from "cloudform"; | |
const [ node, app, schemaFile, outDir ] = process.argv; | |
if (!schemaFile || !outDir) { | |
console.log("Usage: index <schemaFile> <outDir>"); | |
process.exit(1); | |
} | |
const transformer = new GraphQLTransform({ | |
transformers: [ | |
// TODO: Removing until further discussion. `getTransformerOptions(project, '@model')` | |
new DynamoDBModelTransformer(), | |
new VersionedModelTransformer(), | |
new FunctionTransformer(), | |
new HTTPTransformer(), | |
new KeyTransformer(), | |
new ModelConnectionTransformer(), | |
// TODO: Build dependency mechanism into transformers. Auth runs last | |
// so any resolvers that need to be protected will already be created. | |
new ModelAuthTransformer({ | |
authConfig: { | |
defaultAuthentication: { | |
authenticationType: "AMAZON_COGNITO_USER_POOLS", | |
userPoolConfig: { userPoolId: "us-west-2_0E9fbxLFj" } | |
} | |
} | |
}), | |
new SearchableModelTransformer() | |
] | |
}); | |
const schema = fs.readFileSync(schemaFile).toString(); | |
const result = transformer.transform(schema); | |
interface IStringMap { | |
[pname: string]: string; | |
} | |
function makeFnSubLocal(fnSub: [string, IStringMap?]) { | |
const [str, map] = fnSub; | |
return str.replace("s3://${S3DeploymentBucket}/${S3DeploymentRootKey}/", "../"); | |
} | |
function cleanStack(stack: any): any { | |
stack.Transform = "AWS::Serverless-2016-10-31"; | |
for (const resourceName in stack.Resources) { | |
const resource = stack.Resources[resourceName]; | |
switch (resource.Type) { | |
case "AWS::AppSync::GraphQLSchema": | |
if ( | |
resource.Properties.DefinitionS3Location && | |
resource.Properties.DefinitionS3Location["Fn::Sub"] | |
) { | |
resource.Properties.DefinitionS3Location = makeFnSubLocal( | |
resource.Properties.DefinitionS3Location["Fn::Sub"] | |
); | |
} | |
break; | |
case "AWS::AppSync::FunctionConfiguration": | |
if ( | |
resource.Properties.RequestMappingTemplateS3Location && | |
resource.Properties.RequestMappingTemplateS3Location["Fn::Sub"] | |
) { | |
resource.Properties.RequestMappingTemplateS3Location = makeFnSubLocal( | |
resource.Properties.RequestMappingTemplateS3Location["Fn::Sub"] | |
); | |
} | |
if ( | |
resource.Properties.ResponseMappingTemplateS3Location && | |
resource.Properties.ResponseMappingTemplateS3Location["Fn::Sub"] | |
) { | |
resource.Properties.ResponseMappingTemplateS3Location = makeFnSubLocal( | |
resource.Properties.ResponseMappingTemplateS3Location["Fn::Sub"] | |
); | |
} | |
break; | |
case "AWS::AppSync::Resolver": | |
if ( | |
resource.Properties.RequestMappingTemplateS3Location && | |
resource.Properties.RequestMappingTemplateS3Location["Fn::Sub"] | |
) { | |
resource.Properties.RequestMappingTemplateS3Location = makeFnSubLocal( | |
resource.Properties.RequestMappingTemplateS3Location["Fn::Sub"] | |
); | |
} | |
if ( | |
resource.Properties.ResponseMappingTemplateS3Location && | |
resource.Properties.ResponseMappingTemplateS3Location["Fn::Sub"] | |
) { | |
resource.Properties.ResponseMappingTemplateS3Location = makeFnSubLocal( | |
resource.Properties.ResponseMappingTemplateS3Location["Fn::Sub"] | |
); | |
} | |
break; | |
case "AWS::CloudFormation::Stack": | |
resource.Type = "AWS::Serverless::Application"; | |
if ( | |
resource.Properties.TemplateURL && | |
resource.Properties.TemplateURL["Fn::Sub"] | |
) { | |
const [ | |
path, | |
params | |
] = resource.Properties.TemplateURL["Fn::Sub"]; | |
resource.Properties.TemplateURL = path.replace( | |
".json", | |
".yaml" | |
).replace("https://s3.amazonaws.com/${S3DeploymentBucket}/${S3DeploymentRootKey}/stacks/", "./"); | |
} | |
// Strip the "S3DeploymentBucket" and "S3DeploymentRootKey" from the parameters to the Stack | |
if (resource.Properties.Parameters) { | |
const { | |
S3DeploymentBucket, | |
S3DeploymentRootKey, | |
...otherParameters | |
} = resource.Properties.Parameters; | |
resource.Properties.Parameters = otherParameters; | |
} | |
break; | |
} | |
stack.Resources[resourceName] = resource; | |
} | |
// Strip "S3DeploymentBucket" and "S3DeploymentRootKey" from the stack parameters | |
const { | |
S3DeploymentBucket, | |
S3DeploymentRootKey, | |
...otherParameters | |
} = stack.Parameters; | |
stack.Parameters = otherParameters; | |
return stack; | |
} | |
const folders = [`${outDir}`, `${outDir}/functions`, `${outDir}/pipelineFunctions`, `${outDir}/resolvers`, `${outDir}/stacks` ]; | |
for (const folder of folders) { | |
if (!fs.existsSync(folder)) { | |
fs.mkdirSync(folder, { recursive: true }); | |
} | |
} | |
for (const stackName in result.stacks) { | |
// @ts-ignore | |
const stack = cleanStack(JSON.parse(cloudform(result.stacks[stackName]))); | |
fs.writeFileSync(`${outDir}/stacks/${stackName}.yaml`, yaml.dump(stack)); | |
} | |
// @ts-ignore | |
const rootStack = cleanStack(JSON.parse(cloudform(result.rootStack))); | |
fs.writeFileSync(`${outDir}/stacks/template.yaml`, yaml.dump(rootStack)); | |
fs.writeFileSync(`${outDir}/stackMapping.yaml`, yaml.dump(result.stackMapping)); | |
for (const resolverName in result.resolvers) { | |
fs.writeFileSync( | |
`${outDir}/resolvers/${resolverName}`, | |
result.resolvers[resolverName] | |
); | |
} | |
for (const functionName in result.functions) { | |
fs.writeFileSync( | |
`${outDir}/functions/${functionName}`, | |
result.functions[functionName] | |
); | |
} | |
for (const pipelineFunctionName in result.pipelineFunctions) { | |
fs.writeFileSync( | |
`${outDir}/pipelineFunctions/${pipelineFunctionName}`, | |
result.pipelineFunctions[pipelineFunctionName] | |
); | |
} | |
fs.writeFileSync(`${outDir}/schema.graphql`, result.schema); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "snappyfeatures", | |
"version": "1.0.0", | |
"description": "Snappy Features", | |
"main": "index.js", | |
"scripts": { | |
"sam:package": "sam package --template template.yaml --output-template-file cloudformation.yaml --s3-bucket snappyfeatures-deploy --region us-west-2 --profile snappyfeatures", | |
"sam:deploy": "sam deploy --template-file cloudformation.yaml --stack-name snappyfeatures --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND --region us-west-2 --profile snappyfeatures", | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"author": "Richard Buggy <[email protected]> (http://www.goingserverless.com/)", | |
"license": "UNLICENSED", | |
"dependencies": { | |
"@types/node": "^12.7.5", | |
"cloudform": "^4.1.0", | |
"graphql-auth-transformer": "^5.8.0", | |
"graphql-connection-transformer": "^3.19.0", | |
"graphql-dynamodb-transformer": "^5.8.0", | |
"graphql-elasticsearch-transformer": "^3.20.0", | |
"graphql-function-transformer": "^1.15.0", | |
"graphql-http-transformer": "^3.18.0", | |
"graphql-key-transformer": "^1.15.0", | |
"graphql-transformer-core": "^5.8.0", | |
"graphql-versioned-transformer": "^3.18.0", | |
"js-yaml": "^3.13.1", | |
"rimraf": "^3.0.0" | |
}, | |
"devDependencies": { | |
"@types/rimraf": "^2.0.2" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment