ข้ามไปที่เนื้อหา

ส่งและรับ JSON

ในบทช่วยสอนนี้ เราอธิบายวิธีที่คุณสามารถส่งและรับข้อความ JSON

TCP และ WebSocket

เมื่อทำงานกับ JSON คุณสามารถใช้การเชื่อมต่อ TCP หรือ WebSocket ก็ได้

ส่ง JSON

หากคุณเลือกใช้ JSON ในอินทิเกรชันของคุณ คุณจะต้องส่งสตริงที่มี JSON ที่ถูกต้องไปยัง cTrader backend วัตถุ JSON ที่ส่งผ่านสตริงเหล่านี้ต้องมีคีย์ต่อไปนี้

คีย์ ประเภทข้อมูลค่า คำจำกัดความ
"clientMsgId" สตริง ID ที่ไม่ซ้ำของข้อความ ID นี้ต้องถูกสร้างและกำหนดบนฝั่งไคลเอนต์
"payloadType" integer จำนวนเต็มที่แสดงถึงข้อความ รายการประเภท payload ที่ถูกต้องทั้งหมดรวมอยู่ใน ProtoOAPayloadType
"payload" วัตถุ JSON วัตถุ JSON ที่ซ้อนกันซึ่งมีเนื้อหาจริงของข้อความ

ตัวอย่างของสตริงที่ถูกต้อง (แทนข้อความ ProtoOAApplicationAuthReq) สามารถพบได้ด้านล่าง

"{"clientMsgId": "cm_id_2", "payloadType": 2100, "payload": {"clientId": "34Rsd_T098asHkl","clientSecret": "validClientSecret"}}"

เพื่อส่งสตริง JSON ที่ถูกต้อง คุณจะต้องสร้างกลไกการซีเรียไลเซชันแบบกำหนดเองในภาษาการเขียนโปรแกรมที่คุณเลือก

ในตัวอย่างด้านล่าง เรากำหนดวิธีการจัดการการซีเรียไลเซชันหลายวิธี คุณสามารถ (และควร) ดำเนินการของคุณเองขึ้นอยู่กับภาษาการเขียนโปรแกรมและรูปแบบการออกแบบที่คุณต้องการ

ด้านล่าง เรากำหนดคลาสฐานสองคลาสและสร้างการแสดงแบบกำหนดเองของข้อความ ProtoOAApplicationAuthReq

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public abstract class OpenAPIMessageBase
{
    public string ClientMsgId { get; set; }
    public abstract int PayloadType { get; }
}

public abstract class OpenAPIMessagePayloadBase { }

public class ApplicationAuthReq : OpenAPIMessageBase
{
    public ApplicationAuthReq() { }
    public ApplicationAuthReq(string clientId, string clientSecret)
    {
        this.Payload = new ApplicationAuthReqPayload(clientId, clientSecret);
        this.ClientMsgId = Guid.NewGuid().ToString();
    }

    public override int PayloadType => 2100;
    public ApplicationAuthReqPayload? Payload { get; set; }

}

public class ApplicationAuthReqPayload : OpenAPIMessagePayloadBase
{
    public ApplicationAuthReqPayload() { }
    public ApplicationAuthReqPayload(string clientId, string clientSecret)
    {
        this.ClientId = clientId;
        this.ClientSecret = clientSecret;
    }
    public string ClientId { get; set; } = string.Empty;
    public string ClientSecret { get; set; } = string.Empty;
}

เราสร้างคลาสฐานสำหรับข้อความ Open API ทั้งหมด และเพื่อการสาธิต เรากำหนดคลาสสำหรับ ProtoOAApplicationAuthReq

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import uuid
import json

class OpenAPIMessage:

def payloadType(self):
    pass

def payload(self):
    pass

def clientMsgId(self):
    pass

def asJsonString(self):
    pass


class ApplicationAuthReq(OpenAPIMessage):

