I just took a look at the API Connect and DataPower documentation online for version 10.0.5.x LTS. I could not find a diagram that shows the processing flow of an API request from a consumer through all of the potential processing spots that occurs before my API executes and what occurs after my API completes. This email thread seems to contain a lot of the detail.
Original Message:
Sent: Tue November 28, 2023 04:54 PM
From: Steve Linn
Subject: How does 'finally' actually work?
Hi Mohamed,
My apologies for the delay in responding as I was out of the office last week. I've confirmed with the Gateway developer that is the SME for this area of the code. The post-error finally will be executed for every API, so your initial try/catch/finally Java like example above was pretty close. The preflow and post-response global policies fit in nicely, so the finally clauses there will execute regardless of what happens in the preflow and post-response global policies. As for the post-error, the catch will catch any exception that has not been caught, but the finally will execute as a finally for the entire transaction flow, error or no error. I'd need to give some thought then to when you'd use a finally in a post-response global policy unless it was something you wanted to do only for successful transactions, whereas the finally in the post-error would be for something that you needed done for all transactions, successful or unsuccessful, perhaps such a policy that does some logging to an external system, header manipulation of what is returned to the client, etc.
Best Regards,
Steve Linn
------------------------------
Steve Linn
Senior Consulting I/T Specialist
IBM
Original Message:
Sent: Mon November 20, 2023 12:18 PM
From: Mohamed Alkhaligy
Subject: How does 'finally' actually work?
Hi @Steve Linn
Regarding the point
For post-error global policies, they will for sure receive exceptions for any uncaught exception, either from a preflow (including a preflow global policy) or the mainline assembly. Successful requests will be handled in the global post-response policy if present. The post error global policy will never be executed for successful requests, so I believe it will be an either/or use case. Again, I've never tried generating an exception in a post-response global policy to know if that would trigger the post-error global policy, but I'd think that would not be a normal flow and would be more of a defect in the post-response global policy that would need to be fixed. Please clarify if I've misunderstood the question.
The issue here is that I also believed that it would be an either/or use case. But as stated in my original question, the finally block of the error global policy always executes in both successful and unsuccessful requests! Is this a product defect or expected behavior?
Edit 26/11/23: Can you @Steve Linn, @Chris Dudley, or anyone from the APIC team confirm/reply?
------------------------------
Mohamed Alkhaligy
Original Message:
Sent: Fri November 17, 2023 10:06 AM
From: Steve Linn
Subject: How does 'finally' actually work?
Hi Mohamed,
Somewhat. I believe the Global Policies would act independently, so each can have a finally as you've shown, but there isn't an overall arching global policy. As for UnauthorizedError, ForbiddenError, and BadRequestError, this is a left over from the v5 design. Initially, v5 would not allow these three preflow errors to be caught by an API. When that enhancement was added much later after GA, the concern was that starting to catch these errors by default could be a behavioral change that would impact existing APIs that had a default catch, which is why v5 required them to be explicitly caught. That design was then brought forward into the API Gateway. Note that handling of these preflow errors shouldn't be handled in the global preflow policy as catching them there and "handling" them would allow the flow to proceed to the mainline API execution. They should instead only be caught in the post-error global policy which is where the handling of these errors, where the typical use case I've seen is changing the schema of the returned error response, should be done.
As for redact, typically you'd redact based upon the API and the schema it knows about, so I'd think the mainline finally would be where that would go. I agree a redact in a pre-request global policy is too early. The pre-request global policy actions are simply added to the beginning of the default preflow actions (cors, security, etc). Trying to handle a redact globally in a post-response global policy or post error would be done for every API whether it required redaction or not and I'd expect the schemas of the data being redacted would be different by API use case, and if you have both JSON and XML payloads, that would make the handling more complex. Having said that, I don't have a reason why it would not work there as long as the properties being redacted were in the payload/logs, but I have to say I've never tried it. Also remember as part of an log redaction, prior to the redact policy, you must also have a log policy with the gather-only property which will place the analytics data into the context where the redaction can be done.
For post-error global policies, they will for sure receive exceptions for any uncaught exception, either from a preflow (including a preflow global policy) or the mainline assembly. Successful requests will be handled in the global post-response policy if present. The post error global policy will never be executed for successful requests, so I believe it will be an either/or use case. Again, I've never tried generating an exception in a post-response global policy to know if that would trigger the post-error global policy, but I'd think that would not be a normal flow and would be more of a defect in the post-response global policy that would need to be fixed. Please clarify if I've misunderstood the question.
Best Regards,
Steve
------------------------------
Steve Linn
Senior Consulting I/T Specialist
IBM
Original Message:
Sent: Thu November 09, 2023 06:06 PM
From: Mohamed Alkhaligy
Subject: How does 'finally' actually work?
Hi @Steve Linn,
That's really a lot of work. Thank you for your detailed reply.
Just to make sure I understood everything correctly.
You mentioned that it behaves like high-level programming languages, so can we assume that the following code models how the flow works?
try { try { // Error GP try { ... // Pre-request Global Policy Logic } catch (error) { switch (error.name) { case ConnectionError: { ... break; } // A case for every exception catch configured explicitly? . case CustomError: { ... break; } . default : { ... } } } finally { ... } try { ... // Mainline Assembly Flow Logic } catch (error) { switch (error.name) { case ConnectionError: { ... break; } . case CustomError: { ... break; } . default : { ... } } } finally { ... } try { ... // Post-response Global Policy Logic } catch (error) { switch (error.name) { case ConnectionError: { ... break; } . case CustomError: { ... break; } . default : { ... } } } finally { ... } } catch (error) { // Error GP Catch switch (error.name) { . case CustomError2: { ... break; } . default : { ... } } } finally { ... }} catch (error) { // A catch for all uncaught errors probably even UnauthorizedError, ForbiddenError, and BadRequestError. (Internal to IBM, not customizable?)}
A- Does this model how other finally blocks interact with each other? (Probably the only thing that I cannot model here is why APIC needs to catch UnauthorizedError, ForbiddenError, and BadRequestError explicitly if we have a default for all uncaught exceptions?)
B- Going back to the redact example and by following my model, If we add redact in the finally block of the mainline API assembly, or post-response global policy, or error global policy it will probably work as intended. Correct? (Probably not with pre-request GP finally block as it will redact before the mainline assembly flow executes)
C- But in my case, we are implementing a custom solution that must be run after the end of either a successful request or error global policy catches logic has been completed. So, if I understand correctly now we need to add this logic only to the finally block of the error global policy? (Because If it was added only in the post-response global policy it will not run in case of exception, and If added only to the finally block of the post response it will run anyway but as I mentioned we need the error global policy exception catch to be completed first, and If we add this logic to both the post-response GP and finally block of the error GP the logic will be run twice in case of a successful request as mentioned in my original question)
------------------------------
Mohamed Alkhaligy
Original Message:
Sent: Thu November 09, 2023 03:43 PM
From: Steve Linn
Subject: How does 'finally' actually work?
Hi Mohamed,
The finally clause was added in 10.5.0.x of DataPower. It behaves like any high level programming language that has a try, catch, finally syntax in that the try (In API Connect, that is your API assembly) will execute, but if it throws an exception, the catch block will be executed (In API Connect, the exception will be tested against those exceptions you are catching), and then regardless of if you had an exception or if the assembly executed successfully, the finally will execute. From an API Connect viewpoint, the best example I can think of it a redact version 2.0.0 policy. If you placed this policy at the end of your assembly but there was an exception in the assembly rule, then nothing would be redacted. Prior to finally in the 10.0.1.x versions, what you had to do was then place into your catch logic
- At the end of every caught exception (including a default catch) configured, a copy of the redact policy would need to be specified.
- If a default catch wasn't specified and since most probably the catch logic didn't catch every potential exception, a default catch would need to be added that would have a copy of the redact policy, and then since this wasn't planned to be a caught exception, a throw policy which would throw the original exception would need to be added so this exception behaved as if it was uncaught.
- If in a post error global policy which is where you would catch UnauthorizedError, ForbiddenError, and BadRequestError, these three exceptions must be caught explicitly, but again if they were not planned to be caught, the catch for these exceptions would need to be added and the throw added as well, just like the missing default catch.
Wow, now that's a lot of work. With finally, the redact policy will exist ONLY in the finally. It doesn't matter if an exception was thrown and if it was if it was caught or not caught. Every policy in the finally will be executed after the execute and catch and completed. The same would hold true of any API policy you would want to execute, regardless of exceptions, in your API, perhaps some logging you would like to do.
Within the post-error global policy, or even within your API assembly, you'll probably see finally rules being executed in the debug logs, but I don't believe there are any specific policies in those rules by default. By having a finally in your API assembly or in your global post-error policy, the deployment of those artifacts will add the actions in the finally that will be executed at that time.
Best Regards,
Steve
------------------------------
Steve Linn
Senior Consulting I/T Specialist
IBM
Original Message:
Sent: Mon November 06, 2023 04:06 AM
From: Mohamed Alkhaligy
Subject: How does 'finally' actually work?
Can you @Steve Linn, @Chris Dudley, or anyone from the APIC team reply to my issue/inquiry?
------------------------------
Mohamed Alkhaligy
Original Message:
Sent: Wed November 01, 2023 06:30 PM
From: Mohamed Alkhaligy
Subject: How does 'finally' actually work?
A couple of months ago I asked a question about error global policy & post-response global policy and the solution to that question was to add the post-response global policy logic to each catch in post-error which worked perfectly but was redundant. I am working now with APIC 10.0.5.x and I found that the assembly now includes execute, catch, and finally. So I assumed that 'finally' is going to run after either execute or catch is completed. Consequently, I added the post-response global policy logic (from the previous question) to the 'finally' of the error global policy (Instead of adding the same logic to each catch). But now when a successful request is executed both post-response global policy logic and error global policy's 'finally' logic are executed. I found no clear documentation about how 'finally' works, so how does it work in pre-request global policy, mainline API assembly, post-response global policy, and error global policy?
Edit: I also wanted to mention that no error occurred, so I am not sure why finally of the error global policy is being executed.
------------------------------
Mohamed Alkhaligy
------------------------------