github.com/mweagle/Sparta@v1.15.0/docs_source/content/reference/apigateway/context.md (about)

     1  ---
     2  date: 2016-03-09T19:56:50+01:00
     3  title: Request Context
     4  weight: 12
     5  ---
     6  
     7  This example demonstrates how to use the `Context` struct provided as part of the [APIGatewayRequest](https://godoc.org/github.com/mweagle/Sparta/aws/events#APIGatewayRequest).  The [SpartaGeoIP](https://github.com/mweagle/SpartaGeoIP) service will return Geo information based on the inbound request's IP address.
     8  
     9  ## Lambda Definition
    10  
    11  Our function will examine the inbound request, lookup the user's IP address in the [GeoLite2 Database](http://dev.maxmind.com/geoip/geoip2/geolite2/) and return any information to the client.
    12  
    13  As this function is only expected to be invoked from the API Gateway, we'll unmarshall the inbound event:
    14  
    15  ```go
    16  import (
    17    spartaAWSEvents "github.com/mweagle/Sparta/aws/events"
    18    spartaAPIGateway "github.com/mweagle/Sparta/aws/apigateway"
    19  )
    20  func ipGeoLambda(ctx context.Context,
    21    apiRequest spartaAWSEvents.APIGatewayRequest) (*spartaAPIGateway.Response, error) {
    22    parsedIP := net.ParseIP(apiRequest.Context.Identity.SourceIP)
    23    record, err := dbHandle.City(parsedIP)
    24    if err != nil {
    25      return nil, err
    26    }
    27  
    28  ```
    29  
    30  We'll then parse the inbound IP address from the [Context](https://godoc.org/github.com/mweagle/Sparta#APIGatewayContext) and perform a lookup against the database handle opened in the [init](https://github.com/mweagle/SpartaGeoIP/blob/master/main.go#L19) block:
    31  
    32  ```go
    33    parsedIP := net.ParseIP(lambdaEvent.Context.Identity.SourceIP)
    34    record, err := dbHandle.City(parsedIP)
    35    if err != nil {
    36      return nil, err
    37    }
    38  ```
    39  
    40  Finally, marshal the data or error result and we're done:
    41  
    42  ```go
    43    requestResponse := map[string]interface{}{
    44      "ip":     parsedIP,
    45      "record": record,
    46    }
    47    return spartaAPIGateway.NewResponse(http.StatusOK, requestResponse), nil
    48  ```
    49  
    50  ## Sparta Integration
    51  
    52  The next steps are to:
    53  
    54    1. Create the [LambdaAWSInfo](https://godoc.org/github.com/mweagle/Sparta#LambdaAWSInfo) value
    55    1. Create an associated API Gateway
    56    1. Create an API Gateway resource that invokes our lambda function
    57    1. Add a Method name to the resource.
    58  
    59  These four steps are managed in the service's `main()` function:
    60  
    61  ```go
    62  ////////////////////////////////////////////////////////////////////////////////
    63  // Main
    64  func main() {
    65    stage := sparta.NewStage("ipgeo")
    66    apiGateway := sparta.NewAPIGateway("SpartaGeoIPService", stage)
    67    stackName := "SpartaGeoIP"
    68  
    69    var lambdaFunctions []*sparta.LambdaAWSInfo
    70    lambdaFn, _ := sparta.NewAWSLambda(sparta.LambdaName(ipGeoLambda),
    71      ipGeoLambda,
    72      sparta.IAMRoleDefinition{})
    73    apiGatewayResource, _ := apiGateway.NewResource("/info", lambdaFn)
    74    apiMethod, _ := apiGatewayResource.NewMethod("GET", http.StatusOK, http.StatusOK)
    75    apiMethod.SupportedRequestContentTypes = []string{"application/json"}
    76  
    77    lambdaFunctions = append(lambdaFunctions, lambdaFn)
    78  
    79    sparta.Main(stackName,
    80      "Sparta app supporting ip->geo mapping",
    81      lambdaFunctions,
    82      apiGateway,
    83      nil)
    84  }
    85  ```
    86  
    87  ## Provision
    88  
    89  The next step is to provision the stack:
    90  
    91  ```nohighlight
    92  S3_BUCKET=<MY-S3-BUCKETNAME> mage provision
    93  ```
    94  
    95  Assuming all goes well, the log output will include the API Gateway URL as in:
    96  
    97  ```text
    98  INFO[0077] Stack Outputs ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    99  INFO[0077]     APIGatewayURL                             Description="API Gateway URL" Value="https://52a5qqqwo4.execute-api.us-west-2.amazonaws.com/ipgeo"
   100  INFO[0077] Stack provisioned                             CreationTime="2018-12-11 14:30:01.822 +0000 UTC" StackId="arn:aws:cloudformation:us-west-2:123412341234:stack/SpartaGeoIP-mweagle/3e803cd0-fd51-11e8-9c7e-06972e890616" Stack
   101  ```
   102  
   103  ## Verify
   104  
   105  With the API Gateway provisioned, let's check the response:
   106  
   107  ```bash
   108  $ curl -vs https://52a5qqqwo4.execute-api.us-west-2.amazonaws.com/ipgeo/info
   109  *   Trying 13.32.254.81...
   110  * TCP_NODELAY set
   111  * Connected to 52a5qqqwo4.execute-api.us-west-2.amazonaws.com (13.32.254.81) port 443 (#0)
   112  * ALPN, offering h2
   113  * ALPN, offering http/1.1
   114  * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
   115  * successfully set certificate verify locations:
   116  *   CAfile: /etc/ssl/cert.pem
   117    CApath: none
   118  * TLSv1.2 (OUT), TLS handshake, Client hello (1):
   119  * TLSv1.2 (IN), TLS handshake, Server hello (2):
   120  * TLSv1.2 (IN), TLS handshake, Certificate (11):
   121  * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
   122  * TLSv1.2 (IN), TLS handshake, Server finished (14):
   123  * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
   124  * TLSv1.2 (OUT), TLS change cipher, Client hello (1):
   125  * TLSv1.2 (OUT), TLS handshake, Finished (20):
   126  * TLSv1.2 (IN), TLS change cipher, Client hello (1):
   127  * TLSv1.2 (IN), TLS handshake, Finished (20):
   128  * SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
   129  * ALPN, server accepted to use h2
   130  * Server certificate:
   131  *  subject: CN=*.execute-api.us-west-2.amazonaws.com
   132  *  start date: Oct  9 00:00:00 2018 GMT
   133  *  expire date: Oct  9 12:00:00 2019 GMT
   134  *  subjectAltName: host "52a5qqqwo4.execute-api.us-west-2.amazonaws.com" matched cert's "*.execute-api.us-west-2.amazonaws.com"
   135  *  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
   136  *  SSL certificate verify ok.
   137  * Using HTTP2, server supports multi-use
   138  * Connection state changed (HTTP/2 confirmed)
   139  * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
   140  * Using Stream ID: 1 (easy handle 0x7f8522804200)
   141  > GET /ipgeo/info HTTP/2
   142  > Host: 52a5qqqwo4.execute-api.us-west-2.amazonaws.com
   143  > User-Agent: curl/7.54.0
   144  > Accept: */*
   145  >
   146  * Connection state changed (MAX_CONCURRENT_STREAMS updated)!
   147  < HTTP/2 200
   148  < content-type: application/json
   149  < content-length: 1103
   150  < date: Tue, 11 Dec 2018 14:32:00 GMT
   151  < x-amzn-requestid: 851627ca-fd51-11e8-ba5d-9f30493b4ce1
   152  < x-amz-apigw-id: RvyPBHuuPHcFx4w=
   153  < x-amzn-trace-id: Root=1-5c0fca60-2eecbee8bad756981052608c;Sampled=0
   154  < x-cache: Miss from cloudfront
   155  < via: 1.1 400e19a7f70282e0817451f6606ca8f9.cloudfront.net (CloudFront)
   156  < x-amz-cf-id: l4gOpUjDylhS0yHwBWpMneD4BqLBv3zkWcjv6I0j2vBoQu6qD4gKyw==
   157  <
   158  {"ip":"127.0.0.1","record":{"City":{"GeoNameID":0,"Names":null},"Continent":{"Code":"NA","GeoNameID":6255149,"Names":{"de":"Nordamerika","en":"North America","es":"Norteamérica","fr":"Amérique du Nord","ja":"北アメリカ","pt-BR":"América do Norte","ru":"Северная Америка","zh-CN":"北美洲"}},"Country":{"GeoNameID":6252001,"IsInEuropeanUnion":false,"IsoCode":"US","Names":{"de":"USA","en":"United States","es":"Estados Unidos","fr":"États-Unis","ja":"アメリカ合衆国","pt-BR":"Estados Unidos","ru":"США","zh-CN":"美国"}},"Location":{"AccuracyRadius":0,"Latitude":0,"Longitude":0,"MetroCode":0,"TimeZone":""},"Postal":{"Code":""},"RegisteredCountry":{"GeoNameID":6252001,"IsInEuropeanUnion":false,"IsoCode":"US","Names":{"de":"USA","en":"United States","es":"Estados Unidos","fr":"États-Unis","ja":"アメリカ合衆国","pt-BR":"Estados Unidos","ru":"США","zh-CN":"美国"}},"RepresentedCountry":{"GeoNameID":0,"IsInEuropeanUnion":false,"IsoCode":"","Names":null,"Type":""},"Subdivisions":null,"Traits":{"IsAnonymousProxy":false,"IsSatelliteProvider":false}}}
   159  
   160  ```
   161  
   162  Pretty-printing the response body:
   163  
   164  ```json
   165  {
   166      "ip": "127.0.0.1",
   167      "record": {
   168          "City": {
   169              "GeoNameID": 0,
   170              "Names": null
   171          },
   172          "Continent": {
   173              "Code": "NA",
   174              "GeoNameID": 6255149,
   175              "Names": {
   176                  "de": "Nordamerika",
   177                  "en": "North America",
   178                  "es": "Norteamérica",
   179                  "fr": "Amérique du Nord",
   180                  "ja": "北アメリカ",
   181                  "pt-BR": "América do Norte",
   182                  "ru": "Северная Америка",
   183                  "zh-CN": "北美洲"
   184              }
   185          },
   186          "Country": {
   187              "GeoNameID": 6252001,
   188              "IsInEuropeanUnion": false,
   189              "IsoCode": "US",
   190              "Names": {
   191                  "de": "USA",
   192                  "en": "United States",
   193                  "es": "Estados Unidos",
   194                  "fr": "États-Unis",
   195                  "ja": "アメリカ合衆国",
   196                  "pt-BR": "Estados Unidos",
   197                  "ru": "США",
   198                  "zh-CN": "美国"
   199              }
   200          },
   201          "Location": {
   202              "AccuracyRadius": 0,
   203              "Latitude": 0,
   204              "Longitude": 0,
   205              "MetroCode": 0,
   206              "TimeZone": ""
   207          },
   208          "Postal": {
   209              "Code": ""
   210          },
   211          "RegisteredCountry": {
   212              "GeoNameID": 6252001,
   213              "IsInEuropeanUnion": false,
   214              "IsoCode": "US",
   215              "Names": {
   216                  "de": "USA",
   217                  "en": "United States",
   218                  "es": "Estados Unidos",
   219                  "fr": "États-Unis",
   220                  "ja": "アメリカ合衆国",
   221                  "pt-BR": "Estados Unidos",
   222                  "ru": "США",
   223                  "zh-CN": "美国"
   224              }
   225          },
   226          "RepresentedCountry": {
   227              "GeoNameID": 0,
   228              "IsInEuropeanUnion": false,
   229              "IsoCode": "",
   230              "Names": null,
   231              "Type": ""
   232          },
   233          "Subdivisions": null,
   234          "Traits": {
   235              "IsAnonymousProxy": false,
   236              "IsSatelliteProvider": false
   237          }
   238      }
   239  }
   240  ```
   241  
   242  ## Clean Up
   243  
   244  Before moving on, remember to decommission the service via `go run main.go delete` or `mage delete`.
   245  
   246  ## Notes
   247  
   248  * The _GeoLite2-Country.mmdb_ content is embedded in the go binary via [esc](https://github.com/mjibson/esc) as part of the [go generate](https://github.com/mweagle/SpartaGeoIP/blob/master/main.go#L27) phase.
   249    * This is a port of Tom Maiaroto's [go-lambda-geoip](https://github.com/tmaiaroto/go-lambda-geoip) implementation.