I have a service that has a method (A.method()) which is called by other methods from multiple services (B.method(), C.method()...).
I want to know somehow what's the method caller name or the service that called my method.
The only working solution I found until know is throwing a dummy error and checking error.stack, but this is dirty :)
PS: I'm not using any controller/resolver, just functions that are starting because of cronjobs or constructors.
I tried interceptors & auth guards but it seems they do not work for simple methods.
I think the error stack is enough information.
If you find the name is ugly, then you should add sourceMap for better function name and file location.
Another approach ( maybe a bit overkill ) is to add tracing like Jaeger or OpenTelemetry to visualize the functions call, execution time and many other information.
Related
Well I have a few pipes in the application I'm working on and I'm starting to think they actually should be guards or even interceptors.
One of them is called PincodeStatusValidationPipe and its job as simple as snow. It checks the cache for a certain value if that value is the one expected then it returns what it gets otherwise it throws the FORBIDEN exception.
Another pipe is called UserExistenceValidationPipe it operates on the login method and checks if a user exists in DB and some other things related to that user (e.g. wheter a password expected in the login method is present and if it does then whether it matches that of the retrieved user) otherwise it throws appropriate exceptions.
I know it's more of a design question but I find it quite important and I would appreciate any hints. Thanks in advance.
EDIT:
Well I think UserExistenceValidationPipe is definitely not the best name choice, something like UserValidationPipe fits way better.
If you are throwing a FORBIDEN already, I would suggest migrating the PincodeStatusValidationPipe to be PincodeStatusValidationGuard, as returning false from a guard will throw a FORBIDEN for you. You'll also have full access to the Request object which is pretty nice to have.
For the UserExistenceValidationPipe, a pipe is not the worst thing to have. I consider existence validation to be a part of business logic, and as such should be handled in the service, but that's me. I use pipes for data validation and transformation, meaning I check the shape of the data there and pass it on to the service if the shape looks correct.
As for interceptors, I like to use those for logging, caching, and response mapping, though I've heard of others using interceptors for overall validators instead of using multiple pipes.
As the question is mostly an opinionated one, I'll leave the final decision up to you. In short, guards are great for short circuiting requests with a failure, interceptors are good for logging, caching, and response mapping, and pipes are for data validation and transformation.
We are currently working on performance issues with our provided OData interface, since the UI5 issues a read request with multiple expand paths attached. Due to the generic handling of the request by the framework this leads to an additional processing per expand option, which we need to prevent.
Reading the blog about this topic there seems to be a way to overwrite the generic handling somehow:
https://blogs.sap.com/2018/03/19/sap-cloud-platform-sdk-for-service-development-create-odata-service-7-more-navigation-read-create-expand-sqo/
In this case it is us who need to decide if we can afford to rely on the FWK-functionality. Of course, such generic support cannot be performant. But for small amount of data it is just nice to get it for free.
Stay tuned to learn how to overwrite such generic FWK-functionality with own specific implementation.
However, there is no further blog post on this and looking through the framework, my only idea to overwrite this would be to configure and use an own com.sap.gateway.core.api.provider.data.IDataProvider implementation which handles the request in a custom way, although this would be an immense workaround.
So the questions is if there is some leaner or easier approach to overwriting this functionality which I missed?
UPDATE:
I was update to create a custom data provider and register it with the RuntimeDelegate after servlet initialization. This custom data provider would then check for a custom annotation on the mapped method handler to see if expand should be handled or not. If not it will just read the entity, but not perform he generic expanded read. This works more or less fine, but what is of course missing is a way to pass the properties to be expanded in the ReadRequest. So far only a static implementation is possible solving our performance problem, but I would gladly have a hint if there is another, better solution for this...
At the time of this writing, no better approach exists at the moment.
I did a google search, but I could not find what I really need.
I need to query an API, which have the same route, but with different parameters.
Example:
router.get('/items/:query, function(){})
In this case, I would search for all items
router.get('/items/:id, function(){})
Here, I would look for a specific item
At the core of your issue is that you are trying to specify two different resources at the same location. If you design your API to adhere to restful principles you'll see why that's not a wise choice. Here are two good starting points:
https://en.wikipedia.org/wiki/Representational_state_transfer
http://www.restapitutorial.com/lessons/whatisrest.html
In restful api's the root resource represents the item collection:
/api/items
...and when you specify an id that indicates you want only one item:
/api/items/abc123
If you really still want to accomplish what you asked in your question you'll need to add a url parameter like /items/query?query=true or /items/abc123?detail=true but this will be confusing to 99% of web developers who ever look at your code.
Also I'm not sure if you really meant this, but when you pass a variable named "query" to the server that seems to indicate that you're going to send a SQL query (or similar data definition language) from the client into the server. This is a dangerous practice for several reasons - it's best to leave all of this type of code on your server.
Edit: if you really absolutely positively have to do it this way then maybe have a query parameter that says ?collection=true. This would at least be understood by other developers that might have to maintain the code in future. Also make sure you add comments to explain why you weren't able to implement rest so you're not leaving behind a bad reputation :)
The issue is that without additional pattern matching there isn't a way Express will be able to distinguish between /items/:query and /items/:id, they are the same route pattern, just with different aliases for the parameter.
Depending on how you intend to structure your query you may want to consider having the route /items and then use query string parameters or have a separate /items/search/:query endpoint.
I'm building a service which is fragmented across multiple modules that are required when necessary.
I need to access the "request" variable from the router in all my modules.
My current solution (which has been suggested in other threads for passing variables in general) is to pass it to each required module:
var a_module = require('./a_module')(req);
And exporting each module as functions:
module.exports = function(req) {
...
}
But it is verbose and involves having to export my modules as functions, and only having access to this variable in the scope of the exported functions. Ideally I would like to be able to access the variable across the entire required module.
Is there any other elegant way to do it that I am missing? Like declaring the req variable as a global across the entire application?
This question is going to solicit opinions not answers, so it's not a great fit for stack overflow, but here's my $0.02.
You need to step back and ask yourself if you have really written so many modules that need access to a request object. I don't think you have. What you should be writing are functions that take the specific data they need - no more, no less. All these functions almost certainly don't need the entire request. How many of them really need access to every HTTP header, for example? Think of your program as a set of operations on domain objects/data. For example, maybe there's a function that takes a user account record and promotes it from a regular user to an administrator. All that function needs is the user account. It should not be coupled to an HTTP request object.
Just write a bunch of cleanly decoupled functions that take a small number of precise parameters and do something useful with them. This is called "loose coupling". Then organize groups of related functions into a module. This is called "cohesion". Then use some "glue" code to extract the necessary parameters from the HTTP req object and pass them as arguments to these functions. These same functions should work for a command line interface or another non-HTTP interface. They will be easier to understand, test, and more long-lived if you code them that way instead of going nuts with every line of every module knowing about the current HTTP req object.
In our domain-driven application, we use a type called ServiceResponse<> to send data between layers of our application - specifically, one is returned by every method in the domain. As of right now, it encapsulates the data (if any) which was returned from the method, or any errors that it may have generated.
My question, then, is this: is it an acceptable practice to add fields to this object that may be useful in other layers of the application? For example, is it good form to add a Status or StatusCode field to it that may be interpreted later by the service layer for use as an HTTP status code (with or without some mapping)?
It sounds like a fine place to me. The idea that every method returns a "response" of some sort smells a bit like trying to decouple too much, but there are some cases where such extreme decoupling is warranted.
In any case, the ServiceResponse could easily have a status, and if it needed one, that is where I would put it.