Apigee fault handling for CLASSIFICATION_FAILURE - apigee

In Apigee, can fault handling - specifying a FaultRule and a RaiseFault policy be used to handle and provide a custom message for:
{
"fault": {
"faultstring": "Not Found",
"detail": {
"errorcode": "CLASSIFICATION_FAILURE"
}
}
}
If this can be done, should the 'Condition' for the fault rule be 'fault.name = "CLASSIFICATION_FAILURE"'? I tried this and it is not working.

CLASSIFICATION_FAILURE is a system level failure to find an API Proxy for the given URL/URI. The request will not even reach the API proxy(hence the policies) - which is the precise complaint by the system.
So you do not want to handle an error like that.
Another way to approach this case is to have a catch all API proxy with basepath /** which will be invoked when there is no specific URL match. You can generate a custom message in this proxy - this can be the message you wanted to send across in case of classification failure.

Srikanth's answer on 30/05/2014 is only partially correct. Using a basepath /** did not work for us. Instead, we had to create an api proxy with basepath = /
Inside the proxy, we defined a RaiseFault in Preflow and that was it.

Related

CORS issue when calling API via Office Scripts Fetch

I am trying to make an API call via Office Scripts (fetch) to a publicly available Azure Function-based API I created. By policy we need to have CORS on for our Azure Functions. I've tried every domain I could think of, but I can't get the call to work unless I allow all origins. I've tried:
https://ourcompanydoamin.sharepoint.com
https://usc-excel.officeapps.live.com
https://browser.pipe.aria.microsoft.com
https://browser.events.data.microsoft.com
The first is the Excel Online domain I'm trying to execute from, and the rest came up during the script run in Chrome's Network tab. The error message in office Scripts doesn't tell me the domain the request is coming from like it does from Chrome's console. What host do I need to allow for Office Scripts to be able to make calls to my API?
The expected CORS settings for this is: https://*.officescripts.microsoftusercontent.com.
However, Azure Functions CORS doesn't support wildcard subdomains at the moment. If you try to set an origin with wildcard subdomains, you will get the following error:
One possible workaround is to explicitly maintain an "allow-list" in your Azure Functions code. Here is a proof-of-concept implementation (assuming you use node.js for your Azure Functions):
module.exports = async function (context, req) {
// List your allowed hosts here. Escape special characters for the regular expressions.
const allowedHosts = [
/https\:\/\/www\.myserver\.com/,
/https\:\/\/[^\.]+\.officescripts\.microsoftusercontent\.com/
];
if (!allowedHosts.some(host => host.test(req.headers.origin))) {
context.res = {
status: 403, /* Forbidden */
body: "Not allowed!"
};
return;
}
// Handle the normal request and generate the expected response.
context.res = {
status: 200,
body: "Allowed!"
};
}
Please note:
Regular expressions are needed to match the dynamic subdomains.
In order to do the origin check within the code, you'll need to set * as the Allowed Origins on your Functions CORS settings page.
Or if you want to build you service with ASP.NET Core, you can do something like this: https://stackoverflow.com/a/49943569/6656547.

Disable Only HealthCheck Related Logging

I'm trying to figure out a way to disable any health-check related ILogger logging. I am aware of LogLevel filtering, but that will not work here.
As an example, I have a healthcheck that makes an outbound call to a RabbitMQ metrics API. This results in an outbound http call with every inbound call to /health. In general, I want to log all outbound calls made using the HttpClient, but that log is now full of this particular log entry:
[2021.06.15 13:57:04] info: System.Net.Http.HttpClient.Default.LogicalHandler[101] => ConnectionId:0HM9FV5PFFL5K => RequestPath:/health RequestId:0HM9FV5PFFL5K:00000001, SpanId:|6726c52-4217ec92de4df5fb., TraceId:6726c52-4217ec92de4df5fb, ParentId: => Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckLogScope => HTTP GET http://rabbitmq/api/queues/MyVHost/MyQueue?msg_rates_age=60&msg_rates_incr=60
: End processing HTTP request after 4.6355ms - OK
So, I could apply a warning filter to the HttpClient/LogicalHandler to remove those entries, but then I'd be removing all the info logs of other outbound Http requests, which I don't want.
So, basically, I need a smarter filter that can look at the scopes (or even the text in certain cases), and can filter out based on "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckLogScope". That doesn't seem to be possible though, as the filter callback doesn't provide those details.
Does anyone have any idea how to do more specific log filtering for cases like this?
I have looked at .net core log filtering on certain requests, but extending every ILoggerProvider I use isn't possible, since some are not public classes.
You could use Serilog for logging, as it also provides great filtering, enriching, and formatting capabilities with Serilog.Expressions Nuget package.
There is even a simple example provided in the link above for filtering health checks, which fulfilled my needs to fully filter out health check logging based on the request path '/health'. Following the guide, it only required adding appsettings.json configuration, after the serilog was configured as the application logger to make it work:
{
"Serilog": {
"Using": ["Serilog.Expressions"],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "RequestPath like '/health%'"
}
}
]
}
}
To filter out those requests you can try using the Log4Net StringMatchFilter filter with the value of the health URL.
Here is the code for the configuration file if health URL is just localhost/health:
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="/health" />
<acceptOnMatch value="false" />
</filter>

