Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,27 @@ await SetupAndRunRestApiTest(
);
}

/// <summary>
/// Tests that a cast failure of primary key value type results in HTTP 400 Bad Request.
/// e.g. Attempt to cast a string '{}' to the 'id' column type of int will fail.
/// </summary>
[TestMethod]
public async Task DeleteWithUncastablePKValue()
{
await SetupAndRunRestApiTest(
primaryKeyRoute: "id/{}",
queryString: string.Empty,
entityNameOrPath: _integrationEntityName,
sqlQuery: string.Empty,
operationType: Operation.Delete,
requestBody: string.Empty,
exceptionExpected: true,
expectedErrorMessage: "Parameter \"{}\" cannot be resolved as column \"id\" with type \"Int32\".",
expectedStatusCode: HttpStatusCode.BadRequest,
expectedSubStatusCode: DataApiBuilderException.SubStatusCodes.BadRequest.ToString()
);
}

/// <summary>
/// DeleteWithSqlInjectionTest attempts to inject a SQL statement
/// through the primary key route of a delete operation.
Expand Down
18 changes: 18 additions & 0 deletions src/Service.Tests/SqlTests/RestApiTests/Find/FindApiTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,24 @@ await SetupAndRunRestApiTest(
);
}

/// <summary>
/// Tests that a cast failure of primary key value type results in HTTP 400 Bad Request.
/// e.g. Attempt to cast a string '{}' to the 'id' column type of int will fail.
/// </summary>
[TestMethod]
public async Task FindWithUncastablePKValue()
{
await SetupAndRunRestApiTest(
primaryKeyRoute: "id/{}",
queryString: string.Empty,
entityNameOrPath: _integrationEntityName,
sqlQuery: null,
exceptionExpected: true,
expectedErrorMessage: "Parameter \"{}\" cannot be resolved as column \"id\" with type \"Int32\".",
expectedStatusCode: HttpStatusCode.BadRequest
);
}

/// <summary>
/// Tests the REST Api for FindById operation with attempts at
/// Sql Injection in the primary key route.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,32 @@ await SetupAndRunRestApiTest(
);
}

/// <summary>
/// Tests that a cast failure of primary key value type results in HTTP 400 Bad Request.
/// e.g. Attempt to cast a string '{}' to the 'publisher_id' column type of int will fail.
/// </summary>
[TestMethod]
public async Task InsertWithUncastablePKValue()
{
string requestBody = @"
{
""title"": ""BookTitle"",
""publisher_id"": ""StringFailsToCastToInt""
}";

await SetupAndRunRestApiTest(
primaryKeyRoute: string.Empty,
queryString: string.Empty,
entityNameOrPath: _integrationEntityName,
sqlQuery: null,
operationType: Operation.Insert,
requestBody: requestBody,
exceptionExpected: true,
expectedErrorMessage: "Parameter \"StringFailsToCastToInt\" cannot be resolved as column \"publisher_id\" with type \"Int32\".",
expectedStatusCode: HttpStatusCode.BadRequest
);
}

/// <summary>
/// Tests the InsertOne functionality with a missing field in the request body:
/// A non-nullable field in the Json Body is missing.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,31 @@ await SetupAndRunRestApiTest(
);
}

/// <summary>
/// Tests that a cast failure of primary key value type results in HTTP 400 Bad Request.
/// e.g. Attempt to cast a string '{}' to the 'publisher_id' column type of int will fail.
/// </summary>
[TestMethod]
public async Task PatchWithUncastablePKValue()
{
string requestBody = @"
{
""publisher_id"": ""StringFailsToCastToInt""
}";

await SetupAndRunRestApiTest(
primaryKeyRoute: "id/1",
queryString: string.Empty,
entityNameOrPath: _integrationEntityName,
sqlQuery: null,
operationType: Operation.UpsertIncremental,
requestBody: requestBody,
exceptionExpected: true,
expectedErrorMessage: "Parameter \"StringFailsToCastToInt\" cannot be resolved as column \"publisher_id\" with type \"Int32\".",
expectedStatusCode: HttpStatusCode.BadRequest
);
}

/// <summary>
/// Tests the Patch functionality with a REST PATCH request
/// without a primary key route. We expect a failure and so
Expand Down
26 changes: 26 additions & 0 deletions src/Service.Tests/SqlTests/RestApiTests/Put/PutApiTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,32 @@ await SetupAndRunRestApiTest(
);
}

/// <summary>
/// Tests that a cast failure of primary key value type results in HTTP 400 Bad Request.
/// e.g. Attempt to cast a string '{}' to the 'publisher_id' column type of int will fail.
/// </summary>
[TestMethod]
public async Task PutWithUncastablePKValue()
{
string requestBody = @"
{
""title"": ""BookTitle"",
""publisher_id"": ""StringFailsToCastToInt""
}";

await SetupAndRunRestApiTest(
primaryKeyRoute: "id/1",
queryString: string.Empty,
entityNameOrPath: _integrationEntityName,
sqlQuery: null,
operationType: Operation.Upsert,
requestBody: requestBody,
exceptionExpected: true,
expectedErrorMessage: "Parameter \"StringFailsToCastToInt\" cannot be resolved as column \"publisher_id\" with type \"Int32\".",
expectedStatusCode: HttpStatusCode.BadRequest
);
}

/// <summary>
/// Tests the Put functionality with a REST PUT request
/// with the request body having null value for non-nullable column
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@ public Type GetColumnSystemType(string columnName)
}
else
{
throw new ArgumentException($"{columnName} is not a valid column of {DatabaseObject.Name}");
throw new DataApiBuilderException(
message: $"{columnName} is not a valid column of {DatabaseObject.Name}",
statusCode: HttpStatusCode.BadRequest,
subStatusCode: DataApiBuilderException.SubStatusCodes.BadRequest
);
}
}

Expand Down Expand Up @@ -205,17 +209,14 @@ protected object GetParamAsColumnSystemType(string param, string columnName)
{
return ParseParamAsSystemType(param, systemType);
}
catch (Exception e)
catch (Exception e) when (e is FormatException || e is ArgumentNullException || e is OverflowException)
{
if (e is FormatException ||
e is ArgumentNullException ||
e is OverflowException)
{
throw new ArgumentException($"Parameter \"{param}\" cannot be resolved as column \"{columnName}\" " +
$"with type \"{systemType.Name}\".");
}

throw;
throw new DataApiBuilderException(
message: $"Parameter \"{param}\" cannot be resolved as column \"{columnName}\" " +
$"with type \"{systemType.Name}\".",
statusCode: HttpStatusCode.BadRequest,
subStatusCode: DataApiBuilderException.SubStatusCodes.BadRequest,
innerException: e);
}
}

Expand Down