krakend api gateway panic: "X in new path conflicts with existing wildcard Y in existing prefix Z" - api-gateway

I have two webservices, and I'd like to manage both endpoints separated by the prefix using krakend API gateway.
Below is my configuration:
{
"version": 2,
"name": "My API Gateway",
"port": 8080,
"host": [],
"endpoints": [
{
"endpoint": "/api/entity/{entityID}",
"output_encoding": "no-op",
"method": "POST",
"backend": [
{
"url_pattern": "/api/entity/{entityID}",
"encoding": "no-op",
"host": [
"http://987.654.32.1"
]
}
]
},
{
"endpoint": "/api/entity/member/assign/{userID}",
"output_encoding": "no-op",
"method": "GET",
"backend": [
{
"url_pattern": "/api/entity/member/assign/{userID}",
"encoding": "no-op",
"host": [
"http://123.456.789.0"
]
}
]
}
]
}
when I run it, error occurs:
panic: 'member' in new path '/api/entity/member/assign/:userID' conflicts with existing wildcard ':entityID' in existing prefix '/api/entity/:entityID'
As far as I understand, it seems the {entityID} on the first endpoint is conflicting with /member/ in the second endpoint. Is this error expected behaviour or is there any problem with my configuration file?

This is a known limitation of the Gin library that KrakenD uses internally, you can reproduce this behavior directly in the library with this go code, which will reproduce exactly the same issue:
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.New()
r.GET("/ping", handler)
r.GET("/ping/foo", handler)
r.GET("/ping/:a", handler)
r.GET("/ping/:a/bar", handler)
}
func handler(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
}
See the code in this issue.
The solution is to declare endpoint paths that are not colliding subsets of other endpoints. In your configuration the endpoint /api/entity/member/assign/{userID} is a subset of /api/entity/{entityID}.
Notice that {placeholders} are like using wildcards, so your first endpoint could be expressed in other systems like /api/entity/*, and therefore /api/entity/member/assign/{userID} is a positive match.
Any slight change in your configuration where the wildcard does not collide will fix this situation. As an example, the following two endpoints would work for you:
/api/entity/find/{entityID}
/api/entity/member/assign/{userID}

Thanks to #alo on explaining this issue.
I have come across same one, as i have krakend endpoints in following manner:
GET: /v1/projects/{project_uuid}
GET: /v1/projects/{project_key}/portfolio
But surprisingly, by tricking krakenD like this worked fine.
GET: /v1/projects/{key} // In swagger docs mentioned this key to be supplied as uuid
GET: /v1/projects/{key}/portfolio // In swagger docs mentioned this key to be supplied as string
For now this endpoints triggering my backend client as expected. hopefully this annoying thing gets fixed.

Related

CORS error with AWS api gateway and java lambda function

Today I created one api gateway on aws and one java lambda function. Then finally integrated api gateway with lambda function.
So when I hit the api using postman then it returns the result which is basically a list of customer. Till now everything looks fine. Following is the
#Override
public TestResponse handleRequest(Request input, Context context) {
TestService testService = SingletonServiceManager.getInstance().getTestService();
TestListResponse response = (TestListResponse)productListService.executeRequest(input);
return response;
}
After executing it returns following output.
{
"status": 200,
"products": [
{
"name": "test1",
"code": "test1",
"status": true
},
{
"name": "test2",
"code": "test2",
"status": true
}
]
}
but when I started integrating this with api call with Angular from local machine it start throwing CORS issue. Angular client using it CORS setting to connect.
Can someone help me on this. Do I need to enable something special from lambda function.
You need to enable CORS in your API Gateway configuration.

Wiremock Standalone with Dynamic response

I have a standalone instance of Wiremock server. The mappings are stored as json files under the mappings folder. I have a POST request that needs to return a dynamic ID(integer) in the response. Is there a way to configure this in the json file?
To make the above examples work, I had to run the standalone jar with the --global-response-templating. Then I saw, for example, {{now}} working which is what I wanted. Not sure if the documentation specifies this -- I tried the always-useful --help.
In WireMock there are a number of response template helper functions for generating random strings. In the below example I'm using the one for generating a UUID, but several other options exist.
Mapping file: dynamic_id.json
{
"request": {
"method": "POST",
"url": "/dynamic_id"
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 200,
"body": "{{randomValue type='UUID'}}",
"transformers": ["response-template"]
}
}
Using an empty POST http://wiremock/dynamic_id will return an id similar to: c2e6bf32-c9a3-45c0-b988-94fad04cc7a2.
Start WireMock:
java -jar wiremock-standalone-2.18.0.jar --port 8181 --verbose --local-response-templating
This seems like a perfect use-case for OpenTable's Wiremock Body Transformer.
It can be easily integrated with the Standalone Server like this:
java -cp "wiremock-body-transformer-1.1.6.jar:wiremock-2.3.1-standalone.jar" com.github.tomakehurst.wiremock.standalone.WireMockServerRunner --verbose --extensions com.opentable.extension.BodyTransformer
And allows you to easily specify a dynamic variable that you would want to match in the response.
Here is an example to get a random integer without having to specify anything in the request, however if you need to match a specific variable in the request to the response, then that is also very doable with this extension and numerous examples can be found in the readme.
{
"request": {
"method": "POST",
"urlPath": "/transform",
},
"response": {
"status": 200,
"body": "{\"randomInteger\": \"$(!RandomInteger)\"}",
"headers": {
"Content-Type": "application/json"
},
"transformers": ["body-transformer"]
}
}
As #Jeff mentions, If you are running it as a stand-alone process, you need to add this flag --global-response-templating. This will apply templating to each and every reponse. However, few of your responses may be jsut plain json with no templating required.
In that case use --local-response-templating. and add this field inside reponse json:
response:{
"transformers": ["response-template"]
}

Duplicated mapping key in serverless.yml

I'm using Serverless to deploy a couple of functions written in C# to AWS.
While deploying a message duplicated mapping key in "...\serverless.yml" is thrown.
Separately, both functions get deployed but when put together the said error message is shown.
What am I missing?
{
"service": "serverlessquick",
"provider": {
"name": "aws",
"runtime": "nodejs4.3"
},
"functions": {
"hello": {
"handler": "handler.hello",
"events": [
{
"http": {
"path": "hello",
"method": "get"
}
}
]
}
}
}
Make your yaml code into json this way any mistakes are obvious, and will be more likely to be picked up by the parser. If anyone comes across this, use the referenced config above.
I got a similar error but in my case it was indentation problem. Go through your YML file and see if the changes you have made have the correct identation. A json parser as mention by others can help narrow down where in the YML file the problem exists

Amazon Alexa Device Discovery for Smart Home API with Lambda Failing

I have setup an Alexa Smart Home Skill, all settings done, oauth2 processed done and skill is enabled on my Amazon Echo device. Lambda function is setup and linked to the skill. When I "Discover Devices" I can see the payload hit my Lambda function in the log. I am literally returning via the context.succeed() method the following JSON with a test appliance. However Echo tells me that it fails to find any devices.
{
"header": {
"messageId": "42e0bf9c-18e2-424f-bb11-f8a12df1a79e",
"name": "DiscoverAppliancesResponse",
"namespace": "Alexa.ConnectedHome.Discovery",
"payloadVersion": "2"
},
"payload": {
"discoveredAppliances": [
{
"actions": [
"incrementPercentage",
"decrementPercentage",
"setPercentage",
"turnOn",
"turnOff"
],
"applianceId": "0d6884ab-030e-8ff4-ffffaa15c06e0453",
"friendlyDescription": "Study Light connected to Loxone Kit",
"friendlyName": "Study Light",
"isReachable": true,
"manufacturerName": "Loxone",
"modelName": "Spot"
}
]
}
}
Does the above payload look correct?
According to https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/smart-home-skill-api-reference#discovery-messages the version attribute is required. Your response seems to be missing that attribute.
In my (very short) experience with this, even the smallest mistake in the response would generate a silent error like the one you are experiencing.
I had the same problem. If you are creating discovery for "Entertainment Device", make sure you have wrapped the output in 'event' key for context.succeed
var payload = {
endpoints:
[
{
"endpointId": "My-id",
"manufacturerName": "Manufacturer",
"friendlyName": "Living room TV",
"description": "65in LED TV from Demo AV Company",
"displayCategories": [ ],
"cookie": {
"data": "e.g. ip address",
},
"capabilities":
[
{
"interface": "Alexa.Speaker",
"version": "1.0",
"type": "AlexaInterface"
},
]
}
]
};
var header = request.directive.header;
header.name = "Discover.Response";
context.succeed({ event: {
header: header, payload: payload
} });
Although, in the sample code, this is never mentioned and an incorrect example is given (https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/steps-to-create-a-smart-home-skill). However, the response body provided includes the "event" key.
Recreating lambda function helped me fix the issue. I also set "Enable trigger" check button while creating, though I'm not sure if that matters. After that my device provided by skill was found successfully.
Edit: Answer was wrong. Only useful information was this
This context.fail syntax is actually deprecated. Look up the Lambda context object properties, it should look more like "callback(null, resultObj)" now.
Did you include the return statement in your function?
return {
"header": header,
"payload": payload
}
It was missing in the example and after adding it, I was able to 'discover' my device.

Can't define Network when creating Instance Group with Go client library?

When creating an unmanaged instance group through GCP Console, I can see the REST request as:
POST https://www.googleapis.com/compute/v1/projects/my-project/zones/us-east1-d/instanceGroups
{
"name": "ig-web",
"network": "https://www.googleapis.com/compute/v1/projects/my-project/global/networks/nomad-network",
"namedPorts": [
{
"name": "http",
"port": 11080
}
]
}
However, according to the API docs and client library generated code, one has no way to set the network URL.
Anyone care to clarify?
It's actually a documentation bug. The following will work:
op, err := gce.service.InstanceGroups.Insert(projectID, zone, &compute.InstanceGroup{
Name: name,
NamedPorts: namedPorts,
Network: networkURL}).Do()

Resources