Page 1 of 1

SB & PB JSON-RPC CGI

Posted: Thu Jul 18, 2019 5:48 pm
by the.weavster
As there are a few forum members struggling to get started with PureBasic's CGI commands I have quickly put together a simple PureBasic JSON-RPC CGI that exposes one method (sayhello) and an equally simple SpiderBasic client that calls the method and displays the response in the debug window:

PureBasic
Compile this as cgitest.cgi and place that in the "cgi-bin" subfolder of your website (remember to match the architecture of your server).

Code: Select all

Declare SayHello(jsParams,jsRO)
Declare SendChunk(txt$)

Procedure FormatError(jsRO,errcode,errmsg$)
  jsErr = AddJSONMember(jsRO,"error")
  jsErrO = SetJSONObject(jsErr)
  SetJSONString(AddJSONMember(jsErrO,"message"),errmsg$)
  SetJSONInteger(AddJSONMember(jsErrO,"code"),errcode)
  SetJSONInteger(AddJSONMember(jsErrO,"origin"),2)
  jsResP = AddJSONMember(jsRO,"result")
  SetJSONNull(jsResp) 
EndProcedure

Procedure ProcessIncoming(incoming$)
  jsRP = CreateJSON(#PB_Any) ; Start building our JSON-RPC response
  jsRO = SetJSONObject(JSONValue(jsRP))
  WriteCGIString("Content-type: application/json" + #CRLF$,#PB_UTF8)
  WriteCGIString("Transfer-Encoding: chunked" + #CRLF$ + #CRLF$,#PB_UTF8)
  js = ParseJSON(#PB_Any,incoming$) ; Parse incoming JSON-RPC
  ; details here: https://en.wikipedia.org/wiki/JSON-RPC
  If js
    todo$ = GetJSONString(GetJSONMember(JSONValue(js),"method"))
    id$   = GetJSONString(GetJSONMember(JSONValue(js),"id"))
    jsParams = GetJSONMember(JSONValue(js),"params")
    SetJSONString(AddJSONMember(jsRO,"id"),id$) ; always return id
    Select todo$ ; route and pass params to requested method
      Case "sayhello"
        SayHello(jsParams,jsRO)
      Default
        FormatError(jsRO,4,"Method not found: "+todo$)
    EndSelect
    SendChunk(ComposeJSON(jsRP,#PB_JSON_PrettyPrint))
    FreeJSON(js)
    FreeJSON(jsRP)
  EndIf
EndProcedure

Procedure SayHello(jsParams,jsRO)
  NewMap qp.s()
  ExtractJSONMap(jsParams,qp())
  jsErr = AddJSONMember(jsRO,"error")
  SetJSONNull(jsErr)
  jsResP = AddJSONMember(jsRO,"result")
  jsResO = SetJSONObject(jsResP)
  SetJSONString(AddJSONMember(jsResO,"msg"),qp("recipient") + " said: '" + qp("greeting") + "'")
EndProcedure

Procedure SendChunk(txt$)
  nSize    = StringByteLength(txt$,#PB_UTF8)
  If nSize = 0 : ProcedureReturn : EndIf ; don't want to SendEOT by mistake
  hxSize$  = Hex(nSize)
  res$ = hxSize$ + #CRLF$ + txt$ + #CRLF$
  WriteCGIString(res$,#PB_UTF8) 
EndProcedure

Procedure SendEOT()
  WriteCGIString(Hex(0) + #CRLF$ + #CRLF$,#PB_UTF8)
EndProcedure

If Not InitCGI() : End : EndIf
BufferSize = ReadCGI()
If BufferSize = 0 : End : EndIf
RequestBody$ = PeekS(CGIBuffer(),BufferSize,#PB_UTF8)

ProcessIncoming(RequestBody$)
SendEOT()
SpiderBasic
You have to compile this (Enable Debugger should be ticked) and serve it from the same server that's hosting the CGI

Code: Select all

request$ = ""

Procedure HttpGetEvent(Success,Result$,UserData)
  If Success
    Debug Result$
  Else
    Debug "HTTPRequest(): Error"
  EndIf
EndProcedure

If CreateJSON(0)
  jso = SetJSONObject(JSONValue(0))
  SetJSONString(AddJSONMember(jso,"method"),"sayhello")
  SetJSONString(AddJSONMember(jso,"id"),"abc123")
  jsp = SetJSONObject(AddJSONMember(jso,"params"))
  SetJSONString(AddJSONMember(jsp,"recipient"),"Weave")
  SetJSONString(AddJSONMember(jsp,"greeting"),"Hello, World!")
  request$ = ComposeJSON(0)
  FreeJSON(0)
EndIf

Debug request$
Debug ""

NewMap Headers$()
Headers$("Content-Type") = "application/json"
HTTPRequest(#PB_HTTP_Post,"cgi-bin/cgitest.cgi",request$,@HttpGetEvent(),0,Headers$())

Re: SB & PB JSON-RPC CGI

Posted: Fri Jul 19, 2019 7:38 am
by saboteur
Many thanks for the example, will try to work my way through this today.

I'm assuming that : if my webserver runs on a linux machine then the cgi must be written and complied using PB on a linux machine ?

Re: SB & PB JSON-RPC CGI

Posted: Fri Jul 19, 2019 3:45 pm
by the.weavster
saboteur wrote:I'm assuming that : if my webserver runs on a linux machine then the cgi must be written and complied using PB on a linux machine ?
Compiled on Linux, yes. And unlike Windows you can't take it as a given a 32bit executable will run with a 64bit OS so you have to match that too.