Sei sulla pagina 1di 15

2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

GetStarted

Solutions Support Training Community Developer Partner

About

Community / Blogs

UsingaRESTAPIwithjQuery
andJSON
January21,2013 | 421Views |
RdigerPlantiko
morebythisauthor

ABAPDevelopment
jquery | json | mvc | rest | webapplications

Follow

RollingYourOwnSampleswithjsfiddle
HowtoMakeaPolyglotAPI
CrossOriginRessourceSharing(CORS)
ApplicationDesign
ServerRequests
ModelViewControllerintheBrowser
CouplingwiththeEventsObject
ControllerTasks
TheTableObject
Summary

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 1/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

Inmylastblog,IexposedaWebclientagainstaRESTAPIwithXMLas
datatransferlanguage.However,somepeoplefindeverythingXML
relateduncoolandboring,andwouldprefertoworkwithadataformat
likeJSONinstead.

Thisblogisdedicatedtothesepeople.

Idescribeawebapplicationwithexactlythesamefunctionalityasthatof
myformerblog,butworkingwiththeJavaScriptframeworkjQueryon
theclient,andwithJSONasdatatransferformat.Ontheserverside,
exactlythesameRESTAPIisaddressed.HereistheURLofthisweb
application:

http://bsp.mits.ch/buch/zz_jobs_json/jobs.htm

BeforecheckingitinasaBSP,Ihadgraduallydeveloppeditin
jsfiddle.net,aplaygroundforwebdevelopers(selfdescription).

RollingYourOwnSampleswithjsfiddle

jsfiddle.netisaperfectplatformforsuchkindofexperiments.Ina
quadripartitescreen,jsfiddledisplaystheHTML,CSS,andJavaScript
code,andinthebottomrightparttheactualresultbuiltofthese
ingredients.Youcanchoosetheframeworktoworkwith,orevenembed
anyotherressourceintoyoursample.SeeheretheresultofthejQuery
baseddemoapplicationwithJSONasdatatransferformat:

http://jsfiddle.net/rplantiko/vzysD/Toinspectit,youwillneeda
browsersupportingCORS,likeFirefox3.5andabove,Chrome3and
above,orMSIE10.ThejsfiddlepagewillnotworkwithInternetExplorer
9.

Withoutsaving,youcansimplyeditalltheressourcesconstitutinga
jsfiddlewebapplicationandhitRuntoseetheeffectofyourchanges.

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 2/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

HowtoMakeaPolyglotAPI

TheusualwaytomakeaRESTAPIpolygloti.e.tomakeittalkinmore
thanonedatatransferlanguagesistoputitsattentiononthespecial
headerfieldAccept.Ifthefield

Accept:application/json

ispresentintherequestheader,theAPIknowsthatJSONisthedesired
datatransferformat.TheresponsewillthereforebeaJSONobject(and
notXML,aswouldbethecaseotherwise).

ThereismuchconfusionabouttherightMIMEtypeforJSONdatawe
findvaluesliketext/xjson,application/xjavascript,text/javascript,text/x
javascriptandthelike.ButtheJSONspecification(RFC4627)clearly
specifiestheMIMEtypetobeapplication/json.

InourexampleAPI,withtheaboveheaderyougetthedatainthisform:

{
"JOBS":
{"0001":
{
"REPID":"RSNAST00",
"VARID":"UXPD_KUBE_KV",
"PRIO":"2",
"RESTART":"X",
"CONTACT":"RainerZufall",
"DESCR":"Outputallsalesorderconfirmations"}
},

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 3/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

"MESSAGE":"",
"TYPE":""
}

CrossOriginRessourceSharing(CORS)

Thetestapplicationresidingonjsfiddle.net,theSameOriginPolicy
(SOP)wouldusuallyforbidrequestingdatafromthedomainmits.ch,
wheretheRESTAPIislocated:Ajaxcanonlyphonehome.Butifthe
browsersupportsCORS,thereisawaytoperformsuchcrossdomain
request:ThebrowsersendsaspecialrequestwiththeHTTPmethod
OPTIONStotheURLitwantstorequest.Iftheservicethatis
responsibleforthisURL,sendsaspecialheaderfieldinitsreply,for
example:

