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.