About
fv_2007
Agile innovative developer with deep insight into lots of platforms, technologies and protocols. Absolute “early adopter” in Web 2.0 technologies and more. Large professional network and eagerly talking about architecture, strategy, design patterns, restful ressources, object-oriented thinking and modeling languages such as PML. Special interest in programminglanguages constructs, knowledge on languages like Smalltalk, Erlang, Java, Clojure, Scala, Ruby... read more
Follow
Feedfavicon
Comments
Language

Cross Domain JSONP on Rails January 22, 2010 11:49 7 months ago

Jeg vil igang med at lave en Cross Domain Mashup applikation der asynkront kan hente data fra forskellige domains. Min klient er i HTML5, CSS3 og naturligvis Javascript. Protokollen er HTTP, kommunikation er asynchronous og indholdet skal være JSON fordi det allerede er Javascript, kompakt og ikke behøver parsing af nogen art. JSON skal pakkes ind JSONP for at overvinde Same Origin Policy sikkerheds modellen.

Flickr

Flickr er en fantastisk ressource til at præsentere og administrere billeder. De udstiller også en stribe API’er til mange forskellige ting. Jeg har kun interesser for REST API’et

Den præcise URI jeg vil bruge er til min egen foto feed på flickr. Det er værd at bemærke de sidste parameter i URI’en “format=json&jsoncallback=?”. Disse paramter fortæller resourcen at response skal være i formattet JSON og at kaldet måske er Cross Browser og derfor skal JSON pakkes ind som et JSONP kald. Ydermere kan man specificere et callback navn “joncallback=?” ved spørgsmålstegnet hvis man vil have en bestemt metode kaldt når script er loadet.

URI JSONP
&format=json jsonFlickrFeed({ “title”:“Uploads” })
&format=json&jsoncallback=? ({ “title”: "Uploads"})
&format=json&jsoncallback=visfoto visfotos({ “title”: "Uploads"})

Det kan betale sig at undersøge data grundigt inden man går igang med at skrive klienten. Hvis man kan operere/navigere med curl -i URI gennem de ønskede scenarie er man langt.

Nu klienten.

  $(document).ready(function(){
    $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?id=7185299@N07&format=json&jsoncallback=?",
        function(data){
          $.each(data.items, function(i,item){
            $("<img/>").attr("src", item.media.m).appendTo("#images");
            if ( i == 8 ) return false;
          });
        });
  });

Flickr ressourcen bliver ramt gennem Jquery og henter data. Der itereres gennem data der indeholder title, link til foto location, hvornår det er taget og en masse andet. Elementet item.media er en server location men der følger et m med som fortæller noget om de størrelse og repræsentationer som billedet allerede er skaleret til. Prøv fx at skifte m ud med et s.

Nu til den næsten klient app som er twitter updates. Koden herunder henter et antal twitter status update og iterere gennem hver update. Undervejs ledes efter regulære udtryk der minder om et link tag og hvis udskiftes med et rigtig html link anker. Hver update bliver adderet til hash# div tag. Det er muligt at bruge this[array] til at hente data ud af strukturen.

Læg også mærke til at twitter vil have en count parameter med ind for at minimere antal updates over linjen. Bemærk også at er mere REST aware i det de udnytter HTTP header information om den returnerede repræsentation og caching TTL i netværket. De udnytter infrastrukturen bedre end flickr.

  var regexp = /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi; 
  $(document).ready(function(){
    $.getJSON("http://twitter.com/statuses/user_timeline/frankvilhelmsen.json?count=6&callback=?",
      function(data, textStatus) {
        $.each(data, function(i) {
          var twitter_time = prettyDate(this['created_at'])
          var twitter_uri_encoded_text = this['text'].replace(regexp,'<a href="$1">$1</a>') 
          $("#statuses").append("<li>"+twitter_time+": "+twitter_uri_encoded_text+"</li>");
        });
    });
  });

Server

Indtil nu har jeg kun forbrugt ressource hvor jeg kun kender interfacet men jeg vil jo også gerne udstille mine egne REST baseret Cloud ressourcer. Heldigvis understøtte rubyonrails dette lige ud af boxen. Min platform er Heroku | Ruby Cloud, Platform as a Service git og Rails. DNS og alt er sat op.

  p = Post.find(:all, :select => 'id, title, osv') 
  response_to 
    ...
    format.json {render :json => @posts, :callback => [:callback] }
  end 

Det eneste jeg skal gøre for at enable en ressource til cross browser er tilføje denne “:callback => [:callback]”.

Rails har altså dekoreret JSON til JSONP format uden at jeg behøver at gøre mere. Men måske ville jeg reagere anderledes på ønsket om at give parameter som denne med i requestet “&callback=chanceheader”. Direkte til klienten. Og nu er det nemt for koden er næsen det samme som før.

  $(document).ready(function(){
    $.getJSON("http://XXX/posts/title/all?format=json&callback=?",
      function(data){
        $.each(data, function(i) {
        $("#titles").append("<li>"+this.post.id+" - " +this.post.title+"</li>")
     });
  });
});


By Frank Vilhelmsen - 4 tags: rails rest roa cross - Add comment