B4J Question [Solved] Posting JSON to Shopee API

aeric

Well-Known Member
Licensed User
Shopee is an e-commerce platform.
The documentation for their Open API is avaialble at https://open.shopee.com/documents?module=63&type=2&id=53

I have developed a B4J Non-UI app but unable to get the expected results.
B4J:
{"request_id":"f4c3ea528366af36e4fc9ba62132e3b5","msg":"no partner_id","error":"error_param"}

When I use Postman to post the request, I get the correct result.
Postman:
{
"request_id": "5f55837962278cb1f065e7ea1550cc3c",
"orders": [],
"more": false
}
I suspect the request body was not sent correctly. This can happen when Content-Type and Content-Length are not set.

I attached the project here.

Please help.
 

Attachments

DonManfred

Expert
Licensed User

Additional you should set the ContentType another way
B4X:
        Job.GetRequest.SetContentType("application/json")
B4X:
Sub AppStart (Args() As String)
    Try
        strPath = File.DirApp
        If Args.Length > 0 Then
            strPath = Args(0)
        End If
        
        LoadSettings(strPath)
        
        'Log("BUILD: " & BUILD)
        'Log("ENDPOINT: " & ENDPOINT)
        'Log("PARTNER_ID: " & PARTNER_ID)
        'Log("API_KEY: " & API_KEY)
        
        DateTime.DateFormat = "yyyyMMdd_hhmmss"
        ErrorFile = "Error_" & DateTime.Date(DateTime.Now) & ".txt"
                    
        Wait For (ProcessJob) Complete (result As Boolean)
        StartMessageLoop
    Catch
        Log(LastException)
        WriteLog(LastException)
        ExitApplication2(1)
    End Try
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub ProcessJob As ResumableSub   
    Try       
        Dim TimeStamp As Long = DateTime.Now / 1000
        'Log("TimeStamp: " & TimeStamp)
        
        Dim API As String = "/api/v1/orders/get"
        Dim URL As String = ENDPOINT & API
        Log("URL:")
        Log(URL)
        Dim payload As Map = CreateMap("partner_id": PARTNER_ID, "shopid": 220052636, "timestamp": TimeStamp, "order_status": "COMPLETED")
        Dim strJSON As String = Map2Json(payload)
        Log("JSON:")
        Log(strJSON)
        
        Dim SignatureBase As String = GenerateSignatureBaseString(URL, strJSON)

        Dim result As String
        Dim Job As HttpJob
        Job.Initialize("Job", Me)
        Job.PostMultipart(URL, payload, Null)
        'Job.GetRequest.SetContentType("application/json")
        'Job.PostBytes(URL, strJSON.GetBytes("UTF8"))
        'Job.PostString(URL, strJSON)
        'Job.GetRequest.SetHeader("Cache-Control", "no-cache")
        Job.GetRequest.SetContentType("application/json")
        Dim b As Int = CalculateContentLength(strJSON)
        Job.GetRequest.SetHeader("Content-Length", b)
        'Job.GetRequest.SetHeader("Host", "https://partner.uat.shopeemobile.com")
        'Job.GetRequest.SetHeader("Accept", "*/*")
        Job.GetRequest.SetHeader("Cookie", "SC_DFP=W6p9pMGbT2QyuP1u5eA82707acPoFzpT")       
        Job.GetRequest.SetHeader("User-Agent", "PostmanRuntime/7.26.8")
        Job.GetRequest.SetHeader("Authorization", SignatureBase)
        Wait For(Job) JobDone(Job As HttpJob)
        If Job.Success Then
            result = Job.GetString
            Job.Release
            Log(result)
            StopMessageLoop '<----
            'ExitApplication2(0)
        Else
            result = Job.ErrorMessage
            Job.Release
            Log(result)
            WriteLog(result)
            StopMessageLoop '<----
            ExitApplication2(1)
        End If
    Catch
        LogError(LastException)
    End Try
    Return True
End Sub

Sub LoadSettings(Path As String)
    Try
        Dim settings As Map = File.ReadMap(Path, "Settings.ini")
        BUILD = settings.Get("BUILD")
        If BUILD = "DEVELOPMENT" Then
            ENDPOINT = settings.Get("DEVELOPMENT_ENDPOINT")           
            PARTNER_ID = settings.Get("DEVELOPMENT_PARTNER_ID")
            API_KEY = settings.Get("DEVELOPMENT_API_KEY")
        Else
            ENDPOINT = settings.Get("PRODUCTION_ENDPOINT")           
            PARTNER_ID = settings.Get("PRODUCTION_PARTNER_ID")
            API_KEY = settings.Get("PRODUCTION_API_KEY")
        End If
    Catch
        Log(LastException)
        WriteLog(LastException)
        ExitApplication2(1)
    End Try
End Sub

Sub WriteLog(Message As String)
    DateTime.DateFormat = "yyyy-MM-dd hh:mm:ss a"
    File.WriteString(strPath, ErrorFile, DateTime.Date(DateTime.Now) & CRLF & Message)
End Sub

Sub Map2Json(M As Map) As String
    Dim gen As JSONGenerator
    gen.Initialize(M)
    Return gen.ToString
End Sub

Sub CalculateContentLength(Payload As String) As Long
    Dim b() As Byte = Payload.GetBytes("UTF8")
    Return b.Length
End Sub

Sub GenerateSignatureBaseString(URL As String, Body As String) As String
    Dim nonce As String = URL & "|" & Body   
    Dim m As Mac
    Dim k As KeyGenerator
    k.Initialize("HMACSHA256")
    k.KeyFromBytes(API_KEY.GetBytes("UTF8"))
    m.Initialise("HMACSHA256", k.Key)
    m.Update(nonce.GetBytes("UTF8"))
    Dim b() As Byte
    b = m.Sign
    Dim bc As ByteConverter
    Dim signature As String = bc.HexFromBytes(b)
    Log("Authorization:")
    Log(signature)
    Return signature
End Sub
 
Last edited:

aeric

Well-Known Member
Licensed User
I solved it! I never thought I need to go this way but I succeeded!
I modified jOkHttpUtils2.b4xlib and added this sub into HttpJob.bas
B4X:
'Sends a POST request with raw JSON content-type.
Public Sub PostRawJson(Link As String, JSON As String)
    Dim stream As OutputStream
    stream.InitializeToBytesArray(0)
    Dim b() As Byte
    b = JSON.GetBytes("UTF8")
    stream.WriteBytes(b, 0, b.Length)
    PostBytes(Link, stream.ToBytesArray)
    req.SetContentType("application/json")
    req.SetContentEncoding("UTF8")
End Sub
Then call the function like this:
B4X:
Dim Job As HttpJob
Job.Initialize("Job", Me)
Job.PostRawJson(URL, strJSON)
Job.GetRequest.SetHeader("Authorization", SignatureBase)
 

aeric

Well-Known Member
Licensed User
Actually it is equivalent to:
B4X:
Dim Job As HttpJob
Job.Initialize("Job", Me)
Dim data() As Byte
data = strJSON.GetBytes("UTF8")
Job.PostBytes(URL, data)
Job.GetRequest.SetContentType("application/json")
Job.GetRequest.SetHeader("Authorization", SignatureBase)
 
Top