Skip to content

Commit

Permalink
gRPC JSON transcoding: Fix request body OpenAPI (dotnet#47513)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK authored Apr 2, 2023
1 parent 954d42b commit 0b10e13
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ private static ApiDescription CreateApiDescription(RouteEndpoint routeEndpoint,
{
// If from a property, create model as property to get its XML comments.
var identity = bodyDescriptor.PropertyInfo != null
? ModelMetadataIdentity.ForProperty(bodyDescriptor.PropertyInfo, bodyDescriptor.Descriptor.ClrType, bodyDescriptor.PropertyInfo.DeclaringType!)
? ModelMetadataIdentity.ForProperty(bodyDescriptor.PropertyInfo, bodyDescriptor.PropertyInfo.PropertyType, bodyDescriptor.PropertyInfo.DeclaringType!)
: ModelMetadataIdentity.ForType(bodyDescriptor.Descriptor.ClrType);

// Or if from a parameter, create model as parameter to get its XML comments.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.AspNetCore.Grpc.Swagger.Tests.Infrastructure;
using Microsoft.AspNetCore.Grpc.Swagger.Tests.Services;
using Microsoft.OpenApi.Models;
using Xunit.Abstractions;

namespace Microsoft.AspNetCore.Grpc.Swagger.Tests.Binding;

public class BodyTests
{
private readonly ITestOutputHelper _testOutputHelper;

public BodyTests(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}

[Fact]
public void PostRepeated()
{
// Arrange & Act
var swagger = OpenApiTestHelpers.GetOpenApiDocument<BodyService>(_testOutputHelper);

// Assert
var path = swagger.Paths["/v1/body1"];
Assert.True(path.Operations.TryGetValue(OperationType.Post, out var operation));

var bodySchema = operation.RequestBody.Content["application/json"].Schema;
Assert.Null(bodySchema.Reference);
Assert.Equal("array", bodySchema.Type);
Assert.Equal("RequestBody", bodySchema.Items.Reference.Id);

var messageSchema = swagger.ResolveReference(bodySchema.Items.Reference);
Assert.NotNull(messageSchema);
}

[Fact]
public void PostMap()
{
// Arrange & Act
var swagger = OpenApiTestHelpers.GetOpenApiDocument<BodyService>(_testOutputHelper);

// Assert
var path = swagger.Paths["/v1/body2"];
Assert.True(path.Operations.TryGetValue(OperationType.Post, out var operation));

var bodySchema = operation.RequestBody.Content["application/json"].Schema;
Assert.Null(bodySchema.Reference);
Assert.Equal("object", bodySchema.Type);
Assert.Equal("integer", bodySchema.AdditionalProperties.Type);
}

[Fact]
public void PostMessage()
{
// Arrange & Act
var swagger = OpenApiTestHelpers.GetOpenApiDocument<BodyService>(_testOutputHelper);

// Assert
var path = swagger.Paths["/v1/body3"];
Assert.True(path.Operations.TryGetValue(OperationType.Post, out var operation));

var bodySchema = operation.RequestBody.Content["application/json"].Schema;
Assert.Equal("RequestBody", bodySchema.Reference.Id);
}

[Fact]
public void PostRoot()
{
// Arrange & Act
var swagger = OpenApiTestHelpers.GetOpenApiDocument<BodyService>(_testOutputHelper);

// Assert
var path = swagger.Paths["/v1/body4"];
Assert.True(path.Operations.TryGetValue(OperationType.Post, out var operation));

var bodySchema = operation.RequestBody.Content["application/json"].Schema;
Assert.Equal("RequestOne", bodySchema.Reference.Id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using Microsoft.OpenApi.Models;
using Xunit.Abstractions;

namespace Microsoft.AspNetCore.Grpc.Swagger.Tests.Parameters;
namespace Microsoft.AspNetCore.Grpc.Swagger.Tests.Binding;

public class ParametersTests
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand All @@ -7,6 +7,7 @@

<ItemGroup>
<Protobuf Include="Proto\counter.proto" GrpcServices="Both" />
<Protobuf Include="Proto\body.proto" GrpcServices="Both" />
<Protobuf Include="Proto\parameters.proto" GrpcServices="Both" />
<Protobuf Include="Proto\xmldoc.proto" GrpcServices="Both" />
<Protobuf Include="Proto\greeter.proto" GrpcServices="Both" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

syntax = "proto3";

package body;

import "google/api/annotations.proto";

// Add go_package to keep protoc happy when testing generating OpenAPI from commandline.
option go_package = "github.com/dotnet/aspnetcore/swagger";

// HttpRule: https://cloud.google.com/endpoints/docs/grpc-service-config/reference/rpc/google.api#google.api.HttpRule

service Body {
rpc DemoBodyOne (RequestOne) returns (BodyParamResponse) {
option (google.api.http) = {
post: "/v1/body1",
body: "parameter_one"
};
}
rpc DemoBodyTwo (RequestOne) returns (BodyParamResponse) {
option (google.api.http) = {
post: "/v1/body2",
body: "parameter_two"
};
}
rpc DemoBodyThree (RequestOne) returns (BodyParamResponse) {
option (google.api.http) = {
post: "/v1/body3",
body: "parameter_three"
};
}
rpc DemoBodyFour (RequestOne) returns (BodyParamResponse) {
option (google.api.http) = {
post: "/v1/body4",
body: "*"
};
}
}

message RequestOne {
repeated RequestBody parameter_one = 1;
map<int32, int32> parameter_two = 2;
RequestBody parameter_three = 3;
}

message RequestBody {
string request_body = 1;
}

message BodyParamResponse {
string message = 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Params;

namespace Microsoft.AspNetCore.Grpc.Swagger.Tests.Services;

public class BodyService : Body.Body.BodyBase
{
}

0 comments on commit 0b10e13

Please sign in to comment.