When to use (decorate with) what and why - DefaultErpHttpDestination, DefaultHttpDestination? - sap-cloud-sdk

Using java SAP Cloud SDK
I have to use com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.outbounddeliveryv2.batch.OutboundDeliveryV2ServiceBatch.execute(HttpDestinationProperties destination) to perform some updates on S/4 system. This method, execute takes an argument of type HttpDestinationProperties.
Since I need a destination, I am using below code to get destination:
HttpDestination destination = DestinationAccessor.getDestination("MyErpSystem").asHttp();
Since HttpDestination extends HttpDestinationProperties, we can safely pass it to execute. But according to step 4 of 'Connect to OData Service on Cloud Foundry Using SAP Cloud SDK' tutorial, the code for accessing destination looks like this:
ErpHttpDestination destination = DestinationAccessor.getDestination("MyErpSystem").asHttp().decorate(DefaultErpHttpDestination::new);
and then they pass that destintion to the execute method of the service.
My question is that since execute methods takes an argument of type HttpDestinationProperties, How would I know that I have to use DefaultErpHttpDestination? Same thing goes for DefaultHttpDestination.
I have following questions -
When and why should I wrap the destination in DefaultErpHttpDestination?
When and why should I wrap the destination in DefaultHttpDestination?
Why should I wrap the destination in above two wrappers at all?

This is an excellent question!
The context:
Of course you can keep using your original approach:
HttpDestination destination =
DestinationAccessor.getDestination("MyErpSystem").asHttp();
This is the recommended way for destinations targeting a generic HTTP service endpoint.
It loads the required destination properties for HTTP connections, e.g. URL, Authentication, ...
In the tutorials we are describing the integration with S/4HANA OData services:
HttpDestination destination =
DestinationAccessor.getDestination("MyErpSystem").asHttp()
.decorate(DefaultErpHttpDestination::new);
By "decorating" the HttpDestination instance with ERP properties, we enable additional S/4 related HTTP request headers: sap-client and sap-locale. With the above configuration, those values are read automatically from the destination service - if they are set.
Your questions (changed order):
"When and why should I wrap the destination in DefaultHttpDestination?"
DestinationAccessor#getDestination returns a generic Destination. In order to make sure we are dealing with HTTP (and not RFC) connections, you need to run #asHttp - as you already do. With the resulting HttpDestination instance, you can run HTTP queries like OData and REST. Depending on your use case, no additional wrapping is required.
For example, if you were about to use BAPI endpoints, then you'd need to run #asRfc instead. This method will check for different destination properties to make sure all required values are set.
"When and why should I wrap the destination in DefaultErpHttpDestination?"
It is recommended to wrap the destination in DefaultErpHttpDestination only when you are dealing with S/4 service endpoints and you rely on custom values for sap-client and sap-locale. The wrapping can be done at any time of your application runtime, as long as it happens before #execute(HttpDestinationProperties) method.
If you do not want to wrap it a second time, then you'd need to manually manage the HTTP request headers for sap-client and sap-locale.
"Why should I wrap the destination in above two wrappers at all?"
This is the API contract. It makes sure all required destination properties are correctly set before even invoking the actual request. The (optional) ERP flavored wrapping of the destination instance was provided to make sure all S/4 properties are automatically considered as well.

Related

Do Azure Functions have a request pipeline of some kind?

I would like to add some common authentication code to a collection of HttpTrigger Azure Functions (v3), which I'm using as an API. I know about the service-side auth associated with AuthorizationLevel.Function, but that won't work for me. The type of auth I need to do is relatively simple: just check a specific HTTP header for a specific value.
In ASP.NET, this kind of thing can be done in an HttpModule. Do Azure Functions have a similar request pipeline of some kind?
As far as I can tell from the documentation, it looks like new Function instances can call Startup.Configure() before calling the target method, if the project is appropriately configured. However, those calls are intended to support Dependency Injection, and don't have access to the HttpRequest object.
Obviously, I could just put an isAuthorized(request) call at the beginning of each API entry point, but that feels klunky, repetitive, and potentially error-prone. Is there a better way?

Use FluentAPI's to execute against a HTTPClient instead of a destination name

We want to use the VDM generated API's to execute against a Http client instead of a destination.
Currently the fluent api's work along the lines ::
service......execute(new ErpConfigContext(destinationName));
Is it Possible to have it work against a HTTP client.
Use Case :: We are trying to consume Odata Services in non CF environments.. where Destinations are not available.
Update: Starting with version 3.0.0 of the SAP Cloud SDK you are now able to create your own Destinations, so you are no longer reliant on Destinations provided by the SDK.
This might then look something like this:
HttpDestination httpDest = DefaultHttpDestination.builder("https://sap.com").build();
service.getAllEntities().execute(httpDest);
There is no direct possibility to do this via the VDM API as of version 2.19.1.
To circumvent this, however, you could override the DestinationFacade (cf. AbstractDestinationFacade) in the DestinationAccessor.
This would allow you to plug your "non-destination" concept into the VDM.

Azure Remote Monitoring - How to add parameters to CloudToDeviceMethods?

In Azure Remote Monitoring, you can create your own CloudToDeviceMethods. How do you add parameters to those methods?
Usually those methods look like this:
function main(context, previousState, previousProperties) { ... }
...in a .js file that has the name of a specific method. But I don't see how I can add parameters to a method like that. I also want to see those parameters in the Azure Remote Monitoring Solution Accelerator web, so I can call that method and send in some parameters.
A CloudToDeviceMethod supports exactly one parameter, and that is the JSON payload that you can give to it. Of course you can add many properties to that payload to act like separate parameters. On the device side, reading that parameter looks like this in C# and like this in JavaScript (Node example)
You mentioned that you want to be able to add those parameters in the Remote Monitoring Solution Accelerator. This is entirely possible with some changes to the ReactJS code. The main files you need to look at are the Job page, right now it calls the device method without a body. Eventually the request is built here, you can see the JsonPayload is left empty.

Can Azure Functions be used with URI path IDs?

I am wondering if it is possible to configure an Azure Function App to accept a URI-path ID as is typically used in RESTful services, e.g. /api/foo/1, where the function is foo. I haven't been able to find documentation on this and the binding information that I have found suggests that this isn't possible (I don't see a way to map it). It doesn't "just work" with the typical HTTP trigger (which supports /api/foo?id=1). In that configuration one receives a 404 response, I'm guessing because it doesn't know to call the foo function with the ID suffix in the URI.
In case it matters, I'm using C# to write my function.
You are correct that URI parameters are not supported at this time. If you'd like, you can create a feature suggestion for this here in our repo. Thanks :)

Is there a way to link a specific method to a Route in ServiceStack?

The Problem
I'm aware of the basic way to create a route/endpoint in ServiceStack using methods with names like "Get", "Post", "Any", etc inside a service but in the particular case that I'm trying to work with I have an existing service (which I can make an IService via inheritance) that can not be retrofitted w/ServiceStack attributes and currently uses DTOs for the requests and responses.
This service contains many functions that I do not want to manually mask (as this is a pass-through layer) but otherwise already conform to ServiceStack's requirements. What I'm wondering is if there's a way to manually create these routes in a way that would work like I've mocked up here. My existing functions and DTOs already contain the information I would need to define the routes so if this approach is possible it would only require me to enumerate them at initialization time as opposed to generating the services layer manually.
I noticed there is an extension method on Routes.Add that takes an Expression of type Expression> but I was not able to get that working because I believe the underlying code makes assumptions about the type of Expression generated (LambdaExpression vs MemberExpression or something like that). I also may be barking up the wrong tree if that's not the intended purpose of that function but I can not find documentation anywhere on how that variant is supposed to work.
Why?
I'm not sure this is necessary but to shed some light on why I want to do this as opposed to retrofitting my existing layers: The current code is also used outside of a web service context and is consumed by other code internally. Retrofitting ServiceStack in to this layer would make every place that consumes it require ServiceStack's assemblies and be aware of the web service which is a concern I want separated from the lower code. We were previously using MVC/WCF to accomplish this goal but we want some of the features available from ServiceStack.
the current architecture looks like this:
data -> DAL -> discrete business logic -> composition -> web service
Hopefully that makes enough sense and I'm not being obtuse. If you would like any more details about what I want to do or why I'll try to update this post as soon as possible.
Thanks!
You might use the fallback route in order to provide your own routing mechanism.
Then you get the request.Path property and route using your own mapping of path:Function which can be stored in a simple dictionary.
Anyway, if you go this path I don't see much benefit in using servicestack. It seems you just need an http handler that routes requests to existing services.

Resources