> For the complete documentation index, see [llms.txt](https://docs.ecommerce.seb.ee/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ecommerce.seb.ee/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/celvezi/sdk-adapteru-aizstasana.md).

# SDK adapteru aizstāšana

Aizstājiet SDK infrastruktūras adapterus ar vietējiem HTTP, reģistrēšanas, serializācijas, šifrēšanas un webhook risinājumiem.

Izmantojiet šo rokasgrāmatu, ja vēlaties aizstāt vienu no SDK iebūvētajiem adapteriem — novirzīt HTTP caur savu klientu, sūtīt SDK diagnostiku uz savu žurnalēšanas sistēmu, nomainīt JSON serializatoru vai testos imitēt portu.

Šis [SDK arhitektūra](/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/celvezi/arhitektura-un-paplasinamiba.md) lapa izskaidro portu un adapteru dizainu un uzskaita piecus portus un to noklusējuma adapterus. Šī lapa ir praktiskais turpinājums: kuru sviru pavilkt un precīza sintakse katrai valodai.

## Kā darbojas pārrakstīšana

Katrā valodā ir pieejamas tās pašas trīs sviras, vienā un tajā pašā prioritātes secībā:

1. **Padodiet fabrikai (vai `EgwClient` konstruktoram) gatavu instanci.** Skaidri norādīts adapteris vienmēr ir prioritārs — fabrika tikai atgriežas pie atklāšanas tiem portiem, kurus atstājāt nenorādītus. Šis ir tiešākais un visdeterminētākais ceļš, un pareizā izvēle vienreizējām aizstāšanām.
2. **Reģistrējiet nodrošinātāju, izmantojot SDK pakalpojumu nodrošinātāja interfeisa (SPI) mehānismu.** A *nodrošinātājs* ir neliels fabrikas objekts, kas zina, kā izveidot jūsu adapteri; SDK sākumielāde to atrod un izmanto visur, kur tiek izveidots klients. Termins SPI nāk no Java pasaules, taču SDK šo koncepciju piemēro visās četrās valodās — katrs SDK glabā savus nodrošinātāju līgumus atsevišķā `spi` vārdtelpā, ko atklāj platformai raksturīgais idiomātiskais mehānisms. Ja zināt klasisko .NET nodrošinātāja modeli, Laravel servisu nodrošinātājus vai nodrošinātājus Angular/NestJS atkarību ievadē, tā ir tā pati ideja. Šis ir pareizais ceļš, ja pārrakstīšana ir stacijas mēroga politika ("visi EGW klienti šajā servisā žurnalē caur Serilog") nevis izvēle katram atsevišķam instancētam objektam.
3. **Paplašiniet klienta fabriku.** Fabrikas seko šablonmetodes (template-method) paraugam: viena pārrakstāma `newXxx()` izveides metode katram portam (Java/PHP). Apakšklases izmantošana dod jums pilnīgu kontroli pār izveidi, nepieskaroties SPI vispār.

Šis *mehānisms* aiz 2. sviras dažādās valodās atšķiras, katrai izmantojot platformai raksturīgo idiomu. Dodieties tieši uz savu:

* [**Java**](#java) — `ServiceLoader` atklāšana, reģistrēta ar `META-INF/services` failu
* [**PHP**](#php) — interfeisa uz klasi kartējums `providers.php` ko nododat fabrikai
* [**C#**](#c) — salikuma skenēšana; klases deklarēšana *ir* reģistrācija
* [**Node.js / TypeScript**](#nodejs) — tiešs `registerProvider()` izsaukums

Viena asimetrija, par ko jāzina Java un PHP: fabrika piedāvā skaidrus iestatījumus API klientam, API serverim un žurnalētājam, bet serializators un datu šifrētājs vienmēr tiek izveidoti caur SPI — lai aizstātu šos divus, izmantojiet 2. vai 3. sviru.

## Java

* **Atklāšana** — `java.util.ServiceLoader`
* **Reģistrācija** — `META-INF/services/<provider FQN>` fails vai JPMS `provides` klauzula
* **Ja sakrīt vairāki nodrošinātāji** — uzvar pirmais klases ceļā

Sākumielāde ir `DefaultEgwClientFactory`, kas katru portu atrisina caur `java.util.ServiceLoader` pret nodrošinātāju interfeisiem `...sdk.application.bootstrap.spi`: `ApiClientProvider`, `ApiServerProvider`, `DataEncrypterProvider`, `SerializerProvider`, kā arī `EgwLoggerProvider`.

**1. svira — fabrikas iestatītāji.** `connectingWith(ApiClient)`, `listeningWith(ApiServer)`, kā arī `loggingWith(EgwLogger)` pieņem gatavas instances:

```java
var client = new DefaultEgwClientFactory()
        .connectingTo(baseApiUri)
        .authorizingAs(System.getenv("EGW_CLIENT_ID"), System.getenv("EGW_CLIENT_SECRET"))
        .loggingWith(new Slf4jEgwLogger(LoggerFactory.getLogger("egw-sdk")))
        .createEgwClient();
```

**2. svira — ServiceLoader nodrošinātājs.** Realizējiet nodrošinātāja interfeisu ar publisku konstruktoru bez argumentiem, pēc tam reģistrējiet to `META-INF/services`. Žurnalētājs ir tīrākais SPI mērķis — SDK neiekļauj nekādu `EgwLoggerProvider` paša reģistrāciju, tāpēc jūsu tiek paņemta bez konkurences:

```java
public final class Slf4jEgwLoggerProvider implements EgwLoggerProvider {
    @Override
    public EgwLogger create() {
        return new Slf4jEgwLogger(LoggerFactory.getLogger("egw-sdk"));
    }
}
```

```
# src/main/resources/META-INF/services/com.tieto.banking.egw.merchantapi.sdk.application.bootstrap.spi.EgwLoggerProvider
com.example.shop.egw.Slf4jEgwLoggerProvider
```

Pārējiem četriem portiem SDK kodola JAR failā reģistrē savus nodrošinātājus, tāpēc jūsu risinājums sacenšas par pirmo vietu klases ceļā, nevis kaut ko aizstāj — SPI reģistrācija tur nav garantēta pārrakstīšana. Šiem portiem dodiet priekšroku 1. vai 3. svirai.

**3. svira — fabrikas apakšklase.** `DefaultEgwClientFactory` ir atvērta paplašināšanai; pārrakstiet `newXxx()` metodi portam, kuru vēlaties aizstāt. Šis ir uzticamais veids, kā nomainīt serializatoru vai šifrētāju:

```java
public class ShopEgwClientFactory extends DefaultEgwClientFactory {
    @Override
    protected Serializer newSerializer() {
        return new ShopJsonbSerializer();
    }
}
```

## PHP

* **Atklāšana** — nodrošinātāju konfigurācijas fails
* **Reģistrācija** — interfeiss → klase kartējums `providers.php` ko nododat fabrikai
* **Ja sakrīt vairāki nodrošinātāji** — nevar notikt; kartējumā ir viena ieraksta uz katru portu

Sākumielāde nolasa interfeisa uz klasi kartējumu no vienkārša PHP konfigurācijas faila. Nodrošinātāju interfeisi atrodas `...\Application\Bootstrap\Spi`: `ApiClientProviderInterface`, `ApiServerProviderInterface`, `DataEncrypterProviderInterface`, `SerializerProviderInterface`, `EgwLoggerProviderInterface`.

**1. svira — fabrikas iestatītāji.** Tāda pati forma kā Java (`connectingWith()`, `listeningWith()`, `loggingWith()`):

```php
$client = (new DefaultEgwClientFactory())
    ->connectingTo($baseApiUri)
    ->authorizingAs(getenv('EGW_CLIENT_ID'), getenv('EGW_CLIENT_SECRET'))
    ->loggingWith(new Psr3EgwLogger($psrLogger))
    ->createEgwClient();
```

**2. svira — jūsu pašu nodrošinātāju fails.** Kopējiet SDK `config/providers.php`nomainiet ierakstus, kurus vēlaties mainīt, un nododiet faila ceļu fabrikas konstruktoram. Nerediģējiet failu mapē `vendor/` — noklusējuma ceļš turp norāda, un Composer to pārrakstīs:

```php
<?php // config/egw-providers.php
// use paziņojumi SPI interfeisiem, iebūvētajiem nodrošinātājiem un jūsu nodrošinātājiem ir izlaisti

return [
    ApiClientProviderInterface::class => GuzzleHttpClientProvider::class,
    ApiServerProviderInterface::class => ReactPhpHttpServerProvider::class,
    DataEncrypterProviderInterface::class => WebTokenDataEncrypterProvider::class,
    SerializerProviderInterface::class => ShopJsonSerializerProvider::class,   // jūsu pārrakstījums
    EgwLoggerProviderInterface::class => Psr3EgwLoggerProvider::class,         // jūsu pārrakstījums
];
```

```php
$factory = new DefaultEgwClientFactory(__DIR__ . '/config/egw-providers.php');
```

Nodrošinātājs ir klase ar publisku konstruktoru bez argumentiem, kas realizē interfeisu:

```php
final class ShopJsonSerializerProvider implements SerializerProviderInterface
{
    public function create(EgwLoggerInterface $logger): SerializerInterface
    {
        return new ShopJsonSerializer();
    }
}
```

**3. svira — fabrikas apakšklase.** Paplašiniet `DefaultEgwClientFactory` (vai `AbstractEgwClientFactory`) un pārrakstiet attiecīgo `newXxx()` metodi tieši tāpat kā Java.

## C\#

* **Atklāšana** — salikuma skenēšana (refleksija pār ielādētajām assemblijām)
* **Reģistrācija** — nav; vienkārši deklarējiet publisku klasi, kas realizē nodrošinātāja interfeisu
* **Ja sakrīt vairāki nodrošinātāji** — uzvar pirmais ielādes secībā assemblijās

Sākumielāde skenē pašreizējā `AppDomain` ielādētās assemblijas, meklējot konkrētas klases, kas realizē nodrošinātāja interfeisus `Egw.Sdk.Application.Bootstrap.Spi`: `IApiClientProvider`, `IApiServerProvider`, `IDataEncrypterProvider`, `ISerializerProvider`, `IEgwLoggerProvider`. Nekas nav jāreģistrē — klases deklarēšana ir reģistrācija. Nodrošinātāji tiek instancēti ar refleksiju, tāpēc tiem vajadzīgs publisks konstruktors bez parametriem.

Žurnalētājs atkal ir tīrākais SPI mērķis, jo SDK neiekļauj noklusējuma `IEgwLoggerProvider`:

```csharp
public sealed class SerilogEgwLoggerProvider : IEgwLoggerProvider
{
    public IEgwLogger Create() => new SerilogEgwLogger(Log.Logger);
}
```

Divas praktiskas piezīmes. Skenēšana redz tikai tās assemblies, kas jau ir ielādētas AppDomain — ja jūsu nodrošinātājs atrodas assembly, kurai vēl nekas nav pieskāries, pirms klienta izveides piespiediet to ielādēt (atsaucieties uz kādu tipu no tās). Un portiem, kuros SDK piegādā noklusējuma nodrošinātāju, jūsu risinājums sacenšas par pirmo vietu assembly ielādes secībā, nevis kaut ko aizstāj — tā nav garantēta pārrakstīšana.

Garantētā pārrakstīšana C# valodā ir tieša instancēšana — `EgwClient`konstruktors pieņem visus piecus portus:

```csharp
var apiClient = new HttpApiClient(myHttpClient, authentication, logger); // jūsu paša HttpClient instance
using var client = new EgwClient(
    baseUri, apiClient, apiServer: null,
    new JoseDataEncrypter(apiClient, jwkEndpoint, logger),
    new JsonSerializer(logger),
    logger);
```

Ņemiet vērā pirmo rindu: `HttpApiClient` pieņem ievadītu `HttpClient`, tāpēc varat piemērot savus apstrādātājus, taimautus un starpniekservera iestatījumus, vispār neimplementējot portu.

## Node.js

Attiecas gan uz JavaScript, gan TypeScript.

* **Atklāšana** — nav; eksplicīts reģistrs
* **Reģistrācija** — izsauciet `registerProvider({...})` pirms klienta izveides
* **Ja sakrīt vairāki nodrošinātāji** — uzvar pēdējā reģistrācija

JS SDK nav netiešas atklāšanas — reģistrācija ir tiešs izsaukums, kas atbilst platformas uz moduļiem orientētajam idiomam. Reģistrs glabā vienu nodrošinātāju katram portam, un `registerProvider()` pieņem daļēju objektu un to apvieno, tāpēc pārrakstāt var tikai to, ko nosaucat:

```ts
// Alpha piezīme: dziļais imports līdz brīdim, kad registerProvider tiks eksportēts no pakotnes saknes — skatīt zemāk
import { registerProvider } from "@tieto/egw-sdk/dist/application/bootstrap/spi/ProviderRegistry.js";

registerProvider({
  loggerProvider: { create: () => new PinoEgwLogger(pino()) }
});

const client = new DefaultEgwClientFactory().create({
  baseUri: new URL("https://sandbox-api.example.com/merchant"),
  authentication: {
    tokenEndpoint: new URL(process.env.EGW_TOKEN_ENDPOINT!),
    clientId: process.env.EGW_CLIENT_ID!,
    clientSecret: process.env.EGW_CLIENT_SECRET!
  },
  jwkUri: new URL(process.env.EGW_JWK_URI!)
});
```

Nodrošinātāji ir vienkārši objektu literāļi ar `create()` metodi — aizvērnes, nevis klases — tāpēc konfigurācijas nodošanai jūsu adapterim nav vajadzīga nekāda ceremonija. Izsauciet `registerProvider()` pirms fabrikas izveides; SDK reģistrē savus noklusējumus, kad tiek ielādēts fabrikas modulis, un jūsu vēlākā reģistrācija tos aizstāj pēc atslēgas.

Pašreizējā alfa versijā `registerProvider` vēl nav pāreksportēts no pakotnes saknes, tāpēc tam vajadzīgs dziļais imports no SDK `ProviderRegistry` moduļa — skatīt [Zināmie ierobežojumi Node.js ātrajam sākumam](/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/atrie-sakumi/node.js-typescript.md).

Darbojas arī tiešā instancēšana — `EgwClient`konstruktors pieņem visus piecus portus, un `AxiosApiClient` pieņem ievadītu `AxiosInstance` (trešais konstruktora parametrs) jūsu starpniekiem, taimautiem un starpniekservera konfigurācijai.

## Saistītās lapas

* [SDK arhitektūra](/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/celvezi/arhitektura-un-paplasinamiba.md) — portu un adapteru dizains, pieci porti un to noklusējuma adapteri
* [Pārskats](/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/parskats.md) — valodu matrica, pakotnes, alfa statuss
* [Kļūdu apstrāde](/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/celvezi/kludu-apstrade.md) — `ECommException` hierarhija, kurā piedalās jūsu adapteri
* [Drošības mehānismi](/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/celvezi/drosibas-mehanismi.md) — ko adapterim jānodrošina (žetonu apstrāde, JWE, žurnālu rediģēšana)
* Ātrie sākumi katrai valodai: [Java](/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/atrie-sakumi/java.md) · [PHP](/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/atrie-sakumi/php.md) · [C#](/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/atrie-sakumi/c-.net.md) · [Node.js](/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/atrie-sakumi/node.js-typescript.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.ecommerce.seb.ee/seb-docs-draft/seb-docs-public-lv/integracija/api-klienta-sdk/celvezi/sdk-adapteru-aizstasana.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
