How to set up API gateway without specifying all resources - rest

I have some EC 2 applications (in node.js) that have many REST paths, and since still in development process, the path keep changing.
How can I set up in the api-gateway, that will map to multiple paths, instead of specify each of them?
e.g.
my ec2 end points have:
my.ec2.com/api/test
my.ec2.com/api/test1
my.ec2.com/api/test2
my.ec2.com/api/user/time
my.ec2.com/api/user/time1
my.ec2.com/api/user/time2
instead of setting the all resources in api-gateway,
can I do something like:
api-gateway.amazon.com/api that points to my.ec2.com/api/
and it will resolve any call to http://api-gateway.amazon.com/api/test automatically points to http://my.ec2.com/api/test, etc. ?

As of today, it is still impossible in the API gateway console.
The solution is to use Swagger. then I can use some scripts to generate the Swagger file and import to API gateway. In fact, it is a good solution because I can source control on Swagger.

Related

CDK BasePathMapping for existing custom domain is created but doesn't work

This is all done using CDK.
I created a REST API and custom domain associated with it via a base path mapping (domain.addBasePathMapping()). That worked fine.
Due to some requirement, I also need to redirect a particular path from another custom domain (I'll call this the old domain) to this api. In theory this should be straightforward - just create a base path mapping from the old domain to the new API.
This is how I tried doing it:
const domain = DomainName.fromDomainNameAttributes(this, 'oldDomain', {
domainName: 'the old custom domain name',
domainNameAliasTarget: 'the "API Gateway domain name" value from the console for that domain',
domainNameAliasHostedZoneId: 'the "Hosted zone ID" value from the console for that domain',
});
new BasePathMapping(this, 'myMapping', {
domainName: domain,
restApi: this.api,
basePath: 'foo',
});
First I created a DomainName object by looking up the old domain, then created a mapping to my new API with some path. Note that I cannot call addBasePathMapping() on the domain name created, as that method returns an IDomainName which doesn't have that method.
When I ran this, it created the base path mapping in the old custom domain, pointing to my new api, correct stage, specified path. Great!
Except it didn't work. Invoking [old domain]/foo/bar (where bar is the resource path in the new API) returned 404.
The strange thing is that when I create that mapping manually via the console, it works perfectly.
Another weird thing is that if I create it via CDK, and then edit it in the console, it starts working. If I then delete it (manually or via CDK) and then create it again via CDK, it continues to work. But of course this isn't a proper solution.
I can only assume that creating it manually performs some extra operation not done via the CDK construct, but as the docs don't say what else may need to be done, I have no idea what.
The solution is to use the CfnApiMapping construct from aws-cdk-lib/aws-apigatewayv2. In fact this is a lot easier as you don't need to get the hosted zone id etc, just pass it some readily available information and it creates a base path mapping that actually works:
new CfnApiMapping(this, 'myMapping', {
apiId: this.api.restApiId,
domainName: 'old custom domain'
stage: this.api.deploymentStage.stageName,
apiMappingKey: 'foo',
});
I should warn that this comes with strange behaviour.
First an overview of my setup:
The old api has the following path on it: [old api]/foo/bar. The old custom domain is mapped straight to the old api with no path, so the old endpoint url is [old custom domain]/foo/bar. The new endpoint is [new custom domain]/bar. In order for the old URL to map to the new api, I need a base path mapping for foo on the old custom domain to point to the new api, so that [old custom domain]/foo/bar will be directed to [new api]/bar. (Note there are no other resources on foo and nothing new will be added, so this is fine.)
So currently calling [old custom domain]/foo/bar invokes the /foo/bar path on the old api. Once I deploy the CfnApiMapping resource, calling that same URL invokes the correct path on the new api.
Weird behaviour 1: If I delete that base path mapping, I would expect it to go back to the original api. Instead I get a 403 error. If I create it again, it resolves to the new API again, and deleting it again gives the 403 error again.
Weird behaviour 2: If instead of deleting it, I change the path value so it no longer maps "foo", the /foo/bar path works with the old endpoint again. I can then delete the mapping and everything keeps working fine.
Weird behaviour 3: I am unable to recreate this as I can't remember which sequence of steps I took, but it happened a couple of times where I deleted the base path mapping and it continued to work as if the mapping was still there. There was no mapping visible in the console, and I gave it plenty of time for the change to take effect, but it continued to work.
All this is done with the CDK, not manually. Doing this manually or via regular cloudformation works with no issues.

Firebase Functions + Express + subfolder names in routes + logs including route names?

I want to use Firebase Functions and Express to have routes like the following:
/users/:uid
/users/:uid/create
/users/:uid/update
/users/:uid/addFriend/:toAddUid
/users/:uid/sendMessage/:sendToUid
You can do this using Express e.g.
https://medium.com/#atbe/firebase-functions-true-routing-2cb17a5cd288
with a line like this:
exports.api = functions.https.onRequest(expressApp);
However, the logging you get is now very bad. On deploy, you're only told the route "api" was deployed. The runtime logs when functions are running are grouped into a single function called "api" so the dashboard won't tell you how much time was spent in each function, number of calls etc.
How can I get the route names I'd like with decent logging?

How do you use the serviceNameFilter when calling QueryClient.GetServiceListAsync

I'm using Azure Service Fabric with stateless services. I have a list of services deployed under an application, and there's a naming convention used with those service names. I'd like to get a list of services that match a filter expression.
Here is a link to a screenshot of my service fabric explorer. I don't have the reputation points to post an image.
Service Fabric Explorer screenshot
In this example, the name of my application is SFApp1, and the name of my service is HelloWorldStateless. I'd like to query the service fabric cluster to locate all services with the name "HelloWorldSt*" (under the SFApp1 application of course).
I know I can query to find all services with the application name "fabric:/SFApp1", and it'll return all services under that application. This overload of GetServiceListAsync takes just an application URI.
FabricClient client = new FabricClient();
ServiceList serviceList = client.QueryManager.GetServiceListAsync(new Uri("fabric:/SFApp1")).Result;
I also know I can query to find a specific service. This overload takes an application URI AND a service URI and will return a single-item list.
FabricClient client = new FabricClient();
ServiceList serviceList = client.QueryManager.GetServiceListAsync(new Uri("fabric:/SFApp1"), new Uri("fabric:/SFApp1/HelloWorldStateless")).Result;
What I'm trying to find out is if there's any way to do something like a wildcard search.
FabricClient client = new FabricClient();
ServiceList serviceList = client.QueryManager.GetServiceListAsync(new Uri("fabric:/SFApp1"), new Uri("fabric:/SFApp1/HelloWorldSt*")).Result;
The name of the parameter where the service name is specified is serviceNameFilter, and the method returns a list. I'm wondering why they would return a list for this overload if the result was always going to be a single-item list. Also, the parameter name "serviceNameFilter" suggests (to me at least) that there's the ability to supply some kind of expression to narrow down your list.
Here's what I've tried already. I've tried the code above, where I chop off a few characters and put an asterisk. I've tried without the asterisk to see if it was a substring match. I've tried SQL-style, with a percent symbol. I've tried a question mark. All of those attempts returned an empty list.
My current workaround is just to ask for all services under that application, and I'll filter them on the client code end with a linq expression. That'll work, but I worry about performance if my list of services gets really big.
Would be nice if I could inspect the source code to answer this myself.
Is there a way to do what I'm trying to do, or am I just misinterpreting what "serviceNameFilter" means, and it just means you have to put the entire service URI that you're looking for?
Thanks for any help you can provide!
Unfortunately that API parameter is terribly named. It's not really a filter at all, it's just the name of the service (since there's no other query that just returns one service, this is how you "filter" from all the services in an application down to just one in particular).
The nearest thing to what you're looking for is EnumerateSubnames. It's not a wildcard search, but you can get all the names that exist "underneath" a given name (for example, all of the service names that exist within an application, or all names with some specific prefix). Depending on the structure of how you create your service names this could work for you.
// System.Fabric.FabricClient.PropertyManagementClient
public Task<NameEnumerationResult> EnumerateSubNamesAsync(Uri name, NameEnumerationResult previousResult, bool recursive)
For example: Presume the following names exist in the cluster:
fabric:/SomeApplication/Zone1/Service1
fabric:/SomeApplication/Zone1/Service2
fabric:/SomeApplication/Zone2/Service1
Note that in this case the application would have been created with the name "fabric:/SomeApplication" and then the services with the detailed names above incorporating the "Zone" segment.
If you now EnumerateSubnames("fabric:/SomeApplication/Zone1", null, true) you'd get back a result that gave you the full names that matched (1 & 2 above).

Should a RESTful API avoid requiring the client to know the resource hierarchy?

Our API's entry point has a rel named "x:reports" (where x is a prefix defined in the HAL representation, by way of a curie - but that's not important right now).
There are several types of reports. Following "x:report" provides a set of these affordances, each with a rel of its own - one rel is named "x:proofofplay". There is a set of lookup values associated with this type of report (and only this type of report). The representation returned by following "x:proofofplay" has a rel to this set of values "x:artwork".
This results in the following hierarchy
reports
proofofplay
artwork
While the "x:artwork" resource is fairly small, it does take some time to fetch it (10 sec). So the client has opted to async load it at app launch.
In order to get the "x:artwork"'s href the client has to follow the links. I'm not sure whether this is a problem. It seems potentially unRESTful, as the client is depending on out-of-band knowledge of the path to this resource. If ever path to artwork changes (highly unlikely) the client will break (though the hrefs themselves can change with impunity).
To see why I'm concerned, the launch function looks like this:
launch: function () {
var me = this;
Rest.getLinksFromEntryPoint(function(links) {
Rest.getLinksFromHref(links["x:reports"].href, function(reportLinks){
Rest.getLinksFromHref(reportLinks["x:proofofplay"].href, function(popLinks){
me.loadArtworks(popLinks["x:artwork"].href);
});
});
});
}
This hard-coding of the path simultaneously makes me think "that's fine - it's based on a published resource model" and "I bet Roy Fielding will be mad at me".
Is this fine, or is there a better way for a client to safely navigate such a hierarchy?
The HAL answer to this is to embed the resources.
Depending a bit on your server-side technology, this should be good enough in your case because you need all the data to be there before the start of the application, and since you worry about doing this sequentially, you might parallelize this on the server.
Your HAL client should ideally treat things in _links and things in _embedded as the same type of thing, with the exception that in the second case, you are also per-populating the HTTP cache for the resources.
Our js-based client does something like this:
var client = new Client(bookMarkUrl);
var resource = await client
.follow('x:reports')
.follow('x:proofofplay')
.follow('x:artwork')
.get();
If any of these intermediate links are specified in _links, we'll follow the links and do GET requests on demand, but if any appeared in _embedded, the request is skipped and the local cache is used. This has the benefit that in the future we can add new things from _links to _embedded, and speeding up clients who don't have to be aware of this change. It's all seamless.
In the future we intend to switch from HAL's _embedded to use HTTP2 Push instead.

Performing Sticky load balancing in Camel

Hi I would like to perform sticky load balncing in apache camel based on the SOAP session, whcih is embedded in ServiceGroupID node of the first response.
I wrote a small route as follow:
from(uri)
.loadBalance().sticky(xpath(query).namespaces(env).namespaces(wsa).namespaces(ax))
.to(BE1,BE2);
Where URI is the string to which the requests are passed and BE1 and BE2 are the two backend servers.
And my query is
String query = "/soapenv:Envelope/soapenv:Header/wsa:ReplyTo/wsa:ReferenceParameters/axis2:ServiceGroupId/text()";
If i am not wrong this query would extract the servicegroupID from my SOAP header.
But when I try to perform the balancing, due to some reason whatsoever, the requets are not being passed to the same backend server.
and my env, wsa and ax are the namespaces, which are :
Namespaces env = new Namespaces("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
Namespaces wsa = new Namespaces("wsa", "http://www.w3.org/2005/08/addressing");
Namespaces ax = new Namespaces("axis2", "http://ws.apache.org/namespaces/axis2");
Am I doing something wrong here?
If so what? I would appreciate any help.
Also being discussed at the mailing list
http://camel.465427.n5.nabble.com/Performing-Sticky-load-balancing-in-Camel-tp5719170.html
Please dont start the same topic in multiple places at the same time. And if you do, then at least tell us, so we would know this.
People get upset when they spend time to help you, when its already been answered in another place!