Closed rkrzewski closed 9 years ago
Zrobiłem,
zobacz czy o to Ci chodziło @rkrzewski .
Dorzuciłem parentId:Option[Long] pole do Category. Będzie potrzebne przy tworzeniu kategorii chyba.
Oj, faktycznie. Jeśli uwzględnimy dodawanie, modyfikację i kasowanie kategorii to sprawa się komplikuje. Specem od tworzenia API nie jestem, więc propozycja poniżej jest oczywiście do dalszej dyskusji. Notację wymyśliłem na poczekaniu, ale wierzę się się rozczytasz :)
- fetch a specific category
GET /rest/categories/1
>>> 200, {
"id" : 1,
"parentId" : null
"name" : "name",
"hasChildren" : true
}
- fetch subcategories
GET /rest/categories/1/children
>>> 200, [{
"id" : 2,
"parentId" : 1
"name" : "name",
"hasChildren" : true
}, {
"id" : 5,
"parentId" : 1
"name" : "name",
"hasChildren" : false
}]
- update a category
PUT /rest/categories/1
<<< {
"id" : 1, // ignored, path parameter (1 here) used instead
"parentId" : null // updating id moves category subtree
"name" : "name",
"hasChildren" : true
}
>>> 204
- delete a category subtree
DELETE /rest/categories/1
>>> 204
- create a new subcategory
POST /rest/categories/1/children
<<< {
"id" : 1, // ignored, new id generated
"parentId" : null // ignored, path param (1 here) used instead
"name" : "name",
"hasChildren" : true // igored
}
>>> 201, Location: /categories/`new id`
- fetch all root categories
GET /rest/categories/children
>>> 200, [{
"id" : 1,
"parentId" : null
"name" : "root 1",
"hasChildren" : true
}]
- create a new root category
POST /rest/categories/children
<<< {
"id" : 1, // ignored, new id generated
"parentId" : null // ignored, path param (null here) used instead
"name" : "name",
"hasChildren" : true // igored
}
>>> 201, Location: /categories/`new id`
ten URL /rest/categories/children
jest trochę dziwaczny ale nie mam na razie pomysłu jak to inaczej ugryźć.
Po chwili zastanowienia (po napisaniu, a przed wysłaniem poprzedniego komentarza) wymyśliłem inną wersję, która ma trochę prostsze URLe (nie wymaga sufiksu children
) ale jest moim zdaniem gorsza, ponieważ przy fetchowaniu danych wypycha do klienta więcej informacji niż jest faktycznie potrzebne do "leniwego" renderowania drzewka. Poza tym narusza standardową konwencję REST, że GET /rest/categories
powinien zwrócić wszystkie kategorie w systemie, a nie top levelowe. W poprzedniej wersji GET /rest/categories
może po prostu odpowiedzieć 405
co jest bardziej poprawnym zachowaniem niż zwrócenie niestndardowej (i potencjalnie mylącej) treści.
Z punktu widzenia Twojego miniprojektu to jednak jest dzielenie włosa na czworo :) Wybierz co Ci bardziej pasuje, albo zaproponuj jeszcze coś innego.
- fetch all root categories
GET /rest/categories
>>> 200, [{
"id" : 1,
"parentId" : null
"name" : "root 1",
"hasChildren" : true,
"children" : [{
"id" : 2,
"parentId" : 1
"name" : "name",
"hasChildren" : true
}, {
"id" : 5,
"parentId" : 1
"name" : "name",
"hasChildren" : false
}]
}]
- fetch a specific category
GET /rest/categories/2
>>> 200, {
"id" : 1,
"parentId" : null
"name" : "cat 2",
"hasChildren" : true,
"children" : [{
"id" : 3,
"parentId" : 1
"name" : "cat 3",
"hasChildren" : false
}, {
"id" : 4,
"parentId" : 1
"name" : "cat 4",
"hasChildren" : false
}]
}
- update a category
PUT /rest/categories/1
<<< {
"id" : 1, // ignored, path parameter (1 here) used instead
"parentId" : null // updating id moves category subtree
"name" : "name",
"hasChildren" : true
}
>>> 204 / 400 if updating parentId would create a circular dependency
- delete a category subtree
DELETE /rest/categories/1
>>> 204
- create a new root category
POST /rest/categories
<<< {
"id" : 1, // ignored, new id generated
"parentId" : null // ignored, path param (null here) used instead
"name" : "name",
"hasChildren" : true // igored
}
>>> 201, Location: /rest/categories/`new id`
- create a new subcategory
POST /rest/categories/1
<<< {
"id" : 1, // ignored, new id generated
"parentId" : null // ignored, path param (1 here) used instead
"name" : "name",
"hasChildren" : true // igored
}
>>> 201, Location: /rest/categories/`new id`
Myślę, że sporo się pokrywa z tego co jest z tym o czym piszesz. Zróbmy to najprościej jak się da, żeby specjalnie się nie narobić i tak nikt do tego nie zajrzy ;) Będziemy mało REST-owi, ale who cares!
create a new root or child category
POST /rest/categories
<<< {
"name" : "name",
"hasChildren" : true // igored
}
>>> 201, Location: /rest/categories/`new id`
Wystarczy, że podasz te dwie wartości. Jeżeli chcesz podpiąć się pod inną kategorię po prostu dodaj do jsona:
parentId: 2
W zwrotce jest header z Location i wygenerowanym id.
update a category
PUT /rest/categories/1
<<< {
"name" : "name",
"hasChildren" : true
}
delete a category subtree
DELETE /rest/categories/1
>>> 204
tutaj usuwamy kategorię wraz z dziećmi. Muszę to dorobić bo póki co w ogóle nie ma usuwania.
fetch all root categories
GET /rest/categories
[{
"id": 1,
"name": "Great American Novel",
"hasChildren": true
}]
Zwróci wszystkie kategorie, które nie mają ojca.
fetch a specific category children
GET /rest/categories/1
[{
"id": 3,
"name": "Poor people",
"parentId": 1,
"hasChildren": false
}, {
"id": 2,
"name": "Rich people",
"parentId": 1,
"hasChildren": false
}]
:+1: zamknij zadanie kiedy skończysz implementację API (chyba że, już to zrobiłeś?)
Zrobiłem :)
Szczerze nie wiem czy nie przedobrzyłem z ilością rzeczy do dopisania w bazie danych, no ale niech już będzie jak jest.
Obecnie zdefiniowane API dla kategorii jest bardzo nieefektywne jeśli chodzi o wyświetlanie drzewka. Znacznie bardziej przyjazne było by coś takiego:
Pobieranie wszystkich kategorii głównych (nie posiadających rodzica)
Pobieranie podkategorii:
@almendar, czy mógłbyś przerobić backend w taki sposób?