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.