Návrh REST API rubrika: Návrh

5 Nehalem
položil/-a 15.8.2014

Pořád spekuluji jak správně navrhnout API (asi mi něco uniká).
Je mi jasné že když chci manipulovat např. s autem tak to bude:

/cars (GET,POST,PUT,DELETE) Auta
/cars/:uid (GET,POST,PUT,DELETE) Auto

To stejné např. pro osobu

/persons(GET,POST,PUT,DELETE) Osoby
/person/:uid (GET,POST,PUT,DELETE) Osoba

Ale není mi jasné, jak správně napsat API pro metody typu:

  • Připoj osobu k autu
  • Připoj auto k osobě

/persons/addCar ?
/persons/:uid/addcar/:uid
/persons PUT (update cars)
/cars/addPerson ?

Nechci si zadělat API tisíci metodami typu addPerson, doThis, doThat.
Jak to řešíte vy ?

odkaz
10 jiri.knesl
odpověděl/-a 15.8.2014

Ve svém pochopení RESTu máš chybu.

/cars (GET,POST,PUT,DELETE) Auta
/cars/:uid (GET,POST,PUT,DELETE) Auto

Je model, který tlačí Ruby on Rails a je zcela špatně.

Při návrhu REST API zapomeň, že existují nějaké modely, data. Nejhorší věc, kterou můžeš udělat, je sekat RESTová API jako CRUDy. Hodně lidí to tak dělá, ale dělají to špatně, výsledkem je, že se pak to API musí volat příliš mockrát, že vznikají zbytečné metody, že některé věci nejdou udělat, nebo moc složitě.

Správné řešení je vytvářet API podle use-cases. Tzn. chceš-li upravit auto, může být /cars/:id PUT v pořádku. Ale čirou náhodou jen proto, že víš, že klient bude upravovat auto.

Use case je i připoj osobu k autu, můžeš to pojmenovat /person/connect-with-car PUT, nebo /person-connect-with-car PUT nebo dokonce /connect-person-with-car PUT, nebo třeba /connect/person/car PUT.

Všechno jsou to jen jména. URL jsou ve skutečnosti nedůležitá. Dobré řešení by bylo i ?action=connect&what=person&with=car PUT. Pokud si napíšeš knihovnu, která tě odstíní, URL může být i /asdflkjasdfjkl PUT.

Správný postup při návrhu API (REST je detail) zní:

1) zjistit, jak bude klient používat API (nejdůležitější bod)
2) navrhnout jeden logický způsob pojmenování (a může to být /sloveso/ostatní/parametry, nebo ?action=sloveso&ostatni-parametry... nebo cokoliv dalšího)
3) to implementovat
4) sledovat, jestli klient používá API tak, jak jsi myslel
5) vydat verzi 2, která opraví chyby

Pokud nemůžeš udělat krok 1, jsi v pěkné kaši (jako fakt, psát API a nevědět, jak bude klient to API používat, celou věci ztěžuje asi 10-násobně).
Tam místo původního bodu 1 si to nahraď bodem:

1) nastřel API, jak si myslíš (a jak si se ptal všech potenciálních uživatelů API, které znáš), jaké mají v plánu s API dělat workflow a navrhni pro každý krok každého workflow metody s upozorněním, že verze 2 vyjde velmi brzo

Komentáře

  • maryo : Tak sekat RESTová API JEN jako CRUDy je velká chyba, ale z toho nijak nevyplývá, že /cars (GET,POST,PUT,DELETE) Auta /cars/:uid (GET,POST,PUT,DELETE) Auto by bylo špatně. A s těmi Rails... Nejde spíš o lenost doplnit další metody když zaákladní CRUD je otázka pár minut než o to, že by někdo něco tlačil? 15.8.2014
  • Kit : Není CRUD jako CRUD. Pokud nemanipuluje s tabulkou, ale s doménou, je to OK. 16.8.2014
  • Tharos : Tvrdit, že zmíněný model je zcela špatně, je nejvíc špatně. :) REST aka CRUD nad objekty domény je úplně legitimní, není to nic proti ničemu. Je dobré zmínit, že neexistuje žádný „standard“, jak by mělo být REST API navržené. IMHO je mnohem výhodnější mit resources /cars a /cars/:id a používat HTTP metody tímto způsobem: en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services, než mít nějaké use-case obskurnosti typu /cars/add-car, /cars/update-car atp. Odpověď mi přijde cenná, ale zbytečně černobílá a subjektivní (co je úplně špatně, jak to má být správně). 16.8.2014
  • jiri.knesl : Tharos: jak jsem psal ve své odpovědi, pokud jsem si jistý, že klient bude potřebovat i CRUD operace, tak je v pořádku je tam přidat. V opačném případě je to chyba. Mít /cars/add-car /cars/update-car je proti RESTu, ale není proti RESTu /cars/find-cheapest-in-town. Sekat CRUDy je obdoba anemického modelu v OOP, přemýšlet nad API a udělat jen nezbytný minimální počet metod je obdoba kompaktně navrženého rozhraní. 16.8.2014
  • Tharos : Mně ale například přijde „RESTovější“ GET /cars?town=Prague&find=cheapest než zmíněné GET /cars/find-cheapest-in-town. Za základ klasického RESTu považuji zdroje (resources), metody pro práci s nimi a případné další parametry (v query stringu, těle requestu…). Určitě to nevede k bujení metod, k anemickému modelu či nějakému tupému přelévání dat z tabulek do JSONu a zpět… Proč jsem do téhle diskuze vstoupil je, že já jsem si právě prošel cestou use-case lazených API, abych se nakonec vrátil ke „klasickému“ RESTu tak, jak ho popisuji (založeného na zdrojí, metodách…). Je ale důležité o těch zdrojích dobře přemýšlet. 16.8.2014

Pro zobrazení všech 7 odpovědí se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.