API endpoint code sample for BOA.
Posted: Thu May 12, 2022 4:19 am
Hi,
Hereby a sample of an endpoint as you can use it for BOA.
Below are some functions that can be used to start a customer multi tab form.
BOA will call the customers function with the following parameters:
To build an empty grid:
/customers/grid
To fill the grid after entering a search key
/customers?key=abc
Open a grid and fill with data and headers
/customers?key=abc&headers=1
To get all the tabpages with the titles and endpoints
/customers/form
To get all the info for an id, number of the tabpage, and all the labels to display
/customers/id?tab=1&labels=1
For this first test I added the DBF files you will need:
klant with 5000 customers
klantnum.ntx with index on nummer
klantnaa.ntx with index on naam
postnrs with the zipcodes, and with the indexes
postnrs.ntx index on newpost
poststad index on upper(plaats+postnr)
landcode with the countrycodes and indexes.
landcode.ntx with index on code
landcod1.ntx with index on landcode
In the customers function, there is a call to:
APIHEADERS: this will create the headers for the grid
fCustpages(cTabpage,lLabels,@aLabels) which will create the content for the tabpage.
APIblock('klant',cFields) which return the data for the row. cFields is created as a codeblock, and is evaluated.
I also added the following:
webfileopen() to open the files. I don't know how to specify the path.
allfileopen() to check if all files are correctly openend.
allfileclose(cFileopen) closes all files
I also added the source code for sendjson(), so you can see what this does. This also uses convertJSONtoCHAR to get the json object in a string.
The above is not a copy/paste solution, since it is dependant on the json parser you uses. It should give a enough information to understand how BOA works, to get an idea about the work you have to do, and if further interested to start with a test which you can do for free. You can test BOA without buying anything.
In attachment the files the above sample is refering to.
If any question, you can ask them.
Hereby a sample of an endpoint as you can use it for BOA.
Below are some functions that can be used to start a customer multi tab form.
BOA will call the customers function with the following parameters:
To build an empty grid:
/customers/grid
To fill the grid after entering a search key
/customers?key=abc
Open a grid and fill with data and headers
/customers?key=abc&headers=1
To get all the tabpages with the titles and endpoints
/customers/form
To get all the info for an id, number of the tabpage, and all the labels to display
/customers/id?tab=1&labels=1
For this first test I added the DBF files you will need:
klant with 5000 customers
klantnum.ntx with index on nummer
klantnaa.ntx with index on naam
postnrs with the zipcodes, and with the indexes
postnrs.ntx index on newpost
poststad index on upper(plaats+postnr)
landcode with the countrycodes and indexes.
landcode.ntx with index on code
landcod1.ntx with index on landcode
In the customers function, there is a call to:
APIHEADERS: this will create the headers for the grid
fCustpages(cTabpage,lLabels,@aLabels) which will create the content for the tabpage.
APIblock('klant',cFields) which return the data for the row. cFields is created as a codeblock, and is evaluated.
I also added the following:
webfileopen() to open the files. I don't know how to specify the path.
allfileopen() to check if all files are correctly openend.
allfileclose(cFileopen) closes all files
I also added the source code for sendjson(), so you can see what this does. This also uses convertJSONtoCHAR to get the json object in a string.
Code: Select all
function rest_Customers(cCommand,aPara,cDossier,cTaal,cUser,cCodeVert,nCode)
****************************************************************************
Local aVarList, aVars:={}, cZoek:="" , nNummer := 0
local aJSON:={} , x:=0, rec, nLenZoek:=0 , index:=0
Local cFileopen:=webfileopen("klant") + webfileopen("postnrs")+ webfileopen("landcode")
Local oClient:=ThreadObject(), bFilter:={|| .T. }
Local oRec , cVar , nPos , oSubRec
Local cContent := "", cContentType := "" , oJson
Local nFields := 0 , lCorrectie := .F.
Local cField := "" , uValue := nil , nFieldpos , cType
Local aUnknown := {} , cIndexNr , over_arr := {} , uHeaders
Local lHeaders := .F. , aHeaders := {} , aOptions := {}
Local uVar :="" , lOnlyHeaders := .F. , lLabels := .F.
Local amaandArray , nShowmaand := 1 , oOnclick , ctabPage := ""
Static cFields := "" , alabels := {} , cTab := "x"
select klant
aVarList:=oClient:getVar(nil,VAR_QUERY)
IF Valtype(aVarList) == 'A'
FOR x := 1 TO Len(aVarList)
AAdd(aVars,aVarList[x])
NEXT
ENDIF
if aPara[1] == "v1.0"
x := 0
if !empty(aVars)
cFields := DC_HtmlGetVar(aVars, 'fields', .T.)
cVar := DC_HtmlGetVar(aVars, 'key', .T.)
lHeaders := if(var2char(DC_HtmlGetVar(aVars, 'headers', .T.))="1",.T.,.F.)
lLabels := if(var2char(DC_HtmlGetVar(aVars, 'labels', .T.))="1",.T.,.F.)
cIndexNr := DC_HtmlGetVar(aVars, 'index', .T.) // you can create endpoints which defines the ctive index.
cTabPage := DC_HtmlGetVar(aVars, 'tab', .T.) // which tab-page is needed.
endif
if cTab <> cTabpage .or. valtype(cFields) = "U"
cFields := ""
asize(aLabels,0)
cTab := cTabpage
endif
if len(aPara)>2 .And. !empty(aPara[3])
uVar := aPara[3]
if upper(uVar) == "GRID" // start for the grid. BOA will add this to the request. So you know you don't need to return data.
lOnlyHeaders := .t.
elseif upper(uVar) == "FORM" // start a multi tab form. BOA will the form structure, so you can send the captions and number of pages.
// each tab is a form, and each form has his own endpoint.
cTabpage := "0"
else
nNummer := val(uVar)
endif
else
if !empty(cVar)
cZoek:=ConvUtfToCp(upper(cVar))
endif
endif
if cTabpage == "0" // send the info for all the tab-pages of the multi tab form.
rec:=json():new()
rec:title := "Address"
rec:tab := '1'
rec:endpoint := '/customers/${id}?tab=1'
rec:pagetype := "form"
aadd(aheaders,rec)
rec:=json():new()
rec:title := "Administration"
rec:tab := '2'
rec:endpoint := '/customers/${id}?tab=2'
rec:pagetype := "form"
aadd(aheaders,rec)
rec:=json():new()
rec:title := "Extra"
rec:tab := '3'
rec:endpoint := '/customers/${id}?tab=3'
rec:pagetype := "form"
aadd(aheaders,rec)
rec:=json():new()
rec:title := "History"
rec:tab := '4'
rec:endpoint := '/customers/${id}?tab=4'
rec:pagetype := "form"
aadd(aheaders,rec)
rec:=json():new()
rec:title := "Bill"
rec:tab := '5'
rec:endpoint := '/customers/${id}?tab=5'
rec:pagetype := "form"
aadd(aheaders,rec)
rec:=json():new()
rec:title := "Documents"
rec:tab := '6'
rec:endpoint := '/customers/${id}?tab=6'
rec:pagetype := "form"
aadd(aheaders,rec)
rec:=json():new()
rec:title := "Turnover"
rec:tab := '7'
rec:endpoint := '/customers/${id}?tab=7'
rec:pagetype := "form"
aadd(aheaders,rec)
rec:=json():new()
rec:title := "Data"
rec:tab := '8'
rec:endpoint := '/customers/${id}?tab=8'
rec:pagetype := "form"
aadd(aheaders,rec)
rec:=json():new()
rec:file := "klant"
rec:titlefield := 'naam'
rec:tabpages := aHeaders
allfileclose(cFileopen)
return sendjson(rec)
endif
IF lOnlyHeaders // Send only headers, so this is done.
APIheaders('klant',@aHeaders,cTaal)
rec:=json():new()
rec:file := "klant"
rec:headers := aHeaders
allfileclose(cFileopen)
return sendjson(rec)
endif
do while .T.
Do CASE
case cCommand ="DELETE"
if !empty(nNummer)
klant->(dbsetorder(1))
klant->(dbseek(nNummer))
if !klant->(eof()) .and. klant->(locked())
// Here you can delete a record.
klant->(dbrunlock())
endif
endif
case cCommand == "GET"
if empty(nNummer) .and. empty(cFields) .and. lHeaders
APIheaders('klant',@aHeaders,cTaal) // with API headers you can create the headers for different requests.
endif
if !empty(nNummer)
if empty(cFields) .and. cTabPage <> "99" // if tabpage == 99 , only return the fields for the grid.
if lLabels
rec:=json():new()
rec:display := ""
rec:fieldname := "id"
rec:length := 6
rec:inputtype := 'hidden'
aadd(aLabels,rec)
endif
cFields := fCustpages(cTabpage,lLabels,@aLabels)
endif
if nNummer > 0
klant->(dbsetorder(1))
klant->(dbseek(nNummer))
if !klant->(eof())
oRec := APIblock('klant',cFields)
aadd(aJson,oRec)
else
rec:=json():new()
rec:type := "ID does not exist"
rec:id := nNummer
orec:=json():new()
oRec:file := "klant"
oRec:error := rec
allfileclose(cFileopen)
return sendjson(oRec)
endif
endif
elseif !empty(cZoek)
x:=0
nNummer := 0
cZoek:=upper(alltrim(strip(cZoek)))
if left(cZoek,1)=="="
nNummer := val(substr(cZoek,2))
klant->(dbsetorder(1))
klant->(dbseek(nNummer))
oRec := APIblock('klant',cFields)
aadd(aJson,oRec)
else
nLenZoek:=len(cZoek)
klant->(dbsetorder(2))
klant->(dbseek(cZoek,.T.))
Do while upper(left(strip(klant->naam),nLenZoek)) = cZoek
x++
oRec := APIblock('klant',cFields)
aadd(aJson,oRec)
klant->(dbskip(1))
enddo
endif
if lHeaders .and. empty(aHeaders) .and. x > 0
APIheaders('klant',@aHeaders,cTaal)
endif
endif
case cCommand == "POST" // create the record, then change command to PUT for update
klant->(dbsetorder(1))
set deleted off
klant->(dbgobottom())
nNummer := klant->nummer+1 // get next number for the customer
if klant->(append())
klant->nummer := nNummer
klant->(dbrunlock())
endif
cCommand := "PUT"
loop
case cCommand == "PUT" // update after creation
cContent := oClient:HTTPRequest:content
cContentType := oClient:HTTPRequest:contenttype
if lower(cContentType) = "application/json"
oJson := json():new(cContent)
if empty(nNummer) .and. oJson:hasvar("id")
nNummer := var2num(oJson:id)
endif
nFields := len(oJson:_aJson) // oJson:_aJson returns an array with the fieldnames and the data
klant->(dbsetorder(1))
klant->(dbseek(nNummer))
if klant->(eof())
rec:=json():new()
rec:type := "ID does not exist"
rec:id := nNummer
orec:=json():new()
oRec:file := "klant"
oRec:error := rec
allfileclose(cFileopen)
return sendjson(oRec)
endif
if klant->(locked())
for x = 1 to nFields
cField := oJson:_aJson[x][1]
uValue := oJson:_aJson[x][2]
if (nFieldpos := klant->(fieldpos(cField))) > 0
cType := upper( valtype(klant->(fieldget(nFieldpos))))
if cType $ "CM" // Character or memo
if valtype(uValue) = "L"
uValue:=if(uValue,"J","N")
elseif empty(uValue)
uValue := ""
endif
klant->(fieldput(nFieldpos, uValue))
elseif cType == "N" // Numeric
if empty(uValue)
uValue := 0
endif
klant->(fieldput(nFieldpos, var2num(uValue)))
elseif cType == "D" .and. !empty(uValue) // Date
if empty(uValue)
uvalue := " / / "
endif
klant->(fieldput(nFieldpos, ctod(uValue)))
elseif cType == "L" // Logical
if empty(uValue)
uValue := .f.
endif
if valtype(uValue) == "L"
klant->(fieldput(nFieldpos, uValue))
else
klant->(fieldput(nFieldpos, if(upper(uValue)$"0NFALSE",.F.,.T.)))
endif
endif
elseif upper(left(cField,2)) <> "ID"
aadd(aUnknown,cField)
// cUnknown += if(empty(cUnknown),""," | ") + cField
endif
next
klant->(dbrunlock())
endif
oRec := APIblock('klant',cFields)
aadd(aJson,oRec)
endif
endcase
exit
enddo
endif // end Version 1.0
rec:=json():new()
rec:file := "klant"
if lHeaders .and. !empty(aheaders)
rec:headers := aHeaders
endif
if lLabels .and. !empty(aLabels)
rec:labels := aLabels
endif
if nNummer >= 0
rec:data := aJson
endif
allfileclose(cFileopen)
return sendjson(rec)
function fCustpages(cTabPage,lLabels,aLabels)
******************************************
Local rec , cFields, oSubRec , aOptions := {}
do case
case cTabpage = "1"
if lLabels
rec:=json():new()
rec:display := "Name / Company:"
rec:tooltip := "Name of the customer."
rec:fieldname := 'naam'
rec:length := 40
rec:inputtype := 'edit'
rec:newline := .T.
rec:labelwidth := 2
rec:fieldwidth := 4
aadd(aLabels,rec)
rec:=json():new()
rec:display := "Contact:"
rec:tooltip := "Name of contact person."
rec:fieldname := 'naam2'
rec:length := 40
rec:inputtype := 'edit'
rec:newline := .F.
rec:labelwidth := 2
rec:fieldwidth := 4
aadd(aLabels,rec)
rec:=json():new()
rec:display := "Address:"
rec:tooltip := "Address:"
rec:fieldname := 'adres'
rec:length := 40
rec:inputtype := 'edit'
rec:newline := .T.
rec:labelwidth := 2
rec:fieldwidth := 4
aadd(aLabels,rec)
endif
cFields := "naam,naam2,adres"
if lLabels
rec:=json():new()
rec:display := "Address 2:"
rec:tooltip := "Address 2:"
rec:fieldname := 'adres2'
rec:length := 40
rec:inputtype := 'edit'
rec:newline := .F.
rec:labelwidth := 2
rec:fieldwidth := 4
aadd(aLabels,rec)
rec:=json():new()
rec:display := ''
rec:fieldname := 'idpostnr'
rec:length := 10
rec:inputtype := 'hidden'
oSubRec := json():new()
oSubrec:endpoint := "/files/postnrs"
oSubrec:file := "postnrs"
oSubrec:fieldname := "id"
rec:data := oSubRec
aadd(aLabels,rec)
rec:=json():new()
rec:display := ''
rec:fieldname := 'newpost'
rec:length := 10
rec:inputtype := 'hidden'
oSubRec := json():new()
oSubrec:endpoint := "/postnrs"
oSubrec:file := "postnrs"
oSubrec:fieldname := "newpost"
rec:data := oSubRec
aadd(aLabels,rec)
rec:=json():new()
rec:display := "Zipcode:"
rec:tooltip := "Postal code."
rec:fieldname := 'postnr'
rec:length := 8
rec:inputtype := 'search'
rec:newline := .T.
rec:labelwidth := 2
rec:fieldwidth := 2
rec:grid := "postnrs"
oSubRec := json():new()
oSubrec:endpoint := "/postnrs"
oSubrec:file := "postnrs"
oSubrec:fieldname := "postnr"
oSubrec:buttons := "select,add,edit,exit"
rec:data := oSubRec
aadd(aLabels,rec)
rec:=json():new()
rec:display := ''
rec:fieldname := 'idlandcode'
rec:length := 10
rec:inputtype := 'hidden'
oSubRec := json():new()
oSubrec:endpoint := "/landcodes"
oSubrec:file := "/landcodes"
oSubrec:fieldname := "id"
rec:data := oSubRec
aadd(aLabels,rec)
rec:=json():new()
rec:display := "" //fWebMessage(cTaal,60)
rec:tooltip := "Country codes"
rec:fieldname := 'land'
rec:length := 3
rec:inputtype := 'dropdown'
rec:newline := .F.
rec:labelwidth := 0
rec:fieldwidth := 2
rec:grid := "landcode"
oSubRec := json():new()
oSubrec:endpoint := "/landcodes"
oSubrec:file := "landcodes"
oSubrec:fieldname := "code"
rec:data := oSubRec
aadd(aLabels,rec)
rec:=json():new()
rec:display := "Hometown:"
rec:tooltip := ""
rec:fieldname := 'postnrs_plaats'
rec:length := 30
rec:inputtype := 'noedit'
rec:newline := .F.
rec:labelwidth := 2
rec:fieldwidth := 4
oSubRec := json():new()
oSubrec:endpoint := "/postnrs"
oSubrec:file := "postnrs"
oSubrec:fieldname := "plaats"
rec:data := oSubRec
aadd(aLabels,rec)
rec:=json():new()
rec:display := "Phone:"
rec:tooltip := "Telephone"
rec:fieldname := 'telefoon'
rec:length := 16
rec:inputtype := 'phone'
rec:newline := .T.
rec:labelwidth := 2
rec:fieldwidth := 4
aadd(aLabels,rec)
rec:=json():new()
rec:display := "Fax."
rec:tooltip := "Fax."
rec:fieldname := 'telefoon2'
rec:length := 16
rec:inputtype := 'phone'
rec:newline := .F.
rec:labelwidth := 2
rec:fieldwidth := 4
aadd(aLabels,rec)
rec:=json():new()
rec:display := "Mobile:"
rec:tooltip := "Mobile number"
rec:fieldname := 'gsm'
rec:length := 16
rec:inputtype := 'phone'
rec:newline := .T.
rec:labelwidth := 2
rec:fieldwidth := 4
aadd(aLabels,rec)
rec:=json():new()
rec:display := "E-Mail:"
rec:tooltip := "E-Mail address."
rec:fieldname := 'email'
rec:length := 40
rec:inputtype := 'email'
rec:newline := .T.
rec:labelwidth := 2
rec:fieldwidth := 10
aadd(aLabels,rec)
rec:=json():new()
rec:display := "VAT:"
rec:tooltip := ""
rec:fieldname := 'btw_kode'
rec:length := 3
rec:inputtype := 'combobox'
rec:newline := .T.
rec:labelwidth := 2
rec:fieldwidth := 2
oSubRec := json():new()
oSubrec:option := "Individual"
oSubrec:value := "P"
aadd(aOptions,oSubrec)
oSubRec := json():new()
oSubrec:option := "Company"
oSubrec:value := "B"
aadd(aOptions,oSubrec)
oSubRec := json():new()
oSubrec:option := "School"
oSubrec:value := "V"
aadd(aOptions,oSubrec)
oSubRec := json():new()
oSubrec:option := "No VAT"
oSubrec:value := "N"
aadd(aOptions,oSubrec)
rec:options := aOptions
aadd(aLabels,rec)
rec:=json():new()
rec:display := ""
rec:fieldname := 'landcode'
rec:length := 3
rec:inputtype := 'noedit'
rec:newline := .F.
rec:labelwidth := 0
rec:fieldwidth := 2
oSubRec := json():new()
oSubrec:endpoint := "/landcodes"
oSubrec:file := "landcodes"
oSubrec:fieldname := "landcode"
rec:data := oSubRec
aadd(aLabels,rec)
rec:=json():new()
rec:display := "VAT Nr."
rec:tooltip := "VAT number of the customer."
rec:fieldname := 'btw_nr'
rec:length := 16
rec:inputtype := 'edit'
rec:newline := .F.
rec:labelwidth := 2
rec:fieldwidth := 4
aadd(aLabels,rec)
endif
cFields += ",adres2,idpostnrs,postnr,newpost,idlandcode,land,postnrs->plaats,telefoon,telefoon2,gsm"
cFields += ",email,btw_kode,landcode,btw_nr"
/* tabpage 2 to 9 not converted yet
case cTabPage = "2"
....
endcase
return cFields
function APIblock(cAlias,cFields,lLevel) // creates the json for the data.
****************************************
Local oRecord := json():new() , aFields := {} , aSubFields := {}
Local cBlock := '' , x , nField := 2 , cFieldname , y , cField // , bBlock := ""
Local nRecord := 0 , cZoek := "" , nParent := 0 , cType := "" , nFldPos := 0
Local bBlock := ""
default lLevel := .F.
cAlias := upper(cAlias)
// according to the opened file, actions can be done. Some of them can be avoided by using set relation while opening the files
do case
case "newpost" $ cFields .and. !cAlias== "POSTNRS"
postnrs->(dbseek( (cAlias)->newpost))
case "land" $ cFields .and. !cAlias== "LANDCODE"
landcode->(dbseek( (cAlias)->land))
endcase
// a codeblock with all the data has to be created. This is evaluated and returns the result.
cBlock := '{|rec| rec:id := alltrim(str(recno())),'
if empty(cFields)
cFields := (cAlias)->(fieldname(1))
do while !empty( cFieldname := (cAlias)->(fieldname(nField)) )
cFields += ','+cFieldname
nField ++
enddo
endif
aFields := dc_tokenarray(cFields,",")
for x = 1 to len(aFields)
cField := aFields[x]
do case
// In some cases the has to be an json object in the data. This is the system to have relations.
// Sample in customers there is a link to the zipcodes.
// Sample in a stock product there is a relation to productcategories
// Below some samples to check and to create the data
case "newpost" == cField .and. !cAlias == "POSTNRS"
postnrs->(dbseek( (cAlias)->newpost))
cBlock += 'rec:postnrs:= apiblock("postnrs","postnr,plaats,newpost",.t.),'
case "land" == cField .and. !cAlias == "LANDCODE"
landcode->(dbseek( (cAlias)->land))
cBlock += 'rec:landcodes:= apiblock("landcode","code,land,landcode",.t.),'
endcase
endif
if (nFldPos:=(cAlias)->(fieldpos( cField ))) > 0 .or. "->"$cField .or. "+"$cField
cField := strtran(cField,"->","_")
cField := strtran(cField,"+","_")
cField := strtran(cField,"-","_")
cField := strtran(cField,"(recno())","id")
if nFldPos > 0
cType := (cAlias)->(fieldinfo(nFldPos , FLD_TYPE))
if cType == "M"
cBlock += 'rec:'+cField+':=memoeon('+aFields[x]+'),'
elseif cType == "D"
cBlock += 'rec:'+cField+':=dtoc('+aFields[x]+'),'
else
cBlock += 'rec:'+cField+':='+aFields[x]+','
endif
else
cBlock += 'rec:'+cField+':='+aFields[x]+','
endif
endif
next
cBlock += 'rec}'
bBlock := &(cBlock)
endif
return (cAlias)->(eval(bBlock,oRecord ))
function APIHeaders(cAlias,aHeaders,cTaal) // create headers for a grid.
******************************************
Local oRecord := json():new()
Local cBlock := '' , x , bBlock , nField := 2 , cFieldname
cAlias := upper(cAlias)
if cAlias == "KLANT"
// you can create headers as below, or you could read some klant.headers.language.txt with the json in it.
oRecord:title := 'Customer name:'
oRecord:data := 'naam'
oRecord:type := 'string'
oRecord:width := '25%'
aadd(aHeaders , oRecord)
oRecord := json():new()
oRecord:title := 'Address:'
oRecord:data := 'adres'
oRecord:type := 'string'
oRecord:width := '20%'
aadd(aHeaders , oRecord)
oRecord := json():new()
oRecord:title := 'City'
oRecord:data := 'postnrs->plaats'
oRecord:type := 'string'
oRecord:width := '20%'
aadd(aHeaders , oRecord)
oRecord := json():new()
oRecord:title := 'Cell phone:'
oRecord:data := 'gsm'
oRecord:type := 'string'
oRecord:width := '15%'
aadd(aHeaders , oRecord)
oRecord := json():new()
oRecord:title := 'Email'
oRecord:data := 'email'
oRecord:type := 'string'
oRecord:width := '20%'
aadd(aHeaders , oRecord)
elseif cAlias == "LEVER"
oRecord:title := 'Supplier:'
oRecord:data := 'naam'
oRecord:type := 'string'
oRecord:width := '25%'
aadd(aHeaders , oRecord)
oRecord := json():new()
oRecord:title := 'Address:'
oRecord:data := 'adres'
oRecord:type := 'string'
oRecord:width := '20%'
aadd(aHeaders , oRecord)
oRecord := json():new()
oRecord:title := 'City:'
oRecord:data := 'postnrs->plaats'
oRecord:type := 'string'
oRecord:width := '15%'
aadd(aHeaders , oRecord)
oRecord := json():new()
oRecord:title := 'Cell phone:'
oRecord:data := 'gsm'
oRecord:type := 'string'
oRecord:width := '15%'
aadd(aHeaders , oRecord)
oRecord := json():new()
oRecord:title := 'Email:'
oRecord:data := 'email'
oRecord:type := 'string'
oRecord:width := '25%'
aadd(aHeaders , oRecord)
elseif cAlias == "STOCK"
....
else
endif
return .t.
Function webfileopen(cFile)
***************************************
local nDelta := 0
cFile := upper(cFile)
// sample for the opening of the files and corresponding indexes.
if cFile == "KLANT"
do while nDelta < 10
use klant alias klant new
if .not. neterr()
set index to klantnum,klantnaa
return cFile+"/"
else
nDelta ++
endif
sleep(nDelta*3)
enddo
return 'error/'
endif
if cFile == "POSTNRS"
do while nDelta < 10
use postnrs alias postnrs new
if .not. neterr()
set index to postnrs, poststad
return cFile+"/"
else
nDelta ++
endif
sleep(nDelta*3)
enddo
return 'error/'
endif
if cFile == "LANDCODE"
do while nDelta < 10
use landcode alias landcode new
if .not. neterr()
set index to landcode, landcod1
return cFile+"/"
else
nDelta ++
endif
sleep(nDelta*3)
enddo
return 'error/'
endif
return ""
function allfileopen(cFiles)
****************************
if !"error" $ lower(cFiles)
return .T.
else
allfileclose(cFiles)
endif
return .F.
function allfileclose(cFiles)
****************************
Local nPos
do while (nPos:=at("/",cFiles)) > 0
close(substr(cFiles,1,nPos-1))
cFiles := substr(cFiles,nPos+1)
enddo
return .F.
function SENDJSON(ocJSON,lFlat) //
*****************************
local nErr := 0
local o := threadobject()
local cContent := if(valtype(ocJson)=="C",ocJson,convertJSONtoCHAR(ocJSON))
default lFlat := .F.
o:httpResponse:contenttype := 'application/json'
if len(cContent) < 10000 .or. lFlat
o:httpResponse:ContentEncoding("identity")
o:httpresponse:CompressLevel = 0
o:httpResponse:content := cContent
else
o:httpResponse:ContentEncoding( "deflate" )
o:httpResponse:content := xbZCompress( cContent, 4, @nErr, .t. )
endif
return .t.
In attachment the files the above sample is refering to.
If any question, you can ask them.