Get detailed error for exception in SignalR Core Hub method execution

When I call Hub method I get frame response:
{"invocationId":"1","type":3,"error":"An error occurred while updating
the entries. See the inner exception for details."}
How can I get detailed error report (row and file where error occurred) without manually debugging and using step over and check where the code raise exception.
On net I found plenty codes where EnableDetailedErrors is used
services.AddSignalR(options =>
{
options.Hubs.EnableDetailedErrors = true;
});
but options (at least in version 1.0.0-alpha2-final) does not have property Hubs.
This is what you need to do in core (not sure the exact version this was added):
// signalR
services.AddSignalR(options =>
{
if (Environment.IsDevelopment()) {
options.EnableDetailedErrors = true;
}
});
It goes without saying that the reason this is disabled by default in production is for security reasons. So be careful not to expose things you may not wish 'hackers' to see in any of the exceptions you may throw.
Implementing the above setting will reveal a more detailed message in the browser console, whcih you can also see in the websocket debugging tab:
Quick tip:
I've set up SignalR twice now on ASPNetCore and I think I've made the same mistake both times:
// from typescript client arguments are passed like this
this.hubConnection.invoke('SendMessage', 'simon', 'hello');
// not like this
this.hubConnection.invoke('SendMessage', ['simon', 'hello']);
Also invoke will wait for a response, while send does not. So you may not see errors using send.
Currently the option to enable detailed errors is not implemented. There is an issue tracking this. My recommendation would be to turn on logging on the server side - the original exception will be logged there.

Apparently my API Proxy does not exist

I've created a new API Proxy and deployed revision 1 into production, but when I call my API I just get:
HTTP 500 Internal Server Error
{
"fault": {
"faultstring": "Internal server error APIProxy revision 1 of MyProxy does not exist in environment prod of organization MyOrg",
"detail": {
"errorcode": "messaging.adaptors.http.ServerError"
}
}
}
Not the most helpful error message in history. Any pointers where to start debugging this would be very helpful, thanks!
You appear to be using the wrong url for your API, so it could not be found. If you haven't added any API key checking or additional authorization, you should be able to copy the url directly from the API details page in the prod Deployments line. Start a trace session and paste that url into the URL box. Test what happens when you do that trace.
If you have any additional security or other features that would alter the API, you would need to make those changes to the URL before sending it. If you're still having a problem, send an email to help#apigee.com.

How to stop consumers from hitting invalid resources in APIGee API

I have an Apigee proxy that has two resources (/resource1 and /resource2). If tried to access /resource3. How do I return a 404 error instead of the Apigee default fault?
Apigee displays the below fault string:
{
"fault": {
"faultstring": "The Service is temporarily unavailable",
"detail": {
"errorcode": "messaging.adaptors.http.flow.ServiceUnavailable"
}
}
}
Thanks
Currently the way flows work in apigee this way - It parses through your default.xml (in proxy) and tries to match your request with one of the flow either through the path-suffix like "/resource1, /resource2" or VERB or any other condition you might have. If it does not find any matching condition, it throws the error like above.
You can add a special flow which will be kicked in if the condition matches none of the valid flows you have. You can add a raisefault policy in that flow and add a custom error response through that flow.
A better solution is to:
be sure to define something in the base path of all Proxy APIs
create an additional Proxy API called "catchall" with a base path of "/" and with just a Raise fault throwing a 404
Apigee execute Proxy APIs from longest Base Path to shortest; the catchall will run last and always throw back a 404
I just want to clarify Vinit's answer. Vinit said:
If it does not find any matching condition, it throws the error like above.
Actually, if no matching flow condition is found, the request will still be sent through to the backend. The error you mentioned:
{
"fault": {
"faultstring": "The Service is temporarily unavailable",
"detail": {
"errorcode": "messaging.adaptors.http.flow.ServiceUnavailable"
}
}
}
was returned after attempting to connect to the backend without matching a flow.
Vinit's solution to raise a fault to create the 404 is the best solution for your requirements.
In some cases, however, it is appropriate to pass all traffic through to the backend (for example, if you don't need to modify each resource at the Apigee layer, and you don't want to have to update your Apigee proxy every time you add a new API resource). Not matching any flow condition would work fine for that use case.

Resources