AWS API Gateway - Parameter mapping path with HTTP API (overwrite:path) - amazon-web-services

I started looking into using AWS HTTP API as a single point of entry to some micro services running with ECS.
One micro service has the following route internally on the server:
/sessions/{session_id}/topics
I define exactly the same route in my HTTP API and use CloudMap and a VPC Link to reach my ECS cluster. So far so good, the requests can reach the servers. The path is however not the same when it arrives. As per AWS documentation [1] it will prepend the stage name so that the request looks the following when it arrives:
/{stage_name}/sessions/{session_id}/topics
So I started to look into Parameter mappings so that I can change the path for the integration, but I cannot get it to work.
For requestParameters I want overwrite the path like below, but for some reason the original path with the stage variable is still there. If I just define overwrite:path as $request.path.sessionId I get only the ID as the path or if I write whatever string I want it will arrive as I define it. But when I mix the $request.path.sessionId and the other parts of the string it does not seem to work.
How do I format this correctly?
paths:
/sessions/{sessionId}/topics:
post:
responses:
default:
description: "Default response for POST /sessions/{sessionId}/topics"
x-amazon-apigateway-integration:
requestParameters:
overwrite:path: "/sessions/$request.path.sessionId/topics"
payloadFormatVersion: "1.0"
connectionId: (removed)
type: "http_proxy"
httpMethod: "POST"
uri: (removed)
connectionType: "VPC_LINK"
timeoutInMillis: 30000
[1] https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-private.html

You can try to use parentheses. Formal notation instead of shorthand notation.
overwrite:path: "/sessions/${request.path.sessionId}/topics"
It worked well for me for complex mappings.
mapping template is a script expressed in Velocity Template Language (VTL)

dont remove the uri and the connectionId and it will work for you.
add only requestParameters:
overwrite:path: "/sessions/$request.path.sessionId/topics"

Related

AWSa APIGatewayV2HTTPRequest does not contain RequestContext

