Sparta supports provisioning an S3-backed static website as part of provisioning. We’ll walk through provisioning a minimal Bootstrap website that accesses API Gateway lambda functions provisioned by a single service in this example.
The source for this is the SpartaHTML example application.
We’ll start by creating a very simple lambda function:
import (
spartaAPIGateway "github.com/mweagle/Sparta/v3/aws/apigateway"
spartaAWSEvents "github.com/mweagle/Sparta/v3/aws/events"
)
type helloWorldResponse struct {
Message string
Request spartaAWSEvents.APIGatewayRequest
}
////////////////////////////////////////////////////////////////////////////////
// Hello world event handler
func helloWorld(ctx context.Context,
gatewayEvent spartaAWSEvents.APIGatewayRequest) (*spartaAPIGateway.Response, error) {
logger, loggerOk := ctx.Value(sparta.ContextKeyLogger).(*zerolog.Logger)
if loggerOk {
logger.Info("Hello world structured log message")
}
// Return a message, together with the incoming input...
return spartaAPIGateway.NewResponse(http.StatusOK, &helloWorldResponse{
Message: fmt.Sprintf("Hello world 🌏"),
Request: gatewayEvent,
}), nil
}
This lambda function returns a reply that consists of the inbound request plus a sample message. See the API Gateway examples for more information.
The next step is to create an API Gateway instance and Stage, so that the API will be publicly available.
apiStage := sparta.NewStage("v1")
apiGateway := sparta.NewAPIGateway("SpartaHTML", apiStage)
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 as well:
// Enable CORS s.t. the S3 site can access the resources
apiGateway.CORSEnabled = true
Finally, we register the helloWorld
lambda function with an API Gateway resource:
func spartaLambdaFunctions(api *sparta.API) []*sparta.LambdaAWSInfo {
var lambdaFunctions []*sparta.LambdaAWSInfo
lambdaFn, _ := sparta.NewAWSLambda(sparta.LambdaName(helloWorld),
helloWorld,
sparta.IAMRoleDefinition{})
if nil != api {
apiGatewayResource, _ := api.NewResource("/hello", lambdaFn)
_, err := apiGatewayResource.NewMethod("GET", http.StatusOK)
if nil != err {
panic("Failed to create /hello resource")
}
}
return append(lambdaFunctions, lambdaFn)
}
The next part is to define the S3 site resources via sparta.NewS3Site(localFilePath)
. The localFilePath parameter
typically points to a directory, which will be:
provision
to a new S3 bucket.Putting it all together, our main()
function looks like:
////////////////////////////////////////////////////////////////////////////////
// Main
func main() {
// Register the function with the API Gateway
apiStage := sparta.NewStage("v1")
apiGateway := sparta.NewAPIGateway("SpartaHTML", apiStage)
// Enable CORS s.t. the S3 site can access the resources
apiGateway.CORSEnabled = true
// Provision a new S3 bucket with the resources in the supplied subdirectory
s3Site, _ := sparta.NewS3Site("./resources")
// Deploy it
sparta.Main("SpartaHTML",
fmt.Sprintf("Sparta app that provisions a CORS-enabled API Gateway together with an S3 site"),
spartaLambdaFunctions(apiGateway),
apiGateway,
s3Site)
}
which can be provisioned using the standard command line option.
The Outputs section of the provision
command includes the hostname of our new S3 site:
INFO[0092] ────────────────────────────────────────────────
INFO[0092] Stack Outputs
INFO[0092] ────────────────────────────────────────────────
INFO[0092] S3SiteURL Description="S3 Website URL" Value="http://spartahtml-mweagle-s3site89c05c24a06599753eb3ae4e-9kil6qlqk0yt.s3-website-us-west-2.amazonaws.com"
INFO[0092] APIGatewayURL Description="API Gateway URL" Value="https://ksuo0qlc3m.execute-api.us-west-2.amazonaws.com/v1"
INFO[0092] ────────────────────────────────────────────────
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.
An open issue is how to communicate the dynamically assigned API Gateway hostname to the dynamically provisioned S3 site.
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:
{
"APIGatewayURL": {
"Description": "API Gateway URL",
"Value": "https://ksuo0qlc3m.execute-api.us-west-2.amazonaws.com/v1"
}
}