Как сделать поле, допускающее значение NULL, в Proto3 для ответа HTTP?

Я хочу вернуть объект как HTTP-ответ, в котором одно из его полей допускает значение NULL. Проблема в том, что proto3 не позволяет мне сделать это легко. Это происходит потому, что я проанализировал указатель строки на строку, поэтому, когда указатель указывает на ноль, возникает эта ошибка runtime error: invalid memory address or nil pointer dereference

Я попытался решить эту проблему, по крайней мере, этими двумя обходными путями, которые я узнал из Интернета.

1. Использование oneof

упражнение.proto (определение сообщения)

message ExercisesData {
    string Serial = 1 [json_name="serial"];
    string Title = 2 [json_name="title"];
    oneof OptionalSubmissionSerial {
       string SubmissionSerial = 3 [json_name="submission_serial"];
}

mapper.go (для синтаксического анализа структуры Go в соответствии с прототипным сообщением)

exercise := &Exercise.ExercisesData {
           Serial:                   e.Serial,
           Title:                    e.Title,
           OptionalSubmissionSerial: &Exercise.ExercisesData_SubmissionSerial{
                SubmissionSerial: *e.SubmissionInfo.LatestSubmissionSerial,
           },
}

2. Использование google / protobuf / wrappers.proto.

упражнение.proto (определение сообщения)

import "google/protobuf/wrappers.proto";

message ExercisesData {
    string Serial = 1 [json_name="serial"];
    string Title = 2 [json_name="title"];
    google.protobuf.StringValue SubmissionSerial = 3 [json_name="submission_serial"];
}

mapper.go (для синтаксического анализа структуры Go в соответствии с прототипным сообщением)

exercise := &Exercise.ExercisesData {
           Serial:                   e.Serial,
           Title:                    e.Title,
           SubmissionSerial:         &wrappers.StringValue{
                Value: *e.SubmissionInfo.LatestSubmissionSerial,
            },
}

ожидаемый результат

Оба способа по-прежнему вызывают одно и то же сообщение об ошибке, единственная разница - это строка кода, на которую оно ссылается. Вот почему я такой беспомощный. Ожидаемый HTTP-ответ будет выглядеть так

{
    "status": "success",
    "data": [
        {
            "serial": "EXC-NT2OBHQT",
            "title": "Title of Topic Exercise",
            "submission_serial": null
        }
     ]
}

Я действительно надеюсь, что кто-нибудь сможет помочь мне найти способ определить поле, допускающее значение NULL, в proto3 для ответа Http и как проанализировать его из структуры. Спасибо!


person Hardyin Alexander Hutapea    schedule 12.09.2019    source источник
comment
Какая строка кода вызывает ошибку нулевого указателя?   -  person ConnectionLost    schedule 12.09.2019
comment
тот, где я установил значение SubmissionSerial в mapper.go   -  person Hardyin Alexander Hutapea    schedule 13.09.2019


Ответы (2)


Оказывается, я нашел другое решение, которое действительно работает! Он использует google / protobuf / wrappers.proto, но мне нужно немного подправить его в картографе. Вот как это происходит:

упражнение.proto (определение сообщения)

import "google/protobuf/wrappers.proto";

message ExercisesData {
    string Serial = 1 [json_name="serial"];
    string Title = 2 [json_name="title"];
    google.protobuf.StringValue SubmissionSerial = 3 [json_name="submission_serial"];
}

mapper.go (для синтаксического анализа структуры Go в соответствии с прототипным сообщением)

import "github.com/golang/protobuf/ptypes/wrappers"

        exercise := &pbExercise.GetExercisesData{
            Serial:              e.Serial,
            Title:               e.Title,
        }

        if e.SubmissionInfo.LatestSubmissionSerial != nil {
            exercise.SubmissionSerial = &wrappers.StringValue{
                Value: *e.LatestSubmissionSerial,
            }
        }
person Hardyin Alexander Hutapea    schedule 13.09.2019

Я предполагаю, что вы установили syntax = proto3;. Я не думаю, что есть способ добиться того, чего вы хотите в данный момент. Проверьте эту проблему.

Но если ты хочешь жить с

{"serial":"serial","title":"title"}

где submission_serial вообще отсутствует в отличие от

{"serial":"serial","title":"title","submission_serial":null}

чем следующее работает нормально

// ...
data := &ExercisesData{Serial: "serial", Title: "title"}

out, err := proto.Marshal(data)
if err != nil {
  log.Fatalln("failed to encode: ", err)
}

buf := &bytes.Buffer{}
marshaler := jsonpb.Marshaler{}

err = marshaler.Marshal(buf, data)

data2 := &ExercisesData{}
if err := proto.Unmarshal(out, data2); err != nil {
  log.Fatalln("failed to parse: ", err)
}
// ...
person Tom Trebicky    schedule 12.09.2019