Rozwiązania w Codenica API

Pracę z rozwiązaniami przez Codenica API zaczynasz od utworzenia klucza w ustawieniach Codenica. Jeśli klucz nie został jeszcze utworzony, otwórz w nowej karcie Codenica API - wprowadzenie. Znajdziesz tam wspólne zasady wydawania kluczy, przechowywania sekretu i uwierzytelniania.

Techniczna nazwa modułu to solutions, a typ pojedynczego obiektu to solution. Rozwiązanie jest wpisem bazy wiedzy. Może zawierać instrukcję, opis sposobu postępowania, odnośniki i pliki pomocnicze. Nie jest obiektem workflow takim jak Zgłoszenie, Zmiana, Problem albo Wydanie, dlatego nie przenoś do niego ich pól statusu, priorytetu czy eskalacji.

W kolejnych krokach znajdziesz adres, zakresy, context, schema, pola, listy, filtrowanie, tworzenie, idempotencję, ETag, edycję, batch, relacje z Problemami, relacje autorów i edytorów, pliki, ocenę oraz usuwanie.

Przykłady wykorzystują prefix PUBLIC-API-SOLUTION-20260905134845. W swojej integracji zastąp go własnym identyfikatorem, a adresy e-mail, identyfikatory i wartości pól dopasuj do danych w swojej bazie.


Rozwiązania - adres API i wybór instalacji

Wszystkie trasy dotyczące rozwiązań zaczynają się od:

{BASE_URL}/api/v1/solutions

BASE_URL oznacza adres serwera Codenica bez końcówki /api/v1. W wersji Cloud użyj publicznej domeny przypisanej do właściwej firmy:

export BASE_URL="https://twoja-firma.codenica.com"

W domyślnej instalacji On-Premise adres lokalnie rejestrowany przez program Codenica Discovery to:

export BASE_URL="http://codenica.local:5150"

Jeżeli administrator udostępnił instalację pod firmową domeną, przez reverse proxy, z HTTPS albo na innym porcie, użyj dokładnego adresu przekazanego dla tej instalacji:

export BASE_URL="https://api.twoja-firma.example"

Nie używaj localhost, jeśli program integrujący działa na innym komputerze niż API. Właściwa baza danych jest wybierana na podstawie adresu, z którym łączy się integracja. Nie przekazuj tenantId w body ani w query stringu.


Rozwiązania - klucz API i limity licencyjne

Klucz API utwórz w Codenica w miejscu Ustawienia - API - API Keys. Sekret jest pokazywany tylko raz, bezpośrednio po utworzeniu albo obróceniu klucza. Zapisz wtedy Client ID i Client Secret w bezpiecznym magazynie używanym przez integrację.

Codenica API jest dostępne dla licencji Plus i Enterprise. Licencja Plus pozwala utworzyć do 50 aktywnych kluczy, a Enterprise do 100. Starter nie udostępnia Codenica API. Dla każdej aplikacji i środowiska utwórz osobny klucz, aby można było niezależnie ograniczyć jego zakresy, obrócić sekret albo usunąć dostęp.

Licencja
Dostęp do API
Maksymalna liczba aktywnych kluczy
Starter
Brak
0
Plus
Tak
50
Enterprise
Tak
100

Usunięcie klucza usuwa jego rekord i zwalnia miejsce w limicie. Wygaśnięcie daty aktywności zatrzymuje uwierzytelnianie, ale nie zastępuje porządkowania listy kluczy. Jeżeli przy tworzeniu nie ustawisz daty końcowej, domyślny okres ważności wynosi 90 dni. Maksymalny czas aktywności jednego klucza to 5 lat.


Rozwiązania - uwierzytelnianie i bezpieczne żądania

Każde żądanie Codenica API uwierzytelniaj dwoma nagłówkami klucza:

export CLIENT_ID="cna_twoj_client_id"
export CLIENT_SECRET="cns_twoj_client_secret"

curl --request GET --url "$BASE_URL/api/v1/solutions?page=1&pageSize=25" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Zewnętrzna integracja nie potrzebuje JWT administratora ani ciasteczek z panelu Codenica. Klucza nie umieszczaj w repozytorium, kodzie dostarczanym do przeglądarki, adresie URL, historii poleceń ani logach. Poza lokalnymi testami korzystaj z HTTPS.