AccessControlAllowOrigin:http://jsfiddle.net

thenthebrowserwillnotblockthecrossdomainrequest.Thisway,itwill
bepossibletointegratewebservicesfromwhateversourceintotheown
webapplicationaslongasthatwebserviceexplicitlyallowscross
originrequests.

Withthefinalapplicationhttp://bsp.mits.ch/buch/zz_jobs_json/jobs.htm,
thereisnoCORSnecessary,sinceitisonthesamedomainastheAPI.

ApplicationDesign

Followingthedesignofthelastblog,Ihavedividedtheapplication
layoutintoseveralareas:

TheMessageArea,reservedforoutputofsinglemessages
(error,info,successorwhatever),
theInputArea,containingalltheinputfields(textinput,drop
downlistboxes,checkboxes),
theButtonArea,
andtheTableAreacontainingtheactualjobdata,renderedasa
jQuerydatatable.

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 4/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

Theapplicationlogicsomehowreflectsthislayoutstructure.Thereare
globalobjectstable,inputAreaandmsg,connectedtotheTableArea,
theInputArea,andtheMessageArea,respectively.Inadditiontothis
viewpart,thereare

acontrollerobject,
anobjectrepresentingthejobdatathemselves(tobe
distinguishedfromthetablewhichonlypresentsthesedata),
aneventsobjectforregisteringeventhandlersandtriggering
events,
andaserverobject,responsibleforalltheAjaxrequests.

//The"globalplayers":
varjobs,server,//Modelparts(clientandstubforserver)
controller,//Controller
events,//Atinyeventregistrationservice
table,inputArea,msg//Viewparts
;

ServerRequests

Followingthisseparationofconcerns,itmustbetheserverobjectwhich
isresponsibleforperformingalltheRESTAPIcalls.

Letslookatanexample.TheserverobjectholdsamethodsaveJob()
whichwillbecalledwhentheuserhitstheSavebutton.Thedata

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 5/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

enteredintheinputareawillbecollectedintoahashvariablejob.

Server.prototype.saveJob=function(job,callback){
$.ajax({
url:this.JOB_MANAGER_URL+job.ID,
type:"PUT",
data:JSON.stringify(job),
success:this.onSuccess(callback)
});
};

ThisisthewaytosendanAjaxrequestwithJSONdatausingjQuery:
The$.ajax()methodacceptsahashwithalltheactualrequest
properties.WithJSON.stringify(),JavaScriptdatacanbeconvertedinto
aJSONstringthiswillbeusedheretopassthejobdataintheHTTP
requestbody.TheURLcontainsthejobIDandtheHTTPmethodfor
savingisPUT(notPOST).

Youmaymisssomeoptionshereforexample:Howdoestheserver
knowthattheHTTPbodycontainsJSONdata?

Indeed,thereisamethod$.ajaxSetup()whichcanbeusedtosetthe
preferencesforanyAjaxrequestonthepagesothattheydonthave
tobespecifiedwitheachparticular$.ajax()request.

Therightplacetospecifythesepreferencesisintheconstructorofthe
Serverclass:

//Theobjectforremotecallstotheserver
functionServer(){
this.JOB_MANAGER_URL="/buch/job/attributes/";
this.VARIANTS_URL="/buch/job/variants/"
$.ajaxSetup({
url:this.JOB_MANAGER_URL,
type:"GET",
dataType:"json",
contentType:"application/json",
data:"",
processData:false
});
}

IftheAjaxrequestreturnedsuccessfully,theonSuccessmethodwillbe
called.Here,onSuccesshasbeensettoserver.onSuccess(callback),

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 6/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

whichisamethodproducingfunctionsasreturnvaluetheadvantage
isthatthecallbackfunctioncanbepasseddynamicallywhenthe
requestiscalled(i.e.whenthesaveJob()functionisperformed,
becausetheuserhitsSave).