def __init__(self, clientId, clientSecret, clientMsgId = str(uuid.uuid4())):
    self.clientId = clientId
    self.clientSecret = client_secret
    self.payloadType = 2100
    self.clientMsgId = clientMsgId
    self.payload = {"clientId": self.clientId, "clientSecret": self.clientSecret}



def asJsonString(self):
    return json.dumps({"clientMsgId": self.clientMsgId, "payloadType": self.payloadType, "payload": self.payload})

หลังจากดำเนินการตามตรรกะที่ต้องการแล้ว คุณควรสามารถส่งข้อความใหม่ไปยัง cTrader backend ได้โดยการสร้างอินสแตนซ์ใหม่ของคลาสที่แทนข้อความเหล่านี้และส่งผ่านไปยังไคลเอนต์ TCP หรือ WebSocket ที่คุณต้องการ

รับ JSON

เพื่อรับและประมวลผลข้อความ JSON คุณต้องดำเนินการวิธีการสำหรับการดีซีเรียไลซ์สตริง JSON ให้เป็นการแสดงข้อความ Open API

เพื่อดำเนินการวิธีการนี้ คุณอาจพบว่าการเริ่มต้นแผนที่ (หรือพจนานุกรม) ที่ประเภท payload สามารถเป็นคีย์ที่มีชื่อของคลาสที่แทนข้อความเป็นค่าจะเป็นประโยชน์ เพื่อการจัดการข้อยกเว้น คุณอาจต้องการตรวจสอบว่าประเภท payload ของข้อความที่คุณได้รับเป็นคีย์ในแผนที่หรือพจนานุกรมนี้หรือไม่ หากมีคีย์ดังกล่าว คุณสามารถดีซีเรียไลซ์ข้อความโดยใช้ตรรกะที่เหมาะสม

หลังจากดำเนินการวิธีการดังกล่าวแล้ว คุณอาจใช้มันเป็น callback ที่ถูกกระตุ้นทุกครั้งที่คุณได้รับข้อความใหม่

โปรดทราบว่าในตัวอย่างด้านล่าง TMessage เป็นประเภททั่วไป

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public static class MessageReceivedCallbacks
{
    public static Dictionary<int, Type> messages = new Dictionary<int, Type>
    {
        {2100, typeof(ApplicationAuthReq) },

    };

    public static TMessage ReadMessage<TMessage>(string jsonString) where TMessage : OpenAPIMessageBase
    {
        JsonDocument doc = JsonDocument.Parse(jsonString);
        int payloadType = doc.RootElement.GetProperty("payloadType").GetInt32();

        if (!messages.TryGetValue(payloadType, out var type))
            throw new Exception("This payload type is not supported");

        var result = JsonSerializer.Deserialize(jsonString, type)  as TMessage;

        return result;
    }
}

Downcasting

เมธอด ReadMessage() ไม่ได้ส่งกลับคลาสข้อความเฉพาะ คุณจะต้องจัดการ downcasting แยกต่างหากเมื่อรับข้อความ

เราเพิ่มเมธอดต่อไปนี้ในคลาส ApplicationAuthReq ของเรา

1
2
3
@staticmethod
def fromJson(jsonDct):
    return ApplicationAuthReq(clientId=jsonDct['payload']['clientId'], clientSecret=jsonDct['payload']['clientSecret'], clientMsgId=jsonDct['clientMsgId'])

จากนั้นเราเพิ่ม callback readMessage ของเราและดึง payload จากพจนานุกรม

1
2
3
4
5
6
7
8
9
class MessageReceivedCallbacks:

messagesDict = {2100: ApplicationAuthReq}

@staticmethod
def readMessage(jsonString):
    json_dct = json.loads(jsonString)
    payloadType = jsonDct['payloadType']
    return MessageReceivedCallbacks.messagesDict[payloadType].fromJson(jsonDct)

Downcasting

เนื่องจาก Python เป็น duck-typed จึงไม่จำเป็นต้องจัดการ downcasting แยกต่างหาก คุณสามารถดีซีเรียไลซ์สตริง JSON ให้เป็นประเภทที่ต้องการเมื่อรับมัน