REST, hvilken vakker ting

Jeg jobber for tida på mitt så langt største Railsprosjekt. Her har jeg merket noe som ser ut til å være en trend: når etablerte aktører vurderer Rails faller ofte ActiveRecord bort som alternativ i første omgang. Mange tror dette betyr at Rails ikke gir nok til at det er noen vits, der tror jeg de tar feil.

Rails består, ut av boksen av to hovedelementer: ActiveRecord, som håndterer forretningsobjektene dine slik de er representert i en relasjonsdatabase, og et rammeverk for det å lage webapplikasjoner. De fleste eksemplene på bruk av Rails er så enkle og tiltalende nettopp fordi de lener seg så hardt på grunnfunksjonaliteten i Rails: ActiveRecord og ActionPack.

Et av de nyere tilskuddene til Rails-familien er ActiveResource, et bibliotek som lar deg bruke ressurser fra et annet system omtrent som om de fantes i din egen database. Om det andre systemet også er en Rails-applikasjon er dette “plug’n’play”, hvis ikke må det gjøres litt jobb. Jeg mistenker at mange som vurderer Rails resonnerer omtrent sånn:

  • Kan vi bruke ActiveRecord? Nei
  • Kan vi bruke ActiveResource? Kanskje, men da må vi gjøre masse om på det eksterne systemet, slik at ActiveResource kan fungere uten tilpasninger

Om det så skulle vise seg at datastrukturen (eller noe annet) i det eksterne systemet ikke er tilsvarende Rails henfaller mange enten til å avskrive Rails eller å glemme alle prinsipper om bra håndverk og parse XML-strukturer i controllere og whatnot. Det er det ingen grunn til!

På prosjektet jeg jobber nå ligger foreløpig alle modellene våre “utenfor vår kontroll”, det vil si at eneste grensesnittet vi har mot dem er en REST-basert webservice. Disse ligner ikke på ActiveResource i det hele tatt, og det gjør ingenting. Vi bare begynte å skrive klientkode som om disse eksterne modellene var førsteklasses ActiveRecord-lignende objekter.

me = Person.find("marius")
all_people = Person.find(:limit => 22)

Jeg tenkte ikke på hvordan jeg skulle implementere dette i det hele tatt på dette stadiet, jeg bare skrev den klientkoden (som en enhetstest, såklart) som jeg ønsket å bruke om verden var et perfekt sted. Etter min erfaring er dette den eneste måten å få et API/DSL man orker å leve med i lengen: man er nødt til å skille det å designe seg et domenespråk fra det å implementere det. I dette tilfellet valgte jeg å få noe som lignet veldig på ActiveRecord/ActiveResource; først og fremst fordi noen her har tenkt på masse problemstillinger for meg, dernest fordi de andre elementene i Rails-applikasjonen min (Controllere og Views) blir mest mulig lik Rails og jeg slipper å tenke.

Deretter, når jeg hadde bygget meg et språk gjennom de testene jeg hadde laget satt jeg lykkelig og utslitt med et titalls tester som feiler. Da er det på tide å gå hjem, sove ut, og begynne implementasjonen neste dag.

Vi hadde en diskusjon med de som utvikler REST-tjenesten vi skal forholde oss til, og de fortalte blant annet om XML-formatet de brukte når man prøvde å aksessere en ressurs som ikke fantes. Igjen var det noen som hadde tenkt for oss, måten Rails’ REST-tjenester forteller at en ressurs ikke finnes på er å returnere HTTP statuskode 404 (not found). Det gir ingen mening å skulle parse XML for en ressurs som ikke finnes.

Dette er en oppfordring til å være litt ambisiøs når du ikke kan lene deg på Rails. Som Railsutvikler har vi et fantastisk verktøy tilgjengelig: det samme verktøyet som Rails-teamet bruker når de lager Rails – Ruby. Ruby er kraftige greier, bruk det!

No_gravatar

Holder selv på med å lage en logg-applikasjon, men RESTful-servicene jeg kaller er utviklet i .net, og er lagt ut i ashx-format.

Dvs for å for eksempel autorisere en bruker, som igjen vil returnere en del xml om denne brukeren må jeg kalle

http://server.com/Admin/logon.ashx?brukerid={#brukerid}&passord={#passord}

Og i neste omgang for å hente relevant data om noe annet

http://server.com/Admin/logg1.ashx?kid={#kid}&tidsrom={#tidsrom}&sortering{#sortering}

http://server.com/Admin/logg2.ashx?kid={#kid}&tidsrom={#tidsrom}&sortering{#sortering}

osv…

Vil gjerne bruke ActiveResource pga Ajax/XmlHttpRequest, REXML eller Hpricot, osv ser ut til å være mye mer tungvint, men vet ikke helt hvordan det skal gå til. Antar at jeg må lage meg et slags proxy API selv. Er det det dere har gjort?

Uansett om jeg hadde klart å knytte meg opp mot servicene med ARes på en annen måte så blir det jo et problem siden xml-en som returneres er på norsk, og ikke følger de engelske pluraliseringskonvensjonene i Rails.

Lurer på om dere har noen erfaringer med dette her eller kan peke meg i riktig retning. Kunne trengt en shortcut. ;)

No_gravatar

Espen, Om jeg forstår deg rett skal du konsumere en web service som er skrevet i .Net – og dette skal du gjøre fra Ruby?

Det første poenget ditt forstår jeg som at du trenger å autentisere deg for å konsumere web servicen, right? Og dette ser ut til å være basert på sesjoner istedet for HTTP Authorization (som strengt tatt er authentication, men skitt au..)?

Ut fra kodeeksemplet ser det ut som man kan autentisere seg mot tjenesten og at dette returnerer en kid – er dette en slags sesjonsnøkkel? Uansett må du vel bryte opp konsumeringen av tjenesten i to trinn:
  • et trinn der du autentiseres/autoriseres av tjenesten og
  • et trinn der du henter ut selve dataene

Selv om dette jo kompliserer situasjonen noe bør det ikke være umulig å få til. Mitt tips er at du konsentrerer deg om det språket du ønsker å bruke – relativt uavhengig av hvor komplisert du frykter det blir å implementere dette. For eksempel noe sånt:

<pre name=”code” class=”ruby”> class Log < PassiveResource def self.find(what, find_options) connect_and_authorize unless connected? case what when Fixnum find_one(find_options) when :all find_several(find_options) end end def self.find_one(options) end def self.find_several(*options) end end </pre>

Vips har du noe som ligner litt på ActiveRecord, riktignok helt uten noen implementasjon.

Pluraliseringskonvensjoner bør ikke skremme noen, i Rails kan du legge til dine egne regler. Om du ønsker å ha koden din så engelsk som mulig bør du kanskje mappe engelske koder til norske og vise versa.

Mht tips vil jeg anbefale å ta en kikk på kildekoden til ActiveRecord for å finne et API du liker og hvordan delegering kan gjøre koden håndterbar. ActiveResource har jo løst serialisering/deserialisering av objekter til XML ganske greit, så lenge dette er en prosess som gjøres på isolerte steder kan koden din antakelig holde god kvalitet selv om XML-parsing er et kapittel for seg.

Eller misforsto jeg helt her nå?

Marius


Gravatar-aktivert. Les mer om gravatar.
E-postadressen vil ikke vises på siden