github.com/mweagle/Sparta@v1.15.0/docs_source/content/reference/apigateway/s3Site.md (about) 1 --- 2 date: 2016-03-09T19:56:50+01:00 3 title: S3 Sites with CORS 4 weight: 150 5 --- 6 7 Sparta supports provisioning an S3-backed [static website](http://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html) as part of provisioning. We'll walk through provisioning a minimal [Bootstrap](http://getbootstrap.com) website that accesses API Gateway lambda functions provisioned by a single service in this example. 8 9 The source for this is the [SpartaHTML](https://github.com/mweagle/SpartaHTML) example application. 10 11 ## Lambda Definition 12 13 We'll start by creating a very simple lambda function: 14 15 ```go 16 import ( 17 spartaAPIGateway "github.com/mweagle/Sparta/aws/apigateway" 18 spartaAWSEvents "github.com/mweagle/Sparta/aws/events" 19 ) 20 type helloWorldResponse struct { 21 Message string 22 Request spartaAWSEvents.APIGatewayRequest 23 } 24 25 //////////////////////////////////////////////////////////////////////////////// 26 // Hello world event handler 27 func helloWorld(ctx context.Context, 28 gatewayEvent spartaAWSEvents.APIGatewayRequest) (*spartaAPIGateway.Response, error) { 29 logger, loggerOk := ctx.Value(sparta.ContextKeyLogger).(*logrus.Logger) 30 if loggerOk { 31 logger.Info("Hello world structured log message") 32 } 33 // Return a message, together with the incoming input... 34 return spartaAPIGateway.NewResponse(http.StatusOK, &helloWorldResponse{ 35 Message: fmt.Sprintf("Hello world 🌏"), 36 Request: gatewayEvent, 37 }), nil 38 } 39 ``` 40 41 This lambda function returns a reply that consists of the inbound 42 request plus a sample message. See the API Gateway [examples](/reference/apigateway) 43 for more information. 44 45 ## API Gateway 46 47 The next step is to create an API Gateway instance and Stage, so that the API will be publicly available. 48 49 ```go 50 apiStage := sparta.NewStage("v1") 51 apiGateway := sparta.NewAPIGateway("SpartaHTML", apiStage) 52 ``` 53 54 Since we want to be able to access this API from another domain (the one provisioned by the S3 bucket), we'll need to [enable CORS](http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html) as well: 55 56 ```go 57 // Enable CORS s.t. the S3 site can access the resources 58 apiGateway.CORSEnabled = true 59 ``` 60 61 Finally, we register the `helloWorld` lambda function with an API Gateway resource: 62 63 ```go 64 65 func spartaLambdaFunctions(api *sparta.API) []*sparta.LambdaAWSInfo { 66 var lambdaFunctions []*sparta.LambdaAWSInfo 67 lambdaFn, _ := sparta.NewAWSLambda(sparta.LambdaName(helloWorld), 68 helloWorld, 69 sparta.IAMRoleDefinition{}) 70 71 if nil != api { 72 apiGatewayResource, _ := api.NewResource("/hello", lambdaFn) 73 _, err := apiGatewayResource.NewMethod("GET", http.StatusOK) 74 if nil != err { 75 panic("Failed to create /hello resource") 76 } 77 } 78 return append(lambdaFunctions, lambdaFn) 79 } 80 ``` 81 82 83 ## S3 Site 84 85 The next part is to define the S3 site resources via `sparta.NewS3Site(localFilePath)`. The _localFilePath_ parameter 86 typically points to a directory, which will be: 87 88 1. Recursively ZIP'd 89 1. Posted to S3 alongside the Lambda code archive and CloudFormation Templates 90 1. Dynamically unpacked by a CloudFormation CustomResource during `provision` to a new S3 bucket. 91 92 ## Provision 93 94 Putting it all together, our `main()` function looks like: 95 96 ```go 97 98 //////////////////////////////////////////////////////////////////////////////// 99 // Main 100 func main() { 101 // Register the function with the API Gateway 102 apiStage := sparta.NewStage("v1") 103 apiGateway := sparta.NewAPIGateway("SpartaHTML", apiStage) 104 // Enable CORS s.t. the S3 site can access the resources 105 apiGateway.CORSEnabled = true 106 107 // Provision a new S3 bucket with the resources in the supplied subdirectory 108 s3Site, _ := sparta.NewS3Site("./resources") 109 110 // Deploy it 111 sparta.Main("SpartaHTML", 112 fmt.Sprintf("Sparta app that provisions a CORS-enabled API Gateway together with an S3 site"), 113 spartaLambdaFunctions(apiGateway), 114 apiGateway, 115 s3Site) 116 } 117 ``` 118 119 which can be provisioned using the standard [command line](/reference/commandline) option. 120 121 The _Outputs_ section of the `provision` command includes the hostname of our new S3 site: 122 123 ```nohighlight 124 INFO[0092] ──────────────────────────────────────────────── 125 INFO[0092] Stack Outputs 126 INFO[0092] ──────────────────────────────────────────────── 127 INFO[0092] S3SiteURL Description="S3 Website URL" Value="http://spartahtml-mweagle-s3site89c05c24a06599753eb3ae4e-9kil6qlqk0yt.s3-website-us-west-2.amazonaws.com" 128 INFO[0092] APIGatewayURL Description="API Gateway URL" Value="https://ksuo0qlc3m.execute-api.us-west-2.amazonaws.com/v1" 129 INFO[0092] ──────────────────────────────────────────────── 130 ``` 131 132 Open your browser to the `S3SiteURL` value (eg: _http://spartahtml-mweagle-s3site89c05c24a06599753eb3ae4e-9kil6qlqk0yt.s3-website-us-west-2.amazonaws.com_) and view the deployed site. 133 134 ## Discover 135 136 An open issue is how to communicate the dynamically assigned API Gateway hostname to the dynamically provisioned S3 site. 137 138 As part of expanding the ZIP archive to a target S3 bucket, Sparta also creates a _MANIFEST.json_ discovery file with discovery information. If your application has provisioned an APIGateway this JSON file will include that dynamically assigned URL as in: 139 140 1. **MANIFEST.json** 141 142 ```json 143 { 144 "APIGatewayURL": { 145 "Description": "API Gateway URL", 146 "Value": "https://ksuo0qlc3m.execute-api.us-west-2.amazonaws.com/v1" 147 } 148 } 149 ``` 150 151 ### Notes 152 153 * See the [Medium](https://read.acloud.guru/go-aws-lambda-building-an-html-website-with-api-gateway-and-lambda-for-go-using-sparta-5e6fe79f63ef) post for an additional walk through this sample.