I'm trying to setup an API Gateway that forwards requests to a Lambda function. Precisely I struggle to setup CORS properly. When handling the request in my Lambda function the incoming event does not have the RequestContext information set. Hence I don't know when I handle an OPTIONS request.
My debug code: in is the APIGatewayV2HTTPRequest
log.Printf("type: %s", reflect.TypeOf(in))
log.Printf("req: %+v", in)
Output:
type: events.APIGatewayV2HTTPRequest
...
RequestContext:{
RouteKey:
AccountID:xxx
Stage:default
RequestID:dB7h2jEcFiAEMkA=
Authorizer:<nil>
APIID:xxx
DomainName:xxx
DomainPrefix:xxx
Time:
TimeEpoch:0
HTTP:
{Method: Path: Protocol: SourceIP: UserAgent:}
It seems RequestContext.HTTP is not set and I have no idea why.
I had to set the api gateway payload version to v2. For some reason it was set to v1 and therefor the event was not properly populated.

Questions on configuring the YAML file

I'm trying to set up a yaml file for the Gateway API to post to a cloud function, but I don't know how to do that, I searched the internet and found some examples but when I created the gateway with the settings of my YAML file I get the following error:
I know the cause of the error is probably a YAML file indentation error, but I'm not able to resolve it.
My YAML file is configured as follows:
swagger: '2.0'
info:
title: gateway-homologation gateway for homologation of the project cycle
description: "Send a deal object for the data to be treated"
version: "1.0.0"
schemes:
- https
produces:
- application/json
paths:
/dispatcher:
post:
x-google-backend:
address: https://url
description: "Jailson esteve aqui =)"
operationId: "dispatcher"
parameters:
type: object
properties:
request_type:
type: string
deal:
name:
type: string
responses:
200:
description: "#OK"
schema:
type: string
400:
description: "#OPS"
Another question is how can I configure what my gateway will send to my cloud function?
" -The error message is quite clear that at /paths/~1dispatcher/post/parameters, an array is expected but an object is given. This is not a YAML error, but a schema error – you have to give the structure defined by the schema. Making the value of parameters an array will overcome that error, but I do not know enough about Swagger to be confident that this is the only error in your code.
-I understood what you said but I'm not able to do this. How would I turn the object into an array in practice?
The docs Describing Parameters have some examples; - starts a sequence item; sequence items make up a YAML sequence and in JavaScript context will be loaded as an array.
#flyx

GCP url-map with cookie regex matching rule

I am setting up a GCP url map to route requests to backend services based on cookie values. Since cookies would have multiple key values, I am trying to use a regex matcher.
I need to route requests to backends based on region value from cookie.
A typical cookie would look like this: foo=bar;region=eu;variant=beta;
defaultService: https://www.googleapis.com/compute/v1/projects/<project_id>/global/backendServices/multi-region-1
kind: compute#urlMap
name: regex-url-map
hostRules:
- hosts:
- '*'
pathMatcher: path-matcher-1
pathMatchers:
- defaultService: https://www.googleapis.com/compute/v1/projects/<project_id>/global/backendServices/multi-region-1
name: path-matcher-1
routeRules:
- matchRules:
- prefixMatch: /
headerMatches:
- headerName: Cookie
regexMatch: (region=us)
priority: 0
service: https://www.googleapis.com/compute/v1/projects/<project_id>/global/backendServices/multi-region-1
- matchRules:
- prefixMatch: /
headerMatches:
- headerName: Cookie
regexMatch: (region=eu)
priority: 1
service: https://www.googleapis.com/compute/v1/projects/<project_id>/global/backendServices/multi-region-2
However, this url-map fails validation with this error:
$ gcloud compute url-maps validate --source regex-url-map.yaml
result:
loadErrors:
- HttpHeaderMatch has no predicates specified
loadSucceeded: false
testPassed: false
Please note that an exact match with cookie passes validation and matches correctly if cookie value is just something like this: region=us. The headerMatches section for exact match would look like this:
headerMatches:
- headerName: Cookie
exactMatch: region=us
Any pointers on what am I doing wrong here?
Thanks!
Your way of reasoning is correct but the feature you're trying to use is unsupported in external load balancing in GCP; it works only with internal load balancing.
Look at the last phrase from the documentation:
Note that regexMatch only applies to Loadbalancers that have their loadBalancingScheme set to INTERNAL_SELF_MANAGED.
I know it isn't the answer you're looking for but you can always file a new feature request on Google's IssueTracker and explain in detail what you want, how it could work etc.
You can always try to pass the region value in the http request - instead of requesting https://myhost.com all the time - also if you could add a suffix, for example: https://myhost.com/region1 it would allow the GCP load balancer rules to process it and direct the traffic to the backend you wish.
Have a look at this example what you can and can't do with forwarding rules in GCP. Another example here. And another one (mine) explaining how to use pathMatcher to direct traffic to different backend services.

How can I create a mapping template to map path parameter to lambda function in apigateway?

I am using serverless to deploy API gateway and lambda using lambda integration. Below is the infra code:
myLambda:
...
events:
- http:
path: customer/{id}
method: delete
integration: lambda
request:
parameters:
paths:
id: true
template:
text/plain: "$input.params('id')"
It creates a delete API to delete customer based on the id specified in the path parameter. I'd like to map the path id to myLambda's event parameter in its handler. But the above code doesn't work the lambda receives the whole http request from API gateway. How can I map the id parameter to the event parameter in lambda?
When you are using API Gateway and Lambda functions, you have 2 options:
Lambda proxy
Lambda integration
By default, the Serverless framework is using Lambda proxy. This way of connecting to a Lambda function is a lot quicker. It passes the whole HTTP request to a Lambda function and it lets you handle the request completely on the Lambda function side.
There is another way, as I mentioned, it's Lambda integration, without using Lambda proxy. If you want to use this method, you need to set up mappings on your request and your response. This way is "cleaner" on the LAmbda code side, because Lambda received mapped parameters in the event, compared to the whole HTTP request as in proxy. On the other hand, this kind of integration is more complicated to set up, as you need to make all the mappings, and it uses VTL (Apache Velocity Template Language) to do that.
In order to set this up using Serverless, take a look at the "Lambda Integration" section in Serverless framework API Gateway documentation:
I believe that ApiGateway event itself should contain that query / path parameter key value pair and you can directly query your parameters from the event, if you'd go with Lambda Proxy method which #Caldazar mentioned above.
For eg let's say if you have a URL
https://example.execute-api.us-west-2.amazonaws.com/prod/confirmReg?token=12345&uid=5
you could simply retrieve the values as below from your handler:
token = event['queryStringParameters']['token']
uid = event["queryStringParameters"]['uid']
EDIT:
Please follow the below steps for Lambda Integration:
Go to your respective API resource method and click on Integration Request section
Find the Mapping Templates area of the Integration request and open it up. Add a new mapping template for the application/json Content-Type. You'll need to change the type in the combo box from "Input passthrough" to "Mapping Template".
Then paste the following piece of JSON inside the template:
{
"id" : "$input.params('id')"
}
This way you'll not end up receiving the entire event object inside your lambda but only your path param which is sent in your request.
Some references: 1 & 2

Setting a custom call source header with Istio

I have a setup using Kubernetes and Istio where we run a set of services. Each of our services have an istio-sidecar and a REST-api. What we would like is that whenever a service within our setup calls another that the called service knows what service is the caller (Preferably through a header).
Looking at the example image from bookinfo:
bookinfo-image (Link due to <10 reputation)
This would mean that in the source code for the ratings service I would like to be able to, for example, read a header telling me the request came from e.g. Reviews-v2.
My intuition tells me that I should be able to handle this in the istio sidecars, but I fail to realise exactly how.
Until now I have looked at especially envoy filters in the hope that they could help me. I see that for the envoy filters I would be able to set a header, but what I don't see is how I would get the information about what service made the call in order to set it in the header.
Envoy automatically sets the X-Forwarded-Client-Cert header, which contains the SPIFFE ID of the caller. SPIFFE ID in Istio is a URI in the form spiffe://cluster.local/ns/<namespace>/sa/<service account>. Practically, it designates the Kubernetes Service Account of the caller. You may want to test it by using the Istio httpbin sample and sending a request to httpbin:8000/headers
I ended up finding another solution by using a "rule". If we made sure that policy enforcing is enabled and then added the rule:
apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
name: header-rule
namespace: istio-system
spec:
actions: []
requestHeaderOperations:
- name: serviceid
values:
- source.labels["app"]
operation: REPLACE
We achieved what we were attempting to do.