W odpowiedzi zachowuj meta.requestId. Jest potrzebny do diagnozowania konkretnego żądania, ale nie zastępuje identyfikatora rozwiązania i nie powinien być używany jako sekret.


Rozwiązania - sprawdzenie kontekstu połączenia

Przed pierwszym zapisem pobierz kontekst. Dzięki temu sprawdzisz, czy adres prowadzi do właściwej bazy, a wybrany klucz ma potrzebne zakresy:

curl --request GET --url "$BASE_URL/api/v1/context" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

W odpowiedzi zweryfikuj:

  • data.apiVersion i data.contractVersion;
  • data.tenant.id, data.tenant.name i data.tenant.resolvedDomain;
  • data.caller.authentication równe api_key;
  • obecność solutions w data.capabilities.resources;
  • zakresy przypisane do klucza;
  • limity stron, batch, plików i żądań.

Jeżeli kontekst wskazuje inną bazę albo nie zawiera wymaganego zakresu, zatrzymaj integrację i popraw adres lub klucz. Zakresów nie można nadać pojedynczym żądaniem.


Rozwiązania - zakresy uprawnień

Pełna obsługa rozwiązań wymaga zakresów odpowiadających wykorzystywanym operacjom:

solutions:read
solutions:write
solutions:delete
solutions:schema
solutions:stats
solutions:relationships:read
solutions:relationships:write
solutions:users:read
solutions:files:read
solutions:files:write
solutions:technical:read
solutions:technical:write
solutions:rating:write
problems:read
users:read

Do zwykłego odczytu wystarczy solutions:read. Schema i statystyki wymagają osobnych zakresów solutions:schema oraz solutions:stats. Odczyt relacji, autorów, edytorów i plików wymaga odpowiednich zakresów odczytu. Operacje zapisu mają analogiczne zakresy :write.

  • solutions:relationships:read i solutions:relationships:write dotyczą relacji obiektowej z Problemami;
  • solutions:users:read oraz users:read dotyczą odczytu autorów i edytorów, zależnie od konfiguracji;
  • solutions:files:read i solutions:files:write dotyczą listowania, wysyłania, dołączania i usuwania plików;
  • solutions:rating:write jest potrzebny do zapisania lub wycofania własnej oceny;
  • zakresy techniczne stosuj wyłącznie wtedy, gdy integracja korzysta z pól oznaczonych w schema jako techniczne.

Zakres problems:read jest potrzebny wtedy, gdy integracja wyszukuje Problem będący celem relacji. Rozwiązania nie tworzą ani nie usuwają tego Problemu. Przyznawaj zakresy zgodnie z zasadą najmniejszych uprawnień.


Rozwiązania - schema i pola

Schema pokazuje, które pola można odczytać i zapisać w konkretnej bazie. Pobierz je przed przygotowaniem formularza lub mapowania:

curl --request GET --url "$BASE_URL/api/v1/solutions/schema" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Schema zwraca między innymi data.itemType, data.fields oraz data.relationshipTargets. Stała wartość itemType dla tego modułu to solution. Dla każdego pola sprawdź readable, writable, required, technical, unique oraz maxLength. Nie buduj mapowania wyłącznie na podstawie przykładu z tego artykułu.


Rozwiązania - pola zapisywalne i systemowe

Przy tworzeniu trzeba dostarczyć title oraz category. Publiczny katalog pól biznesowych obejmuje:

customId
title
description
location
department
type
tags
section
category
visibility

Maksymalne długości określone w publicznym schemacie:

Pole
Maksymalna długość
customId
500
title
1000
description
10000
location
300
department
300
type
300
tags
2000
section
300
category
300
visibility
100

Dane tylko do odczytu nie należą do zwykłego payloadu PATCH:

helpful
notHelpful
totalFiles
creator
updater
importId
importSource
dateImported

id i itemType są częścią koperty zasobu. dateCreated i dateUpdated są danymi systemowymi. Nie próbuj zmieniać ich przez attributes.


Rozwiązania - podstawowe endpointy

Najważniejsze trasy modułu solutions to:

