Skip to content

Commit

Permalink
Extended protobuf eval to validate and parse json (#197)
Browse files Browse the repository at this point in the history
  • Loading branch information
tbazen authored Jan 29, 2024
1 parent e8910e3 commit a877a98
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 0 deletions.
22 changes: 22 additions & 0 deletions src/ProtoBufEval.Tests/ProtoBufValidatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,28 @@ public async Task GivenValidData_WhenValidate3_ThenHasNoError()
Assert.False(result.HasError);
}

[Fact]
public async Task GivenValidData_WhenValidateAndParse_ThenHasNoError()
{
var validJson64 = Json64(new Dictionary<string, object>
{
["field1"] = "AwesomeFirst",
["field2"] = "SecondField",
["field3"] = 333,
});
var activeSchemaVersionBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(ActiveVersion3()));

var result = await ProtoBufValidator.ValidateAndParseJson(validJson64, activeSchemaVersionBase64, "testschema");

Assert.False(result.HasError);
Assert.NotNull(result.ProtoBuf);

var obj = Serializer.Deserialize<ValidModel>(new MemoryStream(result.ProtoBuf));

Assert.Equal("AwesomeFirst", obj.Field1);
Assert.False(result.HasError);
}

private static string Proto64<TData>(TData obj) where TData : class
{
using var stream = new MemoryStream();
Expand Down
42 changes: 42 additions & 0 deletions src/ProtoBufEval/ProtoBufValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ public ProtoBufValidationResult(string? error, bool hasError)
public bool HasError { get; }
};

public class JsonValidateAndParseResult : ProtoBufValidationResult
{
public JsonValidateAndParseResult(string? error, bool hasError, byte[]? proto) : base(error, hasError)
{
ProtoBuf = proto;
}
public byte[]? ProtoBuf { get; }
}

public static class ProtoBufValidator
{
Expand Down Expand Up @@ -83,6 +91,40 @@ string schemaName
return new(result.StandardError, true);
return new(default, false);
}


/// <summary>
/// Validate a base64 encoded protobuf payload against a schema
/// </summary>
/// <param name="json64"></param>
/// <param name="activeSchemaVersionBase64"></param>
/// <param name="schemaName"></param>
/// <returns></returns>
public static async Task<JsonValidateAndParseResult> ValidateAndParseJson(
string json64,
string activeSchemaVersionBase64,
string schemaName
)
{
var result = await Cli.Wrap(_nativeBinary)
.WithArguments(new[] {
"j2p",
"--payload",json64,
"--schema", activeSchemaVersionBase64,
"--schema-name", schemaName,
})
.WithValidation(CommandResultValidation.None)
.ExecuteBufferedAsync();
if (result is { ExitCode: ProtoBufValidationError.InvalidPayload })
return new(result.StandardError, true, null);
if (string.IsNullOrWhiteSpace(result.StandardOutput))
return new(default, false, null);
var proto64 = result.StandardOutput.Trim();
var protoBytes = Convert.FromBase64String(proto64);
return new(default, false, protoBytes);
}


}

internal static class ProtoBufValidationError
Expand Down
64 changes: 64 additions & 0 deletions src/protoeval-cli/cmd/conv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cmd

import (
"context"
"encoding/base64"
"encoding/json"
"log"
"os"
"strings"

"github.com/spf13/cobra"
)

func init() {
cmd := cobra.Command{
Use: "j2p --payload=payload --schema=schema --schema-name=schema-name",
Aliases: []string{"c"},
Short: "Json to proto-buf",
Args: cobra.MaximumNArgs(0),
Run: func(cmd *cobra.Command, _ []string) {
handleConvertToProtoBuf(cmd.Context())
},
}
cmd.Flags().StringVar(&payloadBase64, "payload", "", "base64 proto-buf payload")
cmd.Flags().StringVar(&activeSchemaBase64, "schema", "", "base64 proto-buf active schema")
cmd.Flags().StringVar(&schemaName, "schema-name", "", "active schema name")
cmd.MarkFlagRequired("payload")
cmd.MarkFlagRequired("schema")
cmd.MarkFlagRequired("schema-name")
rootCmd.AddCommand(&cmd)
}

func handleConvertToProtoBuf(context context.Context) {
jsonBytes, err := base64.StdEncoding.DecodeString(payloadBase64)
if err != nil {
return
}

schemaVersion, err := unmarshalSchemaVersion(activeSchemaBase64)
if err != nil {
return
}
descriptor, err := compileDescriptor(schemaVersion, schemaName)
if err != nil {
return
}

jsonStr := string(jsonBytes)
jsonObj := make(map[string]interface{})
err = json.Unmarshal([]byte(jsonStr), &jsonObj)
if err != nil {
log.SetFlags(0)
log.Fatal(err)
}
protoBytes, err := validateProtoBufMessage(jsonObj, descriptor)
if err != nil {
log.SetFlags(0)
log.Fatal(err)
}

protoBase64 := base64.StdEncoding.EncodeToString(protoBytes)
protoBase64 = strings.TrimRight(protoBase64, "\n")
os.Stdout.WriteString(protoBase64)
}

0 comments on commit a877a98

Please sign in to comment.