Server.prototype.onSuccess=function(callback){
returnfunction(data){
controller.updateFromServer(data,callback);
}
};

Atthispoint,theserverdelegatesfurtherfollowupactionstothe
controllerpassingtheAPIsreturndataasdata,andtherequired
callbackfunctionascallbacktothecontrollermethod
updateFromServer().

ThecontrollermethodupdateFromServer()providesspaceforgeneral
followupactions,andwillfinallycallthecallbackfunction:

Controller.prototype.updateFromServer=function(data,callback){
msg.show(data);
callback(data);
}

IftheAPIreturndatacontainamessage,itwillbedisplayedviathe
msg.show(data)call.Furtheractionisperformedinthecallback.

ModelViewControllerintheBrowser

Foranapplicationinvolvingauserinterface,itisgoodpracticetoapply
theModelViewControllerarchitecturalpattern.

Themodelpart,thecorelogicanddataofourapplicationissplitintotwo
parts(whichisaconsequenceoftheclient/serversplit):

1.TheRESTAPIcontainslogicwhichisprocessedontheservervia
theserverobject.Itoperatesondatawhichresideontheserver
(thejobattributestable).
2.FurtherlogicisimplementedinJavaScriptandexecutedinthe
browser.Thisisthejobsobject.
https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 7/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

Forsimplicity,thejobsobjectontheclientismodelledasahash,since
thereisonlyoneinstancerequired,andthereisnoneedfor
polymorphy.Basically,thismeansthatweonlywanttohaveadefined
namespaceforagroupoffunctions.

ThejobsobjectcontainsanattributeJOBS,ahashwithallthejobdata,
usingtheIDashashkey.Itoffersmethodsformanipulatingthesedata.
Forexample,considertheupdate()method:

//Arepresentationofthejobdataonclientside
jobs={
JOBS:{},
//...
update:function(jobData){
var$elf=this,update=false;
$.each(jobData,function(id,job){
if(id)$elf.JOBS[id]=job;
update=true;
});
if(update)events.raise("update",jobData);
},
//...

Asyousee,theupdatemethodfirstupdatestheowndataaccordingto
theinput.Afterthis,itraisestheupdateeventtonotifyotherpartsof
theapplicationaboutthechange.Thecouplingthroughtheevents
objecthelpskeepingthelayersseparatefromeachother.Thisisin
accordancewiththeMVCmodelitcorrespondstothedashedarrow
ChangeNotificationinSunswellknownMVCgraphic:

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 8/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

AnexampleforaUserGestureiswhentheuserhitstheSavebutton.
Letsseewhathappensonthis:

Thecontrollerhasaclickhandlerforthisevent,sendingthesave
requesttotheserver.
ItreadsthedatafromtheInputArea(view!)andsendsthemas
payloadoftherequesttotheserver
Asacallback,whentheservernotifiesthathisStateChangewas
OK,thejobsobjectreceivesthisStateChangerequestbyacall
oftheupdate()method.
Thedataforthejobs.update()callaretakenfromtheAjax
response(data.JOBS).
Thejobs.update()methodcontainstheChangeNotificationofthe
viewparts.ThedataintheTableArea(view!)havetobeupdated
withthenewvalues.

Controller.prototype.click_save=function(){
if(inputArea.okForPosting()){
server.saveJob(inputArea.get(),function(data){
jobs.update(data.JOBS);
});
}
}

CouplingwiththeEventsObject

Once,whentheapplicationisloaded,theregistrationforthemodel
eventshastobeperformed.Thisisdoneintheconstructorofthe
controllerobject:

//Controllermanages/dispatchestasksofviewandmodel
functionController(){
varcontroller=this;
...
//Registerformodelnotifications
events.register({
update:[[table,"update"],[inputArea,"onUpdate"]],
replace:[[table,"replace"],[inputArea,"reset"]],
deleteSingle:[[table,"deleteRow"],[inputArea,"reset"]]
});
...
}

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 9/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

Theeventsobjectonlyhastwomethodsregister()andraise().With
register(),objectmethodsareregisteredforlatercall.Ascanbeseen
fromtheabovecode,eachregistryentryconsistsofanobjectinstance
andamethodnamebelongingtothisobject.Fromthesearguments,a
callbackfunctionisgeneratedforlatercall,andstoredinthe
events.registryhash.Observethatthisfunctioncallstheinstance
methodbypassingtheobjectinstanceasthisargument.Soitsnotonly
afunctioncall,butreallythecalloftheobjectmethod:

//Aneventregistrationservice
events={
registry:{},
register:function(entries){
var$elf=this;
$.each(entries,function(event,handlers){
if(!$elf.registry[event])$elf.registry[event]=[];
$.each(handlers,function(index,handler){
$elf.registry[event].push(function(data){
handler[0][handler[1]].call(handler[0],data);
});
});
});
},
...
};

Later,whentheeventisraised,alltheregisteredcallbackswillsimplybe
invoked.Actualdatacanbepassedtothehandlerasargumentinthe
events.raise()call:

//Aneventregistrationservice
events={
...
raise:function(event,data){
varhandlers=this.registry[event];
$.each(handlers,function(index,registeredHandler){
registeredHandler(data);
});
}
};

ControllerTasks

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 10/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

Thecontrollerismainlyadelegator:Dependingontheuseraction,it
hastonotifytheviewandmodelcomponentsthatarelinkedtothis
change.Itcontainseventhandlerimplementationsandregistrations.

ThecontrollerinstancewillbeconstructedwhentheDOMisready:

$(function(){controller=newController()});

Allthepagesinitializationtaskswillthereforebeexecutedinthe
constructor.

functionController(){
varcontroller=this;
server=newServer();
...
}

Wehavealreadyseentheevents.register()call,whichispartofthe
Controllerconstructor.Apartfromthis,therearefurtherregistrations
concerningtheviewelements.

Thehandlersforclickbuttonshavetoberegistered.Usingan
appropriatenamingconventionforthehandlermethods,themethod
canbecalleddynamically.Also,beforethespecificclickhandleris
called,thereisroomforgenericactionstobeperformedwitheach
buttonclick:Here,amsg.clear()iscalledforremovingmessagesfrom
formerdialogueactions:

//Registerthebuttonhandlers
$.each(["save","new","copy","delete","reset"],function(index,id){
$("#"+id).click(function(){
msg.clear();
controller["click_"+this.id].call(controller);
});
});

Then,thetable(theobjectresponsiblefortheTableArea)hastobe
constructed.Atthispointintime,therearenorowsinthetable.

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 11/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

Therefore,wehavetoaddadynamicregistrationforrowclicksusing
thejQuery.on()function.WheneverarowappearsintheDOMatalater
time,themethodcontroller.click_row()willberegisteredforitsclick
event.

//Createthetable
table=newTable();
//Registerforallclicksonrows
$("#resulttbody").on("click","tr",function(e){
msg.clear();
controller.click_row(this);
});

Thedropdownlistforvariantshastoberebuiltwheneverthereport
nameischanged:

//Registerforchangeofreportid
$("#REPID").change(function(){
msg.clear();
server.getVariants(
$("#REPID").val(),
function(variants){
inputArea.fillVariants(variants);
})
});

Asthefinalstepoftheconstructor,thecurrentjobsareselectedviathe
RESTAPI,usingaGETrequest,andplacedintothejobsmodelobject.

//Fillitwiththejobs
server.getJobs(function(data){
jobs.update(data.JOBS);
});

TheTableObject

Forthepresentationofthejobdata,weareusingDataTables,avery
powerfulandwelldocumentedjQueryplugin.TheTableAreais
providedbythetableobject,whichcontainsthejQueryDataTableasa
delegate:
https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 12/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

//Tableobjectforpresentingthedata
functionTable(){
//Createdatatableobject
this.dataTable=$("#result").dataTable({
aoColumns:this.aoColumns(jobs.fields,jobs.field_text),
bFilter:false,
bPaginate:false,
bInfo:false
});
}

Thepurposeofthetableobjectistoencapsulatethedetailsofthetable
presentation.Intheinterface,itgetsargumentslikejobData,butnodata
typesthatareinternaltoDataTables.Onlythemethodimplementations
containthedetailsoftheDataTablesAPI.Thisway,thedependencywith
DataTablesisconcentratedinoneclass.WhenIdecidedtoreplacethe
DataTablesobjectbysomethingelse,thenecessarychangescanbe
localizedtothissingleclass.

Thetable.update()methodmayserveasanexample.ItusesAPI
methodstodetectwhetherthejobsarealreadycontainedinthetable.If
yes,theserowsareupdated.Otherwise,newrowsareinserted(similar
inspirittotheOpenSQLstatementMODIFY).Forunknownreasons,
thedynamicaltableupdateisoneofthetasksforwhichthereisno
straightforwardAPIcall.Here,IamusingasolutionbyEmilstrm
whichmaybeinterestingforotherDataTablesusers,too:

Table.prototype.update=function(jobData){
vardataTable=this.dataTable,
settings=dataTable.fnSettings(),
data=this.mapToDataTable(jobData);
$.each(data,function(index,row){
vartr=document.getElementById(row.DT_RowId);
if(tr)//rowexists>update
dataTable.fnUpdate(row,tr);
else//newrow>addit
dataTable.oApi._fnAddData(settings,row);
});
settings.aiDisplay=settings.aiDisplayMaster.slice();
dataTable.fnDraw();
};

Summary

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 13/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

IfaRESTAPIhandlestheapplication/jsoncontenttype,itispossibleto
writeawebclientasaBusinessServerPage,performingalltheAPI
calls,alltheinteractionandpresentationtasksontheclientwith
JavaScript.TheBSPenvironmentonlyservesasacontainerforas
viewedfromserversidestaticressourceslikeHTML,JavaScriptand
CSSfiles.Forcaseslikethis,thejQuerylibraryisagoodchoice.

AlertModerator

2Comments
YoumustbeLoggedontocommentorreplytoapost.

UmitCoskunAydinoglu

May28,2015at8:59am

HelloRdiger,
Excellentarticle.Ihaveonequestion.WhichclassorFMareyouusingto
deserializethejsontoabapobjectorDDIConserverside?Iamusing
/ui2/cl_json=>deserializeandseemstobenotworking.
KindRegards,
Cokun

RdigerPlantiko Postauthor

May28,2015at10:19am

HelloCokun,
thanksforyourfeedback!
Fortheserversideofthatexample,Ihadafurtherblogpost:
DevelopingaRESTAPIinABAP
TheABAPimplementationwaswrittensothatitcouldservetwo
independentUIs,onewrittenwithJSON/JQuery,theotherwritten

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 14/15
2/8/2017 UsingaRESTAPIwithjQueryandJSON|SAPBlogs

withXML/XSLT.
Basically,acustomrequesthandlerperformedthetransformations,
eitherfromXMLtoABAP(andviceversa)orfromJSONtoABAP
(andviceversa).Thetransformationitselfwasperformedinlocal
classes(lcl_json_converterandlcl_xml_converter),bothinheriting
fromthesameabstractclasslcl_converter.Theconcreteconverter
instancetochoosewasdeterminedfromtheHTTPheaderfield
Accept.
ThetransformationsitselfwerehandwrittenXSLTtransformations
(theCALLTRANSFORMATIONstatementhasbuiltinsupportfor
JSONaswell).
IdidntusetheSAPRESTAPIframework(asofwritingthoseblogs,
theRESTAPIwasnotreadyforuse,orif,Ididntknowit).
Havefun!
Rdiger

Share & Follow


Privacy TermsofUse LegalDisclosure Copyright Trademark Sitemap Newsletter

https://blogs.sap.com/2013/01/21/usingarestapiwithjqueryandjson/ 15/15

Potrebbero piacerti anche