GET    /api/v1/solutions
POST   /api/v1/solutions
GET    /api/v1/solutions/{SOLUTION_ID}
PATCH  /api/v1/solutions/{SOLUTION_ID}
DELETE /api/v1/solutions/{SOLUTION_ID}
GET    /api/v1/solutions/schema
GET    /api/v1/solutions/stats
GET    /api/v1/solutions/values
GET    /api/v1/solutions/{SOLUTION_ID}/relationships
POST   /api/v1/solutions/{SOLUTION_ID}/relationships
POST   /api/v1/solutions/{SOLUTION_ID}/relationships:batch
GET    /api/v1/solutions/{SOLUTION_ID}/user-relationships
GET    /api/v1/solutions/{SOLUTION_ID}/files
POST   /api/v1/solutions/{SOLUTION_ID}/files
GET    /api/v1/solutions/{SOLUTION_ID}/files/{FILE_ID}/content
POST   /api/v1/solutions/{SOLUTION_ID}/rating

Każda trasa wymaga uwierzytelnienia. Operacje zmieniające dane wymagają również Idempotency-Key, a operacje chronione wersją wymagają aktualnego If-Match. Konkretne wymagania sprawdzaj w schema i w odpowiedzi context.


Rozwiązania - listowanie i paginacja

Lista jest stronicowana. Przykładowe żądanie pobiera pierwszą stronę i sortuje rozwiązania po tytule:

curl --request GET --url "$BASE_URL/api/v1/solutions?itemType=solution&page=1&pageSize=25&sort=title&direction=asc" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

W odpowiedzi znajdziesz między innymi:

data.items
data.page
data.pageSize
data.totalItems
data.totalPages
data.hasNextPage

Pobieraj kolejne strony, dopóki data.hasNextPage ma wartość true. Nie zakładaj, że liczba rekordów zwrócona na pierwszej stronie oznacza kompletną listę. pageSize dopasuj do limitu zwróconego w context i nie ustawiaj go automatycznie na maksymalną wartość.


Rozwiązania - wyszukiwanie, filtry i sortowanie

Do filtrowania możesz użyć między innymi ids, customId, title, description, location, department, type, tags, section, category, visibility, helpful, notHelpful, createdAfter, createdBefore, updatedAfter i updatedBefore. Wartości zawierające spacje, przecinki lub znaki specjalne koduj w URL.

Przykład listy rozwiązań z kategorii Public API:

curl --request GET --url "$BASE_URL/api/v1/solutions?category=Public%20API&page=1&pageSize=25&sort=title&direction=asc" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Parametr search przeszukuje tekstowe dane rozwiązania, między innymi tytuł, opis, typ, tagi, sekcję, kategorię, widoczność, lokalizację i dział:

curl --request GET --url "$BASE_URL/api/v1/solutions?search=backup&page=1&pageSize=25" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Sortuj po polu udostępnionym przez schema. Nie zakładaj, że każde pole widoczne w formularzu może być użyte jako parametr sort.


Rozwiązania - projekcja pól i dołączanie danych

Jeżeli integracja potrzebuje tylko części danych, ogranicz odpowiedź przez fields:

curl --request GET --url "$BASE_URL/api/v1/solutions?customId=PUBLIC-API-SOLUTION-20260905134845-SOURCE&fields=title%2Ccategory%2Cvisibility&page=1&pageSize=10" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Pojedynczy rekord możesz pobrać razem z plikami, relacjami i informacjami o autorze oraz edytorze:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}?fields=title%2Ccategory%2Cdescription%2Cvisibility&include=files%2Crelationships%2Cusers" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Dozwolone wartości include to files, relationships i users. Każda z nich wymaga odpowiedniego zakresu. fields=* pozwala zażądać wszystkich dostępnych pól, ale pola techniczne pojawią się dopiero przy odpowiednim zakresie technicznym.


Rozwiązania - statystyki i wartości pól

Statystyki służą do policzenia rekordów i grupowania ich po polu:

curl --request GET --url "$BASE_URL/api/v1/solutions/stats?field=category&limit=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Odpowiedź zawiera między innymi total, field i tablicę values. Wartość category=Public API może służyć jako wygodny filtr danych demonstracyjnych.

Aby pobrać odrębne wartości pola, użyj trasy values:

curl --request GET --url "$BASE_URL/api/v1/solutions/values?field=visibility&search=internal&limit=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

limit musi mieścić się w zakresie obsługiwanym przez API. Aktualny limit dla tych endpointów wynosi od 1 do 500. Żądania statystyk i wartości są tylko do odczytu i nie zmieniają rozwiązań.


Rozwiązania - tworzenie rekordu

Przy tworzeniu umieść techniczny typ solution w body, a pola zapisywalne w attributes. Minimalny zapis wymaga title i category:

{
  "itemType": "solution",
  "attributes": {
    "customId": "PUBLIC-API-SOLUTION-20260905134845-SOURCE",
    "title": "PUBLIC-API-SOLUTION-20260905134845 integration knowledge article",
    "description": "Created through the Codenica Public API Solutions flow.",
    "location": "Warsaw",
    "department": "IT",
    "type": "How-to",
    "tags": "public-api,solution,integration",
    "section": "Integrations",
    "category": "Public API",
    "visibility": "team"
  }
}

Zapisz treść jako solution-create.json i wyślij:

curl --request POST --url "$BASE_URL/api/v1/solutions" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-solution-create-20260905134845" \
  --data-binary @solution-create.json

Prawidłowe utworzenie zwraca 201 Created. Odpowiedź zawiera UUID rozwiązania, data.itemType=solution, zapisane atrybuty, daty systemowe i data.meta.etag. Najlepiej pozostawić nadanie id systemowi.


Rozwiązania - bezpieczne ponowienie tworzenia

Jeżeli po wysłaniu żądania wystąpi timeout albo błąd sieci, nie twórz od razu drugiego rekordu. Powtórz identyczne body z tym samym kluczem Idempotency-Key:

curl --request POST --url "$BASE_URL/api/v1/solutions" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-solution-create-20260905134845" \
  --data-binary @solution-create.json

Ponowienie może zwrócić 200 albo 201, ale powinno wskazać ten sam rekord. Nie używaj tego samego klucza dla innego body ani dla innej intencji biznesowej.


Rozwiązania - odczyt i ETag

Przed edycją, zmianą relacji, operacją na pliku albo oceną pobierz aktualny rekord:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}?fields=title%2Ccategory%2Cdescription%2Cvisibility%2Ctags" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

ETag jest zwracany w nagłówku HTTP oraz w kopercie odpowiedzi:

ETag: "..."
data.meta.etag: "..."
meta.etag: "..."

Wartość z odpowiedzi zapisz jako CURRENT_ETAG i użyj jej w następnym żądaniu zmieniającym dane. Po udanej zmianie pobierz nowy ETag. Stary ETag przestaje być aktualny.


Rozwiązania - częściowa edycja z If-Match

PATCH zmienia tylko pola przekazane w attributes. Przykład aktualizuje opis, widoczność, tagi i sekcję:

{
  "attributes": {
    "description": "Updated through the Solutions Public API flow.",
    "visibility": "internal",
    "tags": "public-api,solution,updated",
    "section": "Updated integrations"
  }
}
curl --request PATCH --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-update-20260905134845" \
  --data-binary @solution-update.json

Aktualizacja zakończona powodzeniem zwraca 200 oraz nowy ETag. Nie wysyłaj w zwykłym PATCH pól tylko do odczytu ani danych technicznych obsługiwanych przez osobne endpointy.


Rozwiązania - nieaktualny ETag i brak If-Match

Jeżeli dwa procesy pobrały to samo rozwiązanie, a jeden z nich zapisał zmianę wcześniej, drugi ma stary ETag. Próba zapisu z taką wartością musi zostać odrzucona:

HTTP 412 Precondition Failed
code: if_match_failed

Po HTTP 412 ponownie pobierz rekord, zdecyduj, jak połączyć zmiany, i dopiero wtedy wyślij nowy PATCH. Żądanie odrzucone z powodu starego ETag-u nie powinno zmienić danych.

Mutacja bez wymaganego nagłówka:

HTTP 428 Precondition Required
code: if_match_required

Nie omijaj tego wymagania przez wysłanie pustej wartości. Najpierw odczytaj aktualny rekord i użyj dokładnego ETag-u.


Rozwiązania - operacje batch

Batch pozwala wykonać kilka niezależnych operacji w jednym żądaniu. Przykład tworzy dwa rozwiązania:

{
  "items": [
    {
      "operation": "create",
      "create": {
        "itemType": "solution",
        "attributes": {
          "customId": "PUBLIC-API-SOLUTION-BATCH-A",
          "title": "Batch Solution A",
          "category": "Public API",
          "description": "Batch-created Solution A",
          "type": "How-to",
          "visibility": "team"
        }
      }
    },
    {
      "operation": "create",
      "create": {
        "itemType": "solution",
        "attributes": {
          "customId": "PUBLIC-API-SOLUTION-BATCH-B",
          "title": "Batch Solution B",
          "category": "Public API",
          "description": "Batch-created Solution B",
          "type": "Reference",
          "visibility": "team"
        }
      }
    }
  ]
}
curl --request POST --url "$BASE_URL/api/v1/solutions:batch" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-solution-batch-create-20260905134845" \
  --data-binary @solutions-batch.json

Przy edycji element zawiera operation=update, id, ifMatch i update.attributes:

{
  "items": [
    {
      "operation": "update",
      "id": "{SOLUTION_A_ID}",
      "ifMatch": "{SOLUTION_A_ETAG}",
      "update": {
        "attributes": {
          "description": "Batch update A"
        }
      }
    }
  ]
}

Przy usuwaniu element zawiera operation=delete, id i aktualne ifMatch. Odpowiedź może zawierać succeeded i failed, a przy częściowym wyniku także HTTP 207 Multi-Status. Sprawdzaj każdy element osobno. Batch nie jest transakcją.


Rozwiązania - relacje wyłącznie z Problemami

Rozwiązania obsługują relacje obiektowe wyłącznie z modułem Problemów. Typowym celem zwracanym w schema jest:

targetDataSet: problems
targetItemType: problem

Nie zakładaj, że rozwiązanie można przez te endpointy połączyć z Zasobem, Dokumentem, Klientem, Dostawcą, Zgłoszeniem, Zmianą albo Wydaniem. Jeżeli schema konkretnej bazy nie zwraca celu, integracja nie powinna go używać.

Najpierw znajdź czytelny Problem, korzystając z publicznego pola sortowania:

curl --request GET --url "$BASE_URL/api/v1/problems?itemType=problem&page=1&pageSize=10&sort=subject&direction=asc" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

W demonstracyjnym przebiegu użyto Problemu o identyfikatorze 9793181f-a225-4928-8062-80d6e69cb792. Własna integracja powinna wyszukać aktualny cel, a nie traktować tego UUID-u jako stałej.


Rozwiązania - dodawanie, odczyt i usuwanie relacji

Body bezpośredniego dodania relacji może wyglądać tak:

{
  "targetId": "9793181f-a225-4928-8062-80d6e69cb792",
  "targetDataSet": "problems",
  "targetItemType": "problem",
  "relationshipType": "related"
}

Przed każdą mutacją pobierz aktualny ETag rozwiązania:

curl --request POST --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/relationships" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-problem-relation-add-20260905135119" \
  --data-binary @solution-problem-relation.json

Prawidłowe dodanie zwraca 201 Created. Relację odczytasz osobną trasą:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/relationships?targetDataSet=problems&targetItemType=problem&page=1&pageSize=50" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Usunięcie bezpośrednie wymaga aktualnego ETag-u oraz identyfikatora celu:

curl --request DELETE --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/relationships/problems/9793181f-a225-4928-8062-80d6e69cb792?relationshipType=related" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-problem-relation-delete-20260905135119"

Odpowiedź usunięcia zwraca 200 i data=true. Po operacji pobierz kolekcję ponownie.


Rozwiązania - relacje batch z Problemami

Do jednoczesnego dodawania i usuwania użyj trasy relationships:batch:

{
  "add": [
    {
      "targetId": "9793181f-a225-4928-8062-80d6e69cb792",
      "targetDataSet": "problems",
      "targetItemType": "problem",
      "relationshipType": "related"
    }
  ],
  "remove": []
}
curl --request POST --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/relationships:batch" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-problem-relation-batch-add-20260905135119" \
  --data-binary @solution-problem-relation-batch.json

Aby usunąć relację przez batch, pozostaw puste add i przenieś element do remove:

{
  "add": [],
  "remove": [
    {
      "targetId": "9793181f-a225-4928-8062-80d6e69cb792",
      "targetDataSet": "problems",
      "targetItemType": "problem",
      "relationshipType": "related"
    }
  ]
}

Odpowiedź zawiera liczniki added, removed i skipped. Po dodaniu sprawdź added=1, a po usunięciu removed=1. Przed każdym kolejnym zapisem używaj świeżego ETag-u.


Rozwiązania - relacje autorów i edytorów

Relacje użytkowników w tym module są metadanymi autorstwa i ostatniej edycji. Dopuszczalne typy to author i editor:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/user-relationships?page=1&pageSize=50" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Przykładowy element może zawierać:

{
  "targetId": "8e9cbff3-340f-41f6-97ec-6997bb915829",
  "targetDataSet": "users",
  "relationshipType": "author",
  "displayName": "Fred Savage",
  "email": "[email protected]",
  "role": "Administrator"
}

Relacje author i editor są odczytywane z pól autora i edytora rozwiązania. Publiczny moduł Rozwiązań nie udostępnia dla nich endpointu dodawania, edycji ani usuwania. Nie próbuj tworzyć typów agent, watcher, appUserRequester lub clientRequester, ponieważ należą do innych obiektów.


Rozwiązania - pliki

Przed każdą operacją na pliku odczytaj aktualne rozwiązanie i jego ETag. Lista plików:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/files?page=1&pageSize=100" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Element listy zawiera między innymi id, name, fileName, contentType, size, width, height, relationshipType, isMain oraz downloadUrl. Dla Rozwiązań isMain jest zawsze równe false. Moduł nie udostępnia endpointu set-main, dlatego nie próbuj ustawiać głównego pliku.

Wysłanie pliku wymaga formatu multipart/form-data:

curl --request POST --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/files?relationshipType=documentation" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-file-20260905134845" \
  --form "[email protected];type=text/plain"

Prawidłowy upload zwraca 201 Created i zasób pliku. W przykładzie użyto pliku solution-one.txt typu text/plain. Upload zmienia wersję rozwiązania, dlatego po operacji pobierz nowy ETag.

Treść pobierzesz przez uwierzytelnioną ścieżkę:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/files/{FILE_ID}/content" \
  --header "Accept: application/octet-stream" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --output solution-one-downloaded.txt

downloadUrl traktuj jako ścieżkę API, a nie jako publiczny, anonimowy link. Jeżeli plik istnieje już w tej samej przestrzeni plików, możesz dołączyć go do innego rozwiązania:

curl --request POST --url "$BASE_URL/api/v1/solutions/{TARGET_SOLUTION_ID}/files/{FILE_ID}?relationshipType=manual" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $TARGET_CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-file-attach-20260905134845"

Przy dołączaniu użyj ETag-u rozwiązania docelowego, nie rekordu, z którego plik pochodzi. Usunięcie pliku wymaga aktualnego ETag-u:

curl --request DELETE --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/files/{FILE_ID}" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-file-delete-20260905134845"

Po otrzymaniu 200 odczytaj listę plików, aby potwierdzić, że plik nie jest już zwracany.


Rozwiązania - ocena przydatności

Ocena jest osobną mutacją. Możesz oznaczyć rozwiązanie jako pomocne, jako niepomocne albo wycofać własną ocenę:

{
  "rating": 1
}
  • 1 - pomocne;
  • 0 - niepomocne;
  • -1 - wycofanie własnej oceny.

Oznaczenie jako pomocne:

curl --request POST --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/rating" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-rating-helpful-20260905134845" \
  --data '{"rating":1}'

Wycofanie własnej oceny:

curl --request POST --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/rating" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $RATING_CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-rating-reset-20260905134845" \
  --data '{"rating":-1}'

Obie operacje wymagają ETag-u. Odpowiedź zawiera aktualne liczniki helpful i notHelpful oraz nową wersję ETag-u. Pól helpful i notHelpful nie aktualizuj przez zwykły PATCH.


Rozwiązania - usuwanie rekordu

Usuwanie jest nieodwracalne, dlatego najpierw odczytaj rekord i pobierz aktualny ETag:

curl --request DELETE --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-delete-20260905134845"

Prawidłowa odpowiedź to 200 z data=true. Następnie wykonaj kontrolny GET oraz sprawdź filtrowaną listę:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

curl --request GET --url "$BASE_URL/api/v1/solutions?customId=PUBLIC-API-SOLUTION-20260905134845-SOURCE&page=1&pageSize=10" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Po usunięciu pojedynczy GET zwraca 404 Not Found z kodem solution_not_found, a filtrowana lista powinna mieć totalItems=0. Relacje i pliki warto wcześniej zweryfikować lub uporządkować przez integrację.


Rozwiązania - błędy, limity i bezpieczeństwo

Błędy API używają formatu Problem Details. Najważniejsze pola to status, code, detail i requestId:

{
  "type": "https://docs.codenica.com/errors/if_match_failed",
  "title": "Precondition failed.",
  "status": 412,
  "detail": "The supplied ETag is not the current solution version.",
  "instance": "/api/v1/solutions/{SOLUTION_ID}",
  "code": "if_match_failed",
  "requestId": "..."
}
HTTP
Znaczenie
Reakcja
400
niepoprawne pole, filtr, body albo relacja
popraw żądanie zgodnie ze schema
401
brak lub nieprawidłowe uwierzytelnienie
sprawdź adres i klucz
403
brak zakresu albo dostępu do bazy
zmień zakres lub uprawnienia użytkownika
404
rozwiązanie, Problem, plik albo cel relacji nie istnieje lub jest niewidoczny
zweryfikuj UUID i adres instalacji
409
konflikt identyfikatora albo istniejącej relacji
odczytaj stan i zdecyduj, czy konflikt jest oczekiwany
412
nieaktualny ETag
pobierz rekord i nowy ETag
413
plik lub body jest zbyt duży
sprawdź limit w context
422
wartość pola albo istniejący flow odrzucił operację
przeanalizuj code i detail
428
brak If-Match albo Idempotency-Key
dodaj właściwy nagłówek
429
przekroczono limit żądań
zastosuj backoff i Retry-After
500
błąd serwera
zachowaj requestId i nie powtarzaj mutacji bez idempotencji

Odczytuj nagłówki X-RateLimit-Limit i X-RateLimit-Remaining. Po 429 respektuj Retry-After, jeśli został zwrócony, i stosuj kontrolowane ponowienia z rosnącym opóźnieniem.

Dane rozwiązań mogą zawierać informacje operacyjne i wewnętrzne instrukcje. Minimalizuj zakres pól, stosuj HTTPS i ogranicz dostęp klucza do konkretnej bazy danych. Client ID i Client Secret przechowuj poza kodem źródłowym, nie zapisuj ich w logach i nie wysyłaj w zgłoszeniach.


Rozwiązania - kolejność pracy integracji

  1. Ustal rzeczywisty adres Cloud albo On-Premise i ustaw BASE_URL.
  2. Utwórz osobny klucz dla aplikacji i środowiska w Ustawienia - API - API Keys.
  3. Nadaj tylko zakresy potrzebne do odczytu, zapisu, relacji, plików lub oceny.
  4. Wyślij GET /api/v1/context i sprawdź bazę, caller, zakresy oraz limity.
  5. Pobierz GET /api/v1/solutions/schema i zbuduj mapowanie pól.
  6. Pobierz listę albo wyszukaj istniejące rozwiązanie.
  7. Utwórz rekord przez POST z unikalnym Idempotency-Key.
  8. Zapisz UUID i ETag z odpowiedzi.
  9. Przed każdą edycją, relacją, operacją plikową, oceną lub usunięciem odśwież ETag.
  10. Relację obiektową twórz wyłącznie do Problemu zwróconego przez schema.
  11. Relacje autorów i edytorów tylko odczytuj, ponieważ nie mają publicznych endpointów zapisu.
  12. Po każdej mutacji odczytaj wynik i zapisz nowy ETag.
  13. Przy 412 pobierz rekord, rozstrzygnij konflikt i dopiero wtedy ponów operację.
  14. Przy batch sprawdź wynik każdej pozycji, ponieważ częściowy błąd nie cofa sukcesów.
  15. Przed usunięciem potwierdź aktualny ETag, a po operacji sprawdź HTTP 404 i pustą listę po customId.

Taki przebieg pozwala synchronizować rozwiązania bazy wiedzy z innym systemem bez opierania integracji na założeniach o polach, relacjach lub danych systemowych.