# Dokumentacja CrossyWord
## Spis treści
1. [Wstęp](#wstęp)
2. [Elementy składowe systemu](#elementy-składowe-systemu)
1. [Opis architektury](#opis-architektury)
2. [Schemat architektury systemu](#schemat-architektury-systemu)
3. [Aplikacja użytkownika](#aplikacja-użytkownika)
4. [Mikroserwisy](#mikroserwisy)
1. [CrosswordGenerator](#crosswordgenerator)
2. [WordSuggestor](#wordsuggestor)
3. [UserDataService](#userdataservice)
4. [AuthService](#authservice)
5. [Frontend](#frontend)
3. [Środowisko chmurowe](#środowisko-chmurowe)
1. [Platforma GCP](#platforma-gcp)
2. [Kubernetes](#kubernetes)
3. [Istio](#istio)
4. [Domena i certyfikat](#domena-i-certyfikat)
4. [Konfiguracja CI/CD](#konfiguracja-ci/cd)
5. [Interfejsy mikroserwisów](#interfejsy-mikroserwisów)
1. [Accounts API v1.0.0](#accounts-api)
2. [CrosswordGenerator v1.0.0](#crosswordgenerator)
3. [Crosswords API v1.0.0](#crosswords-api)
4. [OAuth 2.0 API v1.0.0](#oauth-2-0-api)
5. [Word suggestor v0.0.1](#word-suggestor)
6. [User Profiles API v1.0.0](#user-profiles-api)
## Wstęp
CrossyWord to aplikacja pozwalająca na automatyczne generowanie krzyżówek. Głównymi grupami odbiorczymi produktu są:
- szkoły językowe,
- nauczyciele języków obcych,
- autorzy książek do nauki języków.
Rozwiązanie występuje w dwóch wersjach:
- Podstawowa (darmowa): pozwala wygenerować krzyżówkę z podanych słówek oraz ich definicji.
- Premium (płatna): funkcje z wersji podstawowej + pozwala na generowanie krzyżówek ze słówek wprowadzonych do bazy przez innych użytkowników (w szczególności korzystających z wersji podstawowej). Wersja premium udziela również dostępu do usługi poprzez API, dzięki czemu proces można w pełni zautomatyzować i zintegrować z innymi rozwiązaniami.
CrossyWord dostępne jest w modelu Software as a Service.
## Elementy składowe systemu
### Opis architektury
Zastosowano architekturę mikroserwisową
- Mikroserwisy komunikują się ze sobą na drodzę zapytań http
- Mikroserwisy są bezstanowe
- Bazy danych należą do pojedynczego mikroserwisu
- Pojedynczy mikroserwis może być zaimplementowany w dowolnej technologii
- Aplikacja internetowa komunikuje się z serwisami za pośrednictwem Gateway, która odpowiedzialny jest za przekierowania zapytania do właściwego punktu końcowego.
### Schemat architektury systemu

### Aplikacja użytkownika
Aplikacja użytkownika została stworzona z wykorzystaniem biblioteki React.js oraz Redux do zarządzania stanem aplikacji.
### Mikroserwisy
<h4 id="crossword_generator">CrosswordGenerator</h4>
*Szczegółowa dokumentacja API znajduje się w rozdziale: [CrosswordGenerator v1.0.0](#crosswordgenerator)*
- Generowanie przestrzennego rozkładu słów w krzyżówce.
- Stosuje algorytm maksymalizujący liczbę skrzyżowań.
- Krzyżówki generowane są w jednym z następujących formatów:
- JSON
- PDF
- SVG
- Język programowania: **Java**
- Architektura mikroserwisu:
- Projekt zrealizowany jest w architekturze portów i adapterów (hexagonalnej)
- Oddzielenie kodu domenowego od "zewnętrznego świata", tj. komunikacji z bazą danych oraz z innymi mikroserwisami za pomocą REST
- Porty wejściowe reprezentują funkcjonalności oferowane przez domenę dla zewnętrznego świata, a są to:
- generowanie krzyżówki z zadanych słówek w formacie JSON
- exportowanie wygenerowanej krzyżówki do formatu PDF
- exportowanie wygenerowanej krzyżówki do formatu SVG
- Porty wyjściowe reprezentują funkcjonalność, która jest wymagana przez domenę do jej poprawnego działania w skład której wchodzą:
- implementacja warstwy dostępu do bazy danych
- komunikacja z innymi mikroserwisami
- Adaptery wejściowe korzystają z portów wchodzących domeny w celu dostarczenia funkcjonalności do użytkownika
- Adaptery wyjściowe implementują porty (interfejsy) wyjściowe zdefiniowane w domenie i realizują potrzebne jej zależności:
- warstwa persystencji w prostych przypadkach implementowana jest automatycznie przez Spring Data, bardziej złożone zapytania wymagają ręcznej implementacji z wykorzystaniem `MongoTemplate`.
- komunikacja REST-owa z innymi mikroserwisami zrealizowana jest z wykorzystaniem biblioteki OpenFeign, umożliwiającej podejście deklaratywne
- Struktura wygenerowanej krzyżówki w formacie JSON:
```json
{
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}
```
##### Algorytm
Dopasowywanie kolejnych słów oparte jest na dwóch strategiach. Pierwsza ze strategii iteruje po już zajętych polach zaczynając od pól dodanych najwcześniej. Po dodaniu nowego słowa nowe dostępne pola dodawane sa do kolejki. Jeżeli pierwsza strategia zawiedzie używana jest druga strategia próbująca w sposób *bruteforce* wstawić słowo w każde pole krzyżówki poruszając się spiralnym ruchem od środka.
##### Formaty krzyżówek
Pod każdym z trzech endpointów można otrzymać krzyżówkę w jednym z trzech formatów.
###### JSON
Krzyżówki wygenerowane w formacie JSON służą do przekazywania jej między aplikacją użytkownika a mikroserwisami oraz do przechowywania w bazie danych.
###### PDF
Na podstawie pliku JSON opisującego krzyżówkę, serwis umożliwia wygenerowanie pliku PDF z krzyżówką. Wygenerowany plik składa się z dwóch stron. Na każdej z nich znajduje się krzyżówka wraz z opisami haseł. Na pierwszej stronie krzyżówka jest nieuzupełniona, na drugiej zaś jest uzupełniona.
Plik pdf jest przystosowany do wydrukowania na zajęcia ze studentami.
###### SVG
Na podstawie pliku JSON opisujacego krzyżówkę, serwis umożliwia wygenerowanie pliku ZIP, w skład którego wchodzą dwa pliki SVG i jeden plik tekstowy. Jeden z plików SVG zawiera krzyżówkę nieuzupełnioną, drugi zaś uzupełnioną. Plik tekstowy zawiera opisy haseł.
Plik svg to grafika wektorowa i posiada przezroczyste tło przez co nadaje się dobrze do dalszego przetwarzania lub do umieszczenia na innej większej grafice.
#### Suggestor
*Szczegółowa dokumentacja API znajduje się w rozdziale: [Suggestor v0.0.1](#word-suggestor)*
Użytkownik premium może skorzystać z komponentu, który wykorzystuje zewnętrzne api do tworzenia nowych krzyżówek. Aby z niego skorzystać musi być zalogowany. Serwis bowiem komunikuje się z AuthService, który sprawdza czy użytkownik jest uwierzytelniony.
Sam komponent umożliwia sprecyzowanie kategorii szukanych słówek. Wykorzystując api "https://www.wordsapi.com/" pobierane są słówka w języku angielskim o danej kategorii. Użytkownik w tym momencie ma możliwość zaznaczanie dowolnej ilości słówek, które chce umieścić w krzyżówce. Następnie ma do wyboru albo dalsze poszukiwanie kolejnych słówek wpisując kolejne kategorie lub wygenerowanie krzyżówki. Po wybraniu drugiej opcji wykorzystywane jest kolejne zewnętrzne API ("https://dictionaryapi.dev/"), które dla wszystkich haseł pobiera ich definicje. Jeśli API nie znajdzie definicji, to pole zostanie puste.
WordsAPI jest darmowe do 2500 żądań dziennie - na potrzeby aktualnej aplikacji ta ilość jest wystarczająca.
DictionaryAPI jest w całości darmowe.
Akutalnie serwis proponuje jedynie słówka w języku angielskim. Dobrym pomysłem byłoby w przyszłości zagwarantowanie obsługi w innych językach.
Język programowania: Java 14
#### UserDataService
*Szczegółowa dokumentacja API znajduje się w rozdziałach: [User Profiles API v1.0.0](#user-profiles-api) oraz [Crosswords API v1.0.0](#crosswords-api)*
Mikroserwis obsługujący zasoby użytkownika. Wykorzystując bazę MongoDB, o nazwie user-data-db, zarządza krzyżówkami, które posiadają użytkownicy. Obsługuje dodawanie ich do konta, pobieranie już istniejących, pobieranie konkretnej krzyżówki, usuwanie oraz aktualizację. Baza danych posiada dwie tabele:
- users -- tabela przechowująca identyfikator użytkownika oraz identyfikatory posiadanych przez niego krzyżówek
- crosswords -- tabela przechowująca krzyżówki wraz z ich identyfikatorami, ilością kolumn, wierszy, ich nazwą oraz listą obiektów słówek. Każde słówko zawiera: słowo, jego opis, pozycję oraz orientację (pozioma/pionowa). Pozycja określa kolumnę oraz wiersz w jakim zaczyna się słówko w krzyżówce.
Użytkownicy w tabeli users są tworzeni podczas rejestracji. Jest to wykonywane automatycznie przy użyciu serwisu AuthService, który wysyła odpowiednie żądanie do UserDataService.
Aby móc korzystać z serwisu, użytkownik musi mieć aktualny token uzyskany z AuthService, który przekazuje w headerze zapytania.
Język programowania: Java 14
#### AuthService
*Szczegółowa dokumentacja API znajduje się w rozdziałach: [Accounts API v1.0.0](#accounts-api) oraz [OAuth 2.0 API v1.0.0](#oauth-2-0-api)*
Mikroserwis obsługujący autoryzację użytkowników, a także zarządzający ich kontami.
- Obsługiwane operacje:
- tworzenie nowego konta - jest to operacja dozwolona bez dodatkowej autoryzacji, jednak w najbliższej przyszłości planowane jest wprowadzenie mailowych potwierdzeń, tak aby nikt nie mógł zarejestrować się przy pomocy nie swojego adresu e-mail.
- modyfikacja danych konta (np. adresu email) - jest to operacja dostępna jedynie dla zalogowanego użytkownika oraz dodatkowo zabiezpieczona poprzez konieczność podania hasła
- zmiana hasła - jest to operacja możliwa zarówno dla zalogowanego jak i niezalogowanego użytkownika. Użytkownik który chce zmienić hasło, po kliknięciu odpowiedniego przycisku, otrzymuje maila z linkiem potwierdzającym jego zamiar (ma to na celu zabezpieczenie przed sytuacją, w której ktoś niepowołany chciałby zmienić jego hasło). Link potwierdzający w parametrach żądania GET zawiera uprzednio wygenerowany identyfikator UUID (co gwarantuje jego globalną unikalność), który podczas przekierowania jest odczytywany przez stronę logowania, a następnie przekazywany do backendu wraz z nowym hasłem wprowadzonym przez użytkownika. Tam następuje jego walidacja i, jeśli zakończy się ona sukcesem, wówczas w bazie danych zapisywany jest hash nowego hasła.
- Metoda autoryzacji
- Oparta na standardzie OAuth 2.0, zgodnie z metodą Resource Owner Credentials
- Użytkownik wprowadza swoje dane logowania do formularza na frontendzie
- Frontend wykonuje zapytanie w celu uzyskania tokenu autoryzacyjnego. Poniżej schematycznie przedstawiono format zapytania (oczywiście, zgodnie z nagłówkiem, jest ona w formie `x-www-form-urlencoded` nie w formacie `JSON`).
```json
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
{
"username": "user@example.com"
"password": "some-password"
"grant_type": "password"
}
```
Hasło użytkownika nie jest narażone na niebezpieczeństwo, ponieważ jest przekazywane w zapytaniu POST za pomocą szyfrowanego protokołu HTTPS.
- Serwer backendowy pobiera dane o użytkowniku z bazy danych (w tym hash hasła), a następnie porównuje hasło zaprezentowane z hasłem rzeczywistym - w przypadku poprawnej weryfikacji, autoryzacja jest udzielana i generowany jest token w formacie JWT, podpisany kluczem prywatnym Auth Service. Format odpowiedzi autoryzacyjnej jest następujący:
```json
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW...",
"token_type": "bearer",
"expires_in": 3599,
"scope": "generate_crossword suggest_words",
"email": "john.rambo@example.com",
"account_type": "PREMIUM",
"user_id": "5eebef0ef0b4da75ac20896f",
"iss": "crossyword-auth-service",
"jti": "J1Kpfm8zJRSp5WzTNT7vGyezdZ8"
}
```
- Token autoryzacyjny zapisywany jest przez frontend w warstwie `local storage`, a następnie dołączany do każdego kolejnego zapytania do backendu.
- Mikroserwisy walidują poprawność tokenu przy pomocy klucza publicznego, udostępnianego przez Auth Service pod ścieżką `/oauth/.well-known/jwks.json`. Obliczany jest hash wiadomości i porównywany z sygnaturą zapisaną w samym tokenie JWT. W przypadku poprawnej walidacji, przyznawany jest dostęp do zasobu.
#### Frontend
Aplikacja kliencka została napisana w języku Javascript przy użyciu biblioteki React v.16.11.0. Zarządzanie globalnym stanem aplikacji realizowane jest dzięki bibliotece Redux a asynchroniczne akcje realizowane za pomocą middleware redux-saga.
Do testów wykorzystywany jest test runner, a testy napisane są przy użyciu react-testing-library.
W lokalnym pliku *.env* powinny być umieszczone zmienne środowiskowe wymienione w pliku *.env.example*. W przypadku kopiowania zmiennych środowiskowych z CI/CD w serwisie Gitlab należy wymienić wszystkie $$ pojedynczym znakiem $.
## Środowisko chmurowe
### Platforma GCP
W projekcie wykorzystana została platforma chmurowa Google Cloud Platform. Wybór został podyktowany faktem, że Google oferuje 300$ do wykorzystania na poznanie możliwości platformy.
### Kubernetes
Klaster Kubernetesa postawiony został przy użyciu usługi Google Kubernetes Engine. Stworzona została pula trzech węzłów. Wykorzystaliśmy obiekty Deployment oraz StatefulSet w celu zarządzania cyklem życia serwisów oraz komponentów stanowych (takich jak baza danych MongoDB czy Prometheus). Komunikacja pomiędzy serwisami odbywa się przy pomocy obiektów typu Service w konfiguracji NodePort. Przygotowaliśmy także szereg pomocniczych zasobów Kubernetesa, takich jak ConfigMap, PersistentVolumeClaim czy też Secret.
### Ingress
W projekcie postanowliśmy zastosować **Ingress**. Dzięki temu mamy kontrolę nad ruchem wejściowym lub pomiędzy podami, możliwość konfiguracji autoryzacji użytkownika wykonującego zapytanie przychodzące do klastra.
### Domena
Do projektu zakupiono za **0 PLN** domenę *crossyword.ml*. Darmowe domeny dostępne są oferowane przez serwis *freenom.com*. W usłudze GCP skonfigurowaliśmy serwery DNS dla naszej domeny i publicznego adresu IP *load balancera* odpowiadającego za zarządzanie ruchem wchodzącym do klastra. Wykupiona domena okazała się jednak nieakceptowalna przez serwis zoho.mail, dlatego zdecydowaliśmy się wykupić dodatkową domenę w celu skonfigurowania systemu mailingowego. Jest to domena *[crossyword.online](crossyword.online)*, która wedle najnowszych planów ma stać się docelową domeną aplikacja - póki co jednak jest ona wykorzystywania jedynie w celu wysyłania automatycznych maili.
#### System mailingowy
Jak wspomniano wyżej, skonfigurowaliśmy kilka domenowych adresów e-mail, m. in. **office@crossyword.online** oraz **no-reply@crossyword.online**. Drugi z wymienionych adresów jest przez nas wykorzystywany do wysyłania automatycznych maili potwierdzających zamiar zmiany hasła przez użytkownika. Dzięki takiemu rozwiązaniu, zabezpieczamy się przed sytuacją, w której niepowołany podmiot mógłby zmienić hasło do konta użytkownika. W przyszłości planowane jest zastosowanie tego mechanizmu także podczas rejestracji użytkownika - będzie on musiał potwierdzić swój adres email.
## Konfiguracja CI/CD
Jako system CI/CD wykorzystano GitlabCI zintegrowany z wykorzystywanym przez nas serwisem Gitlab. Każdy z realizowanych przez nas mikroserwisów przechowywany jest w osobnym repozyorium, do którego dołączony jest plik .gitlab-ci.yaml. Zawiera on konfigurację kolejnych kroków związaniem z wytworzeniem i uruchomieniem aplikacji. Kroki w zależności od mikroserwisu różnią się od siebie, jednak wyróżnić możemy następujące kroki wspólne:
- zbudowanie aplikacji i uruchomienie testów,
- zbudowanie obrazu dockerowego i załadowanie go do rejestru obrazów,
- wymuszenie restartu podów należących do odpowiedniego deploymentu z nowymi wersjami obrazów
Pliki konfiguracyjne poszczególnych usług zostały zebrane do osobnego repozytorium o nazwie Configuration. Zawiera ona definicje wszystkich obiektów Deployment, StatefulSet, Service etc. w postaci plików yaml, więc kiedy zachodzi potrzeba np. przeskalowania danej usługi, wystarczy zmienić liczbę replik w odpowiednim pliku konfiguracyjnym i opublikować zmiany do Gitlaba. Konfiguracja CI/CD w przypadku tego repozytorium aplikuje zawartość wszystkich plików konfiguracyjnych do klastra kubernetesowego, dzięki czemu aktualna konfiguracja znajduje się zawsze na branchu master.
System GitlabCI oferuje publiczne maszyny do wykonywania zadań - tzw. *runners*, które są używane w tym projekcie. Niestety, ich darmowe wykorzystanie jest ograniczone, dlatego w przyszłości należałoby znaleźć lepsze rozwiązanie.
System CI/CD do wykonywania skryptów w niektórych krokach potrzebuje poufnych informacji, np. w celu uzyskania dostępu do klastra kubernetesowego. Zapisywanie ich w bezpośrednio w kodzie stanowi powazne naruszenie zasad bezpieczeństwa. System GitlabCI oferuje możliwość konfiguracji poufnych zmiennych środowiskowych w ustawieniach projektu i ten mechanizm został przez nas wykorzystany do zapisanaia tokenu dostępowego do klastra. Dzięki oznaczeniu zmiennej jako poufnej, nie pojawia się ona w logach.
## Monitoring
Do agregacji i przechowywania metryk aplikacyjnych wykorzystaliśmy bazę danych Prometheus. Przechowuje on szeregi czasowe, z możliwością obsługi wielu wymiarów pojedynczej metryki, a także dostarcza języka zapytań PromQL, który udostępnia szereg przydatnych funkcji agregujących. Serwisy są cyklicznie odpytywane na endpoincie /actuator/prometheus, z którego pozyskiwane są wartości metryk.
Jako narzędzie do wizualizacji metryk z Prometheusa zostanie wykorzystana Grafana. Jest to platforma do interaktywnej wizualizacji danych (w szczególności z aspektem czasowym), udostępniająca multum konfigurowalnych szablonów wizualizacji i możliwości dostosowania sposobów prezentacji do indywidualnych potrzeb. Jest to obecnie najpopularniejsza platforma do wizualizacji metryk aplikacyjnych.
Metryki:
* średni czas generowania krzyżówki
* liczba przychodzących żądań wygenerowania krzyżówki
* liczba spotów znaleziona za pomocą strategii PositionBasedSpotFinder
* liczba spotów znaleziona za pomocą strategii SpiralSpotFinder
* standardowe metryki JVM: uptime, heap memory, GC collections
## Interfejsy mikroserwisów
<!-- Generator: Widdershins v4.0.1 -->
<h1 id="accounts-api">Accounts API v1.0.0</h1>
> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
Accounts API
Base URLs:
* <a href="http://localhost:9090">http://localhost:9090</a>
<h1 id="accounts-api-accounts">Accounts</h1>
## createAccount
<a id="opIdcreateAccount"></a>
> Code samples
```http
POST http://localhost:9090/accounts HTTP/1.1
Host: localhost:9090
Content-Type: application/json
Accept: application/json
```
```javascript
const inputBody = '{
"email": "john.rambo@example.com",
"password": "vietnam"
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json'
};
fetch('http://localhost:9090/accounts',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`POST /accounts`
*Create new account*
> Body parameter
```json
{
"email": "john.rambo@example.com",
"password": "vietnam"
}
```
<h3 id="createaccount-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|body|body|[NewAccount](#schemanewaccount)|true|none|
> Example responses
> Account created successfully
```json
{
"userId": "123",
"email": "john.rambo@example.com",
"accountType": "PREMIUM"
}
```
<h3 id="createaccount-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|201|[Created](https://tools.ietf.org/html/rfc7231#section-6.3.2)|Account created successfully|[Account](#schemaaccount)|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Invalid request data|None|
|409|[Conflict](https://tools.ietf.org/html/rfc7231#section-6.5.8)|Address email is already taken|None|
<aside class="success">
This operation does not require authentication
</aside>
## deleteAccount
<a id="opIddeleteAccount"></a>
> Code samples
```http
DELETE http://localhost:9090/accounts/{accountId} HTTP/1.1
Host: localhost:9090
Content-Type: application/x-www-form-urlencoded
```
```javascript
const inputBody = '{
"confirmationPassword": "you_wont_guess_mee"
}';
const headers = {
'Content-Type':'application/x-www-form-urlencoded'
};
fetch('http://localhost:9090/accounts/{accountId}',
{
method: 'DELETE',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`DELETE /accounts/{accountId}`
*Delete account*
> Body parameter
```yaml
confirmationPassword: you_wont_guess_mee
```
<h3 id="deleteaccount-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|accountId|path|string|true|Account identifier|
|body|body|[DeleteAccount](#schemadeleteaccount)|false|none|
<h3 id="deleteaccount-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|204|[No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5)|Account deleted successfully|None|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Account not found|None|
<aside class="success">
This operation does not require authentication
</aside>
## updateAccount
<a id="opIdupdateAccount"></a>
> Code samples
```http
PATCH http://localhost:9090/accounts/{accountId} HTTP/1.1
Host: localhost:9090
Content-Type: application/json
Accept: application/json
```
```javascript
const inputBody = '{
"newEmail": "johny.rambollini@example.com",
"confirmationPassword": "you_wont_guess_mee"
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json'
};
fetch('http://localhost:9090/accounts/{accountId}',
{
method: 'PATCH',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`PATCH /accounts/{accountId}`
*Update account*
> Body parameter
```json
{
"newEmail": "johny.rambollini@example.com",
"confirmationPassword": "you_wont_guess_mee"
}
```
<h3 id="updateaccount-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|accountId|path|string|true|Account identifier|
|body|body|[UpdateAccount](#schemaupdateaccount)|true|none|
> Example responses
> Account updated successfully
```json
{
"userId": "123",
"email": "john.rambo@example.com",
"accountType": "PREMIUM"
}
```
<h3 id="updateaccount-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Account updated successfully|[Account](#schemaaccount)|
<aside class="success">
This operation does not require authentication
</aside>
## resetPassword
<a id="opIdresetPassword"></a>
> Code samples
```http
POST http://localhost:9090/accounts/password/reset HTTP/1.1
Host: localhost:9090
Content-Type: application/x-www-form-urlencoded
```
```javascript
const inputBody = '{
"email": "john.rambo@example.com",
"sendAsync": true
}';
const headers = {
'Content-Type':'application/x-www-form-urlencoded'
};
fetch('http://localhost:9090/accounts/password/reset',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`POST /accounts/password/reset`
*Reset password for account*
> Body parameter
```yaml
email: john.rambo@example.com
sendAsync: true
```
<h3 id="resetpassword-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|body|body|[PasswordReset](#schemapasswordreset)|true|none|
<h3 id="resetpassword-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|202|[Accepted](https://tools.ietf.org/html/rfc7231#section-6.3.3)|Reset password request completed successfully|None|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Account not found|None|
<aside class="success">
This operation does not require authentication
</aside>
## confirmPasswordReset
<a id="opIdconfirmPasswordReset"></a>
> Code samples
```http
POST http://localhost:9090/accounts/password/confirm HTTP/1.1
Host: localhost:9090
Content-Type: application/x-www-form-urlencoded
```
```javascript
const inputBody = '{
"newPassword": "even_better_password",
"passwordResetCode": "3c168520-e28e-4b16-aacf-e6490119a9cc"
}';
const headers = {
'Content-Type':'application/x-www-form-urlencoded'
};
fetch('http://localhost:9090/accounts/password/confirm',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`POST /accounts/password/confirm`
*Confirm password reset and provide new one*
> Body parameter
```yaml
newPassword: even_better_password
passwordResetCode: 3c168520-e28e-4b16-aacf-e6490119a9cc
```
<h3 id="confirmpasswordreset-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|body|body|[PasswordConfirm](#schemapasswordconfirm)|true|none|
<h3 id="confirmpasswordreset-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Password changed successfully|None|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad password reset code|None|
<aside class="success">
This operation does not require authentication
</aside>
# Schemas
<h2 id="tocS_NewAccount">NewAccount</h2>
<!-- backwards compatibility -->
<a id="schemanewaccount"></a>
<a id="schema_NewAccount"></a>
<a id="tocSnewaccount"></a>
<a id="tocsnewaccount"></a>
```json
{
"email": "string",
"password": "string",
"accountType": "STANDARD"
}
```
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|email|string|false|none|none|
|password|string|false|none|none|
|accountType|any|false|none|none|
allOf
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|» *anonymous*|[AccountType](#schemaaccounttype)|false|none|none|
and
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|» *anonymous*|object|false|none|none|
<h2 id="tocS_UpdateAccount">UpdateAccount</h2>
<!-- backwards compatibility -->
<a id="schemaupdateaccount"></a>
<a id="schema_UpdateAccount"></a>
<a id="tocSupdateaccount"></a>
<a id="tocsupdateaccount"></a>
```json
{
"newEmail": "string",
"confirmationPassword": "string"
}
```
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|newEmail|string|false|none|none|
|confirmationPassword|string|false|none|none|
<h2 id="tocS_Account">Account</h2>
<!-- backwards compatibility -->
<a id="schemaaccount"></a>
<a id="schema_Account"></a>
<a id="tocSaccount"></a>
<a id="tocsaccount"></a>
```json
{
"accountId": "string",
"email": "string",
"accountType": "STANDARD"
}
```
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|accountId|string|false|none|none|
|email|string|false|none|none|
|accountType|[AccountType](#schemaaccounttype)|false|none|none|
<h2 id="tocS_AccountType">AccountType</h2>
<!-- backwards compatibility -->
<a id="schemaaccounttype"></a>
<a id="schema_AccountType"></a>
<a id="tocSaccounttype"></a>
<a id="tocsaccounttype"></a>
```json
"STANDARD"
```
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|*anonymous*|string|false|none|none|
#### Enumerated Values
|Property|Value|
|---|---|
|*anonymous*|STANDARD|
|*anonymous*|PREMIUM|
<h2 id="tocS_PasswordReset">PasswordReset</h2>
<!-- backwards compatibility -->
<a id="schemapasswordreset"></a>
<a id="schema_PasswordReset"></a>
<a id="tocSpasswordreset"></a>
<a id="tocspasswordreset"></a>
```json
{
"email": "string",
"sendAsync": true
}
```
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|email|string|false|none|none|
|sendAsync|boolean|false|none|none|
<h2 id="tocS_PasswordConfirm">PasswordConfirm</h2>
<!-- backwards compatibility -->
<a id="schemapasswordconfirm"></a>
<a id="schema_PasswordConfirm"></a>
<a id="tocSpasswordconfirm"></a>
<a id="tocspasswordconfirm"></a>
```json
{
"newPassword": "string",
"passwordResetCode": "string"
}
```
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|newPassword|string|false|none|none|
|passwordResetCode|string|false|none|none|
<h2 id="tocS_DeleteAccount">DeleteAccount</h2>
<!-- backwards compatibility -->
<a id="schemadeleteaccount"></a>
<a id="schema_DeleteAccount"></a>
<a id="tocSdeleteaccount"></a>
<a id="tocsdeleteaccount"></a>
```json
{
"confirmationPassword": "string"
}
```
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|confirmationPassword|string|false|none|none|
<!-- Generator: Widdershins v4.0.1 -->
<h1 id="crosswordgenerator">CrosswordGenerator v1.0.0</h1>
> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
API for CrosswordGenerator microservice
Base URLs:
* <a href="http://localhost:8080">http://localhost:8080</a>
# Authentication
- oAuth2 authentication.
- Flow: password
- Token URL = [http://localhost:9090/oauth/token](http://localhost:9090/oauth/token)
|Scope|Scope Description|
|---|---|
|crossword-generator|CrosswordGenerator API scope|
* API Key (apiKey)
- Parameter Name: **apiKey**, in: header.
<h1 id="crosswordgenerator-crosswords">Crosswords</h1>
Generating crosswords
## generateCrossword
<a id="opIdgenerateCrossword"></a>
> Code samples
```http
POST http://localhost:8080/crosswords/generate HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Accept: application/json
```
```javascript
const inputBody = '{
"words": [
{
"word": "apple",
"description": "Green fruit"
},
{
"word": "orange",
"description": "Orange fruit"
},
{
"word": "banana",
"description": "Yellow fruit"
}
]
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('http://localhost:8080/crosswords/generate',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`POST /crosswords/generate`
*Generate a crossword in given format*
> Body parameter
```json
{
"words": [
{
"word": "apple",
"description": "Green fruit"
},
{
"word": "orange",
"description": "Orange fruit"
},
{
"word": "banana",
"description": "Yellow fruit"
}
]
}
```
<h3 id="generatecrossword-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|body|body|[GenerateCrosswordRequest](#schemageneratecrosswordrequest)|true|none|
> Example responses
> Crossword generated successfully
```json
{
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}
```
```json
{
"rows": 10,
"columns": 10,
"words": [
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 2,
"column": 9
},
"orientation": "vertical"
},
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 6,
"column": 4
},
"orientation": "horizontal"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 3,
"column": 6
},
"orientation": "vertical"
}
]
}
```
> 200 Response
<h3 id="generatecrossword-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Crossword generated successfully|string|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Invalid input parameters|None|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Unauthorized|None|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Insufficient scope|None|
<aside class="warning">
To perform this operation, you must be authenticated by means of one of the following methods:
crosswordGenerator ( Scopes: crossword-generator ), apiKey ( Scopes: apiKey )
</aside>
## exportCrosswordToPdf
<a id="opIdexportCrosswordToPdf"></a>
> Code samples
```http
POST http://localhost:8080/crosswords/export/pdf HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Accept: application/pdf
```
```javascript
const inputBody = '{
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/pdf'
};
fetch('http://localhost:8080/crosswords/export/pdf',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`POST /crosswords/export/pdf`
*Export crossword to PDF format*
> Body parameter
```json
{
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}
```
<h3 id="exportcrosswordtopdf-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|body|body|[Crossword](#schemacrossword)|true|none|
> Example responses
> 200 Response
<h3 id="exportcrosswordtopdf-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Crossword successfully exported to PDF|string|
<aside class="success">
This operation does not require authentication
</aside>
## exportCrosswordToSvg
<a id="opIdexportCrosswordToSvg"></a>
> Code samples
```http
POST http://localhost:8080/crosswords/export/svg HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Accept: application/zip
```
```javascript
const inputBody = '{
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/zip'
};
fetch('http://localhost:8080/crosswords/export/svg',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`POST /crosswords/export/svg`
*Export crossword to SVG format. It will return a zip archive file containing the *.svg files*
> Body parameter
```json
{
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}
```
<h3 id="exportcrosswordtosvg-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|body|body|[Crossword](#schemacrossword)|true|none|
> Example responses
> 200 Response
<h3 id="exportcrosswordtosvg-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Crossword successfully exported to SVG|string|
<aside class="success">
This operation does not require authentication
</aside>
# Schemas
<h2 id="tocS_GenerateCrosswordRequest">GenerateCrosswordRequest</h2>
<!-- backwards compatibility -->
<a id="schemageneratecrosswordrequest"></a>
<a id="schema_GenerateCrosswordRequest"></a>
<a id="tocSgeneratecrosswordrequest"></a>
<a id="tocsgeneratecrosswordrequest"></a>
```json
{
"rows": 10,
"columns": 10,
"words": [
{
"word": "string",
"description": "string"
}
]
}
```
Generate crossword request
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|rows|integer(int32)|false|none|Optional number of rows for the crossword. If ommited, the size will be computed dynamically.<br>Should be present together with 'columns'|
|columns|integer(int32)|false|none|Optional number of columns for the crossword. If ommited, the size will be computed dynamically.<br>Should be present together with 'rows'|
|words|[[Word](#schemaword)]|false|none|Array containig words to be put into the crosswords|
<h2 id="tocS_Crossword">Crossword</h2>
<!-- backwards compatibility -->
<a id="schemacrossword"></a>
<a id="schema_Crossword"></a>
<a id="tocScrossword"></a>
<a id="tocscrossword"></a>
```json
{
"rows": 10,
"columns": 10,
"words": [
{
"word": "string",
"description": "string",
"position": {
"row": 0,
"column": 0
},
"orientation": "horizontal"
}
]
}
```
Generate crossword response
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|rows|integer(int32)|false|none|Number of rows of the generated crossword|
|columns|integer(int32)|false|none|Number of columns of the generated crossword|
|words|[[PlacedWord](#schemaplacedword)]|false|none|Array of words of the generated crosswords, containing information about their positions|
<h2 id="tocS_Word">Word</h2>
<!-- backwards compatibility -->
<a id="schemaword"></a>
<a id="schema_Word"></a>
<a id="tocSword"></a>
<a id="tocsword"></a>
```json
{
"word": "string",
"description": "string"
}
```
The word, which is used as an input for crossword generation
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|word|string|false|none|The word itself|
|description|string|false|none|The word description|
<h2 id="tocS_PlacedWord">PlacedWord</h2>
<!-- backwards compatibility -->
<a id="schemaplacedword"></a>
<a id="schema_PlacedWord"></a>
<a id="tocSplacedword"></a>
<a id="tocsplacedword"></a>
```json
{
"word": "string",
"description": "string",
"position": {
"row": 0,
"column": 0
},
"orientation": "horizontal"
}
```
### Properties
allOf
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|*anonymous*|[Word](#schemaword)|false|none|The word, which is used as an input for crossword generation|
and
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|*anonymous*|any|false|none|The word, which is returned as part of generated crossword|
and
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|*anonymous*|object|false|none|none|
|» position|[Position](#schemaposition)|false|none|Position of the word placed in generated crossword|
|» orientation|enum|false|none|none|
#### Enumerated Values
|Property|Value|
|---|---|
|orientation|horizontal|
|orientation|vertical|
<h2 id="tocS_Position">Position</h2>
<!-- backwards compatibility -->
<a id="schemaposition"></a>
<a id="schema_Position"></a>
<a id="tocSposition"></a>
<a id="tocsposition"></a>
```json
{
"row": 0,
"column": 0
}
```
Position of the word placed in generated crossword
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|row|integer(int32)|false|none|none|
|column|integer(int32)|false|none|none|
<!-- Generator: Widdershins v4.0.1 -->
<h1 id="crosswords-api">Crosswords API v1.0.0</h1>
> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
Crosswords API
Base URLs:
* <a href="http://localhost:7070">http://localhost:7070</a>
# Authentication
- oAuth2 authentication.
- Flow: password
- Token URL = [http://localhost:9090/oauth/token](http://localhost:9090/oauth/token)
|Scope|Scope Description|
|---|---|
|user-data-service|UserDataService API scope|
<h1 id="crosswords-api-user-crosswords">User crosswords</h1>
Crosswords owned by users
## saveCrossword
<a id="opIdsaveCrossword"></a>
> Code samples
```http
POST http://localhost:7070/users/{userId}/crosswords HTTP/1.1
Host: localhost:7070
Content-Type: application/json
Accept: application/json
```
```javascript
const inputBody = '{
"name": "Crossword1",
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('http://localhost:7070/users/{userId}/crosswords',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`POST /users/{userId}/crosswords`
*Save crossword for user*
> Body parameter
```json
{
"name": "Crossword1",
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}
```
<h3 id="savecrossword-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|userId|path|string|true|The user identifier|
|body|body|[NewCrossword](#schemanewcrossword)|true|none|
> Example responses
> Crossword saved successfully
```json
{
"id": "a123d3r23112d2",
"name": "Crossword1",
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}
```
<h3 id="savecrossword-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|201|[Created](https://tools.ietf.org/html/rfc7231#section-6.3.2)|Crossword saved successfully|[Crossword](#schemacrossword)|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Invalid request data|None|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Unauthorized|None|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Insufficient scope|None|
<aside class="warning">
To perform this operation, you must be authenticated by means of one of the following methods:
userDataService ( Scopes: user-data-service )
</aside>
## getCrosswords
<a id="opIdgetCrosswords"></a>
> Code samples
```http
GET http://localhost:7070/users/{userId}/crosswords HTTP/1.1
Host: localhost:7070
Accept: application/json
```
```javascript
const headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('http://localhost:7070/users/{userId}/crosswords',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`GET /users/{userId}/crosswords`
*Get user's crosswords*
<h3 id="getcrosswords-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|userId|path|string|true|The user identifier|
> Example responses
> All user crosswords
```json
{
"id": "a123d3r23112d2",
"name": "Crossword1",
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}
```
<h3 id="getcrosswords-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|All user crosswords|[Crossword](#schemacrossword)|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Invalid request data|None|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Unauthorized|None|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Insufficient scope|None|
<aside class="warning">
To perform this operation, you must be authenticated by means of one of the following methods:
userDataService ( Scopes: user-data-service )
</aside>
## getMyCrosswords
<a id="opIdgetMyCrosswords"></a>
> Code samples
```http
GET http://localhost:7070/users/me/crosswords HTTP/1.1
Host: localhost:7070
Accept: application/json
```
```javascript
const headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('http://localhost:7070/users/me/crosswords',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`GET /users/me/crosswords`
*Get current user's crosswords*
> Example responses
> All user crosswords
```json
{
"id": "a123d3r23112d2",
"name": "Crossword1",
"wordsAmount": 10
}
```
<h3 id="getmycrosswords-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|All user crosswords|[BasicCrossword](#schemabasiccrossword)|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Invalid request data|None|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Unauthorized|None|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Insufficient scope|None|
<aside class="warning">
To perform this operation, you must be authenticated by means of one of the following methods:
userDataService ( Scopes: user-data-service )
</aside>
<h1 id="crosswords-api-crosswords">Crosswords</h1>
Crosswords as standalone resources
## getCrossword
<a id="opIdgetCrossword"></a>
> Code samples
```http
GET http://localhost:7070/crosswords/{crosswordId} HTTP/1.1
Host: localhost:7070
Accept: application/json
```
```javascript
const headers = {
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('http://localhost:7070/crosswords/{crosswordId}',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`GET /crosswords/{crosswordId}`
*Get crossword*
<h3 id="getcrossword-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|crosswordId|path|string|true|The crossword identifier|
> Example responses
> Requested crossword
```json
{
"id": "a123d3r23112d2",
"name": "Crossword1",
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}
```
<h3 id="getcrossword-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Requested crossword|[Crossword](#schemacrossword)|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Invalid request data|None|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Unauthorized|None|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Insufficient scope|None|
<aside class="warning">
To perform this operation, you must be authenticated by means of one of the following methods:
userDataService ( Scopes: user-data-service )
</aside>
## deleteCrossword
<a id="opIddeleteCrossword"></a>
> Code samples
```http
DELETE http://localhost:7070/crosswords/{crosswordId} HTTP/1.1
Host: localhost:7070
```
```javascript
const headers = {
'Authorization':'Bearer {access-token}'
};
fetch('http://localhost:7070/crosswords/{crosswordId}',
{
method: 'DELETE',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`DELETE /crosswords/{crosswordId}`
*Delete crossword*
<h3 id="deletecrossword-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|crosswordId|path|string|true|The crossword identifier|
<h3 id="deletecrossword-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|204|[No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5)|Crossword deleted successfully|None|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Invalid request data|None|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Unauthorized|None|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Insufficient scope|None|
<aside class="warning">
To perform this operation, you must be authenticated by means of one of the following methods:
userDataService ( Scopes: user-data-service )
</aside>
## updateCrossword
<a id="opIdupdateCrossword"></a>
> Code samples
```http
PUT http://localhost:7070/crosswords/{crosswordId} HTTP/1.1
Host: localhost:7070
Content-Type: application/json
Accept: application/json
```
```javascript
const inputBody = '{
"name": "Crossword1",
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('http://localhost:7070/crosswords/{crosswordId}',
{
method: 'PUT',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`PUT /crosswords/{crosswordId}`
*Update crossword*
> Body parameter
```json
{
"name": "Crossword1",
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}
```
<h3 id="updatecrossword-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|crosswordId|path|string|true|The crossword identifier|
|body|body|[NewCrossword](#schemanewcrossword)|true|none|
> Example responses
> Updated crossword
```json
{
"name": "Crossword1",
"rows": 8,
"columns": 8,
"words": [
{
"word": "orange",
"description": "Orange fruit",
"position": {
"row": 1,
"column": 0
},
"orientation": "vertical"
},
{
"word": "banana",
"description": "Yellow fruit",
"position": {
"row": 0,
"column": 2
},
"orientation": "horizontal"
},
{
"word": "apple",
"description": "Green fruit",
"position": {
"row": 3,
"column": 2
},
"orientation": "vertical"
}
]
}
```
<h3 id="updatecrossword-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Updated crossword|[NewCrossword](#schemanewcrossword)|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Invalid request data|None|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Unauthorized|None|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Insufficient scope|None|
<aside class="warning">
To perform this operation, you must be authenticated by means of one of the following methods:
userDataService ( Scopes: user-data-service )
</aside>
# Schemas
<h2 id="tocS_BasicCrossword">BasicCrossword</h2>
<!-- backwards compatibility -->
<a id="schemabasiccrossword"></a>
<a id="schema_BasicCrossword"></a>
<a id="tocSbasiccrossword"></a>
<a id="tocsbasiccrossword"></a>
```json
{
"id": "string",
"name": "string",
"wordsAmount": 10
}
```
The crossword
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|id|string|false|none|Crossword id|
|name|string|false|none|Crossword name|
|wordsAmount|integer(int32)|false|none|Number of words in crossword|
<h2 id="tocS_Crossword">Crossword</h2>
<!-- backwards compatibility -->
<a id="schemacrossword"></a>
<a id="schema_Crossword"></a>
<a id="tocScrossword"></a>
<a id="tocscrossword"></a>
```json
{
"id": "string",
"name": "string",
"rows": 10,
"columns": 10,
"words": [
{
"word": "string",
"description": "string",
"position": {
"row": 0,
"column": 0
},
"orientation": "horizontal"
}
]
}
```
The crossword
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|id|string|false|none|Crossword id|
|name|string|false|none|Crossword name|
|rows|integer(int32)|false|none|Number of rows of the generated crossword|
|columns|integer(int32)|false|none|Number of columns of the generated crossword|
|words|[[Word](#schemaword)]|false|none|Array of words of the generated crosswords, containing information about their positions|
<h2 id="tocS_NewCrossword">NewCrossword</h2>
<!-- backwards compatibility -->
<a id="schemanewcrossword"></a>
<a id="schema_NewCrossword"></a>
<a id="tocSnewcrossword"></a>
<a id="tocsnewcrossword"></a>
```json
{
"name": "string",
"rows": 10,
"columns": 10,
"words": [
{
"word": "string",
"description": "string",
"position": {
"row": 0,
"column": 0
},
"orientation": "horizontal"
}
]
}
```
The crossword
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|name|string|false|none|Crossword name|
|rows|integer(int32)|false|none|Number of rows of the generated crossword|
|columns|integer(int32)|false|none|Number of columns of the generated crossword|
|words|[[Word](#schemaword)]|false|none|Array of words of the generated crosswords, containing information about their positions|
<h2 id="tocS_Word">Word</h2>
<!-- backwards compatibility -->
<a id="schemaword"></a>
<a id="schema_Word"></a>
<a id="tocSword"></a>
<a id="tocsword"></a>
```json
{
"word": "string",
"description": "string",
"position": {
"row": 0,
"column": 0
},
"orientation": "horizontal"
}
```
The word, containing information about its placement
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|word|string|false|none|The word itself|
|description|string|false|none|The word description|
|position|[Position](#schemaposition)|false|none|Position of the word in crossword|
|orientation|enum|false|none|none|
#### Enumerated Values
|Property|Value|
|---|---|
|orientation|horizontal|
|orientation|vertical|
<h2 id="tocS_Position">Position</h2>
<!-- backwards compatibility -->
<a id="schemaposition"></a>
<a id="schema_Position"></a>
<a id="tocSposition"></a>
<a id="tocsposition"></a>
```json
{
"row": 0,
"column": 0
}
```
Position of the word in crossword
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|row|integer(int32)|false|none|none|
|column|integer(int32)|false|none|none|
<!-- Generator: Widdershins v4.0.1 -->
<h1 id="oauth-2-0-api">OAuth 2.0 API v1.0.0</h1>
> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
OAuth 2.0 API
Base URLs:
* <a href="http://localhost:9090">http://localhost:9090</a>
# Authentication
- HTTP Authentication, scheme: basic
<h1 id="oauth-2-0-api-oauth-2-0">OAuth 2.0</h1>
## getToken
<a id="opIdgetToken"></a>
> Code samples
```http
POST http://localhost:9090/oauth/token HTTP/1.1
Host: localhost:9090
Content-Type: application/x-www-form-urlencoded
Accept: application/json
```
```javascript
const inputBody = '{
"username": "john.rambo@example.com",
"password": "vietnam",
"grant_type": "password"
}';
const headers = {
'Content-Type':'application/x-www-form-urlencoded',
'Accept':'application/json'
};
fetch('http://localhost:9090/oauth/token',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`POST /oauth/token`
*Get authorization token*
> Body parameter
```yaml
username: john.rambo@example.com
password: vietnam
grant_type: password
```
<h3 id="gettoken-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|body|body|[TokenRequest](#schematokenrequest)|true|none|
> Example responses
> Account created successfully
```json
{
"access_token": "yJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJqb2huLnJhbWJvQGV4YW1wbGUuY29tIiwianRpIjoiX3dyZ3gyTWJDNm0wbjYzRzlsMF81SklHemFNIiwiY2xpZW50X2lkIjoidXNlci1kYXRhLXNlcnZpY2UiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXX0.TMHjA4sYi0vxK7cbUu9FI2ZbuEfr7yope6nG1WW1jz1iGjkFUN9-0romG2eJYOsi2-DJkfTz5SrqDGSaefGpmAo8oqGCmrs25Q0puYMt_q4MBXZW94OX-HGnAs7PiywuyYfhZmhvXp2qCQreoCKE7Xj6ToA-TgbvC0A8Uv6PVQ_tJVU5GgUH59jc0N0tQLM-H9pLDh2umbO_7OCC3xwrKVlwG181j3ffxlRdbrSzMtG87DH-qrweIzbIDWc_2sMBtuYObkb627kcrDY24su3sqVBpLO3UcMv76nBRd9nCyX0nBKhnNz7druLlAxolEXtQiTXxpSP76JLlkpm84OkGw",
"token_type": "bearer",
"scope": "read write",
"jti": "_wrgx2MbC6m0n63G9l0_5JIGzaM"
}
```
<h3 id="gettoken-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Account created successfully|[TokenResponse](#schematokenresponse)|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Invalid user credentials|None|
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Client application unauthorized|None|
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Different authorization error|None|
<aside class="warning">
To perform this operation, you must be authenticated by means of one of the following methods:
basicAuth
</aside>
## getJwkSet
<a id="opIdgetJwkSet"></a>
> Code samples
```http
GET http://localhost:9090/oauth/token/.well-knwown/jwks.json HTTP/1.1
Host: localhost:9090
Accept: application/json
```
```javascript
const headers = {
'Accept':'application/json'
};
fetch('http://localhost:9090/oauth/token/.well-knwown/jwks.json',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`GET /oauth/token/.well-knwown/jwks.json`
*Get JWT key set*
> Example responses
> JWT key set retrieved successfully
```json
{
"keys": {
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "rossyword-key-id",
"alg": "RS256",
"n": "oyAQIx-33LJRvnWXTQJQ7489AiHkk_fawbtq5IXJx-l7H-Y6VPc4W88xw4E8MX9n5NnPCe4A7cOEXLQ0_A2ahoLfdRuz7gDG3mxBxJuKgQvHwZ2eb5_y4ESuhqaQeDHjA6qYV-HJQH2B4Fy0buWV2HBvBZcm-vpZ6U3unbIBHqhVDktQD-Hqs3eew-youH8qu01Kd67xRuKq1yuB8XrxmRidTdHC9XNYh8bhBhnjvMtJ2pDb3YAY8IMdlCw3DvVapyYYHIkpRI1RQvOfFwGtRIH7tehGh4m6e1m51YjCVDKDA0cjh14pA5KVYsNTyKK47dL5ogZOw"
}
}
```
<h3 id="getjwkset-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|JWT key set retrieved successfully|[JWKSetResponse](#schemajwksetresponse)|
<aside class="success">
This operation does not require authentication
</aside>
# Schemas
<h2 id="tocS_TokenRequest">TokenRequest</h2>
<!-- backwards compatibility -->
<a id="schematokenrequest"></a>
<a id="schema_TokenRequest"></a>
<a id="tocStokenrequest"></a>
<a id="tocstokenrequest"></a>
```json
{
"username": "string",
"password": "string",
"grant_type": "password",
"scope": "string"
}
```
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|username|string|false|none|Actually the e-mail address, which is treated by framework as username|
|password|string|false|none|The user password in plain text|
|grant_type|string|false|none|The grant type, for user authentication should be 'password'|
|scope|string|false|none|[OPTIONAL] A space separated list of additional scopes to be requested. Note that those are additional scopes<br>intended for third-party applications usage, not the user-permission scopes which are granted automatically<br>based on user account type (like generate_crossword or suggest_words). Currently no additional scopes are<br>supported.|
<h2 id="tocS_TokenResponse">TokenResponse</h2>
<!-- backwards compatibility -->
<a id="schematokenresponse"></a>
<a id="schema_TokenResponse"></a>
<a id="tocStokenresponse"></a>
<a id="tocstokenresponse"></a>
```json
{
"access_token": "string",
"token_type": "string",
"scope": "string",
"jti": "string",
"email": "string",
"user_id": "string",
"issuer": "string"
}
```
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|access_token|string|false|none|The JWT access token|
|token_type|string|false|none|The token type, most of the time equal to 'Bearer'|
|scope|string|false|none|List of scopes that the token has granted|
|jti|string|false|none|Identifier of the JWT token|
|email|string|false|none|The user email address|
|user_id|string|false|none|The user identifier|
|issuer|string|false|none|Name of the token issuer|
<h2 id="tocS_JWKSetResponse">JWKSetResponse</h2>
<!-- backwards compatibility -->
<a id="schemajwksetresponse"></a>
<a id="schema_JWKSetResponse"></a>
<a id="tocSjwksetresponse"></a>
<a id="tocsjwksetresponse"></a>
```json
{
"keys": {
"kty": "string",
"e": "string",
"use": "string",
"kid": "string",
"alg": "string",
"n": "string"
}
}
```
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|keys|object|false|none|none|
|» kty|string|false|none|none|
|» e|string|false|none|none|
|» use|string|false|none|none|
|» kid|string|false|none|Key identifier|
|» alg|string|false|none|Algorithm used for key pair generation|
|» n|string|false|none|The public key itself|
<!-- Generator: Widdershins v4.0.1 -->
<h1 id="word-suggestor">Suggestor v0.0.1</h1>
> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
Suggestor OpenAPI schema
Base URLs:
* <a href="http://localhost:6060">http://localhost:6060</a>
<h1 id="word-suggestor-default">Default</h1>
## words
<a id="opIdload_words_words__language__post"></a>
> Code samples
```http
GET http://localhost:6060/words/{type} HTTP/1.1
Host: localhost:6060
Content-Type: application/json
Accept: application/json
```
<h3 id="load_words_words__language__post-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|type|path|string|true|none|
<h3 id="load_words_words__language__post-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Successful Response|Inline|
|204|[No content](https://tools.ietf.org/html/rfc2518#section-10.3)|No content|[Inline](#schemahttpvalidationerror)|
<h3 id="load_words_words__language__post-responseschema">Response Schema</h3>
<aside class="success">
This operation does not require authentication
```json
{
"type": string
"words": [
"string"
]
}
```
</aside>
## Definitions
<a id="Definitions"></a>
> Code samples
```http
GET http://localhost:6060/words/definitions HTTP/1.1
Host: localhost:6060
Accept: application/json
```
`GET /words/definitions`
*Definitons for all passed words*
<h3 id="suggest_for_one_word_words__language___word_one__suggestions_get-parameters">Parameters</h3>
```json
{
"words": [
"string"
]
}
```
<h3 id="suggest_for_one_word_words__language___word_one__suggestions_get-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Successful Response|Inline|
|204|[No content](https://tools.ietf.org/html/rfc2518#section-10.3)|No content|[Inline](#schemahttpvalidationerror)|
<aside class="success">
This operation does require authentication
```json
{
[
word: "string",
description: "string"
]
}
```
</aside>
<!-- Generator: Widdershins v4.0.1 -->
<h1 id="user-profiles-api">User Profiles API v1.0.0</h1>
> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
User Profiles API
Base URLs:
* <a href="http://localhost:7070">http://localhost:7070</a>
# Authentication
- oAuth2 authentication.
- Flow: password
- Token URL = [http://localhost:9090/oauth/token](http://localhost:9090/oauth/token)
|Scope|Scope Description|
|---|---|
|user-data-service|UserDataService API scope|
<h1 id="user-profiles-api-users">Users</h1>
Accessing user profiles data
## createUserProfile
<a id="opIdcreateUserProfile"></a>
> Code samples
```http
PUT http://localhost:7070/users/{accountId} HTTP/1.1
Host: localhost:7070
Content-Type: application/json
Accept: application/json
```
```javascript
const inputBody = '{
"email": "john.rambo@example.com",
"name": "John",
"surname": "Rambo",
"avatarUrl": "http://images.com/johnrambo.png"
}';
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':'Bearer {access-token}'
};
fetch('http://localhost:7070/users/{accountId}',
{
method: 'PUT',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`PUT /users/{accountId}`
*Create user profile*
> Body parameter
```json
{
"email": "john.rambo@example.com",
"name": "John",
"surname": "Rambo",
"avatarUrl": "http://images.com/johnrambo.png"
}
```
<h3 id="createuserprofile-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|accountId|path|string|true|The account identifier corresponding to this user profile|
|body|body|[CreateUser](#schemacreateuser)|true|none|
> Example responses
> User profile created successfully
```json
{
"accountId": "123",
"email": "john.rambo@example.com",
"name": "John",
"surname": "Rambo",
"avatarUrl": "http://images.com/johnrambo.png"
}
```
<h3 id="createuserprofile-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|User profile created successfully|[User](#schemauser)|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Invalid request data|None|
<aside class="warning">
To perform this operation, you must be authenticated by means of one of the following methods:
userDataService ( Scopes: manage_user_profile )
</aside>
## deleteUserProfile
<a id="opIddeleteUserProfile"></a>
> Code samples
```http
DELETE http://localhost:7070/users/{accountId} HTTP/1.1
Host: localhost:7070
```
```javascript
const headers = {
'Authorization':'Bearer {access-token}'
};
fetch('http://localhost:7070/users/{accountId}',
{
method: 'DELETE',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
```
`DELETE /users/{accountId}`
*Delete user profile*
<h3 id="deleteuserprofile-parameters">Parameters</h3>
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|accountId|path|string|true|The account identifier corresponding to this user profile|
<h3 id="deleteuserprofile-responses">Responses</h3>
|Status|Meaning|Description|Schema|
|---|---|---|---|
|204|[No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5)|User profile deleted successfully|None|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|User profile not found|None|
<aside class="warning">
To perform this operation, you must be authenticated by means of one of the following methods:
userDataService ( Scopes: manage_user_profile )
</aside>
# Schemas
<h2 id="tocS_CreateUser">CreateUser</h2>
<!-- backwards compatibility -->
<a id="schemacreateuser"></a>
<a id="schema_CreateUser"></a>
<a id="tocScreateuser"></a>
<a id="tocscreateuser"></a>
```json
{
"email": "string",
"name": "string",
"surname": "string",
"avatarUrl": null
}
```
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|email|string|false|none|none|
|name|string|false|none|none|
|surname|string|false|none|none|
|avatarUrl|binary|false|none|none|
<h2 id="tocS_User">User</h2>
<!-- backwards compatibility -->
<a id="schemauser"></a>
<a id="schema_User"></a>
<a id="tocSuser"></a>
<a id="tocsuser"></a>
```json
{
"email": "string",
"name": "string",
"surname": "string",
"avatarUrl": null,
"accountId": "string"
}
```
### Properties
allOf
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|*anonymous*|[CreateUser](#schemacreateuser)|false|none|none|
and
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|*anonymous*|object|false|none|none|
|» accountId|string|false|none|none|