diff --git a/README.md b/README.md index 00d77177..da78f17f 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ After restarting your application, you should see an "aicore" entry in the `VCAP ```java Destination destination = DestinationAccessor.getDestination("my-aicore"); -ApiClient client = Core.getClient(destination); +ApiClient client = new AiCoreService().withDestination(destination); ``` @@ -239,7 +239,7 @@ For more detailed information and advanced usage, please refer to the following: To add a header to AI Core requests, use the following code: ```java -ApiClient client = Core.getClient().addDefaultHeader("header-key", "header-value"); +ApiClient client = new AiCoreService().client().addDefaultHeader("header-key", "header-value"); DeploymentApi api = new DeploymentApi(client); ``` diff --git a/docs/adrs/004-core-class-for-service-integration.md b/docs/adrs/004-core-class-for-service-integration.md new file mode 100644 index 00000000..3352672a --- /dev/null +++ b/docs/adrs/004-core-class-for-service-integration.md @@ -0,0 +1,108 @@ +# Core class for service integration + +Status: In-Progress. + + +## Background + +The integration with AI Core is based on multiple layers of API. +Depending on the usage scenario the user wants to interact with (1) AI Core, (2) foundation models, or (3) the orchestration service. +API design and expected behavior heavily depend on the use case and functional- and non-functional requirements. +When evaluating use cases we have to consider _nice_ users following best-practices with the same priority as _naughty_ users who do not follow recommendations nor read JavaDoc. + +Our product is the API. + +---- + +## API design requirements + +Let's distinguish between functional and non-functional requirements. + +### Non-Functional requirements + +* **Stability** + * The API should be stable upon release. + * Additions and extensions are allowed. + * Breaking changes to existing methods are not allowed. +* **Consistency**: + * The API should be reasonable consistent across all available service integrations. + * This includes naming conventions, method signatures, and compatible return types. +* **Usability**: + * The API should be easy to use and understand. + * The user is expected to mostly auto-complete the code. + Therefore fluent API design is expected. + * The user expects that all available methods may lead to a reasonable outcome. + * The user expects logic to be customizable. + * General code guidelines apply like JavaDoc, method names, and parameter count and -names. +* **Simplicity**: + * The core API should not (immediately) expose any internal methods or classes. + * No ambiguity. + No repetition and redundant data. + * Low hierarchy of API, i.e. deep nesting of classes is not required. + * Object immutability is preferred. +* **Transparency**: + * The API should be transparent about its behavior. + * Use correct method name prefix to indicate actions, e.g. `get`, `list`, `resolve`, `update`. + + +SAP Cloud SDK flavored requirements: +* Consider public interfaces over specific classes to be exposed to user. + This makes implementations easier to extend and replace in the future. + +### Functional requirements + +* **Optimization** + * Avoid redundant operations that cost heavy resources like time or memory, e.g. HTTP requests. + * Avoid premature computation of data. + * When evaluating, consider multi-threading and parallelism. + For shared objects, consider thread-safety. +* **Documentation** + * Document public API usage in our repository. + * Document best-practices and recommended API usage. + * Document pitfalls and bad-practices. + * Document error messages and solutions. + +SAP Cloud SDK flavored requirements: +* Log activity, intermediate results, fallbacks and errors. + + +## State of Core class + +| API | Behavior | +|--------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------| +| `new AiCoreService()` | | +| `withDestination()` | | +| `forDeployment()`
`forDeploymentByModel()`
`forDeploymentbyScenario()` | | +| `withResourceGroup()` | | +| `client()` | | +| `destination()` | | + +Properties: +* Lazy evaluation of deployments +* Lazy evaluation of service binding (if no destination is provided) +* Service Binding lookup itself is not cached by AI SDK itself, but by Service Binding library. +* Immutable objects. +* Custom method overloads on (sub-classes of) `AiCoreService` are propagated down to the client. + +Consideration: +* Always assume worst-case: + * User instantiates a constant `AiCoreService` in a static context. + * Custom Service Binding may be supplied by 3nd party library. + Race condition for resolving service bindings may lead to inconsistent behavior. + * User switches resource group at runtime. + * User switches destination at runtime. + * User switches deployment at runtime. + +Pro: +- No redundant HTTP traffic. +- Slim API contract, not many public methods. + +Con: +- Allowing for Resource Group declaration **only** on deployment level requires API separation. + Two classes are necessary, where one class would've been better. +- High maintainability cost. + Extending or changing the API and its inherent behavior will likely require a complete implementation rewrite. + +## Decision + +- postponed for now \ No newline at end of file diff --git a/docs/guides/AI_CORE_DEPLOYMENT.md b/docs/guides/AI_CORE_DEPLOYMENT.md index cf891ab4..2477b7fc 100644 --- a/docs/guides/AI_CORE_DEPLOYMENT.md +++ b/docs/guides/AI_CORE_DEPLOYMENT.md @@ -67,7 +67,7 @@ In addition to the prerequisites above, we assume you have already set up the fo Use the following code snippet to create a deployment in SAP AI Core: ```java -var api = new DeploymentApi(getClient()); +var api = new DeploymentApi(new AiCoreService().client()); var resourceGroupId = "default"; AiDeploymentCreationRequest request = @@ -86,7 +86,7 @@ Refer to the [DeploymentController.java](../../sample-code/spring-app/src/main/j AiDeploymentCreationResponse deployment; // provided String deploymentId = deployment.getId(); -var api = new DeploymentApi(getClient()); +var api = new DeploymentApi(new AiCoreService().client()); var resourceGroupId = "default"; if (deployment.getStatus() == AiExecutionStatus.RUNNING) {