in src/Core/Services/RestService.cs [63:206]
public async Task<IActionResult?> ExecuteAsync(
string entityName,
EntityActionOperation operationType,
string? primaryKeyRoute)
{
_requestValidator.ValidateEntity(entityName);
string dataSourceName = _runtimeConfigProvider.GetConfig().GetDataSourceNameFromEntityName(entityName);
ISqlMetadataProvider sqlMetadataProvider = _sqlMetadataProviderFactory.GetMetadataProvider(dataSourceName);
DatabaseObject dbObject = sqlMetadataProvider.EntityToDatabaseObject[entityName];
if (dbObject.SourceType is not EntitySourceType.StoredProcedure)
{
await AuthorizationCheckForRequirementAsync(resource: entityName, requirement: new EntityRoleOperationPermissionsRequirement());
}
else
{
await AuthorizationCheckForRequirementAsync(resource: entityName, requirement: new StoredProcedurePermissionsRequirement());
}
QueryString? query = GetHttpContext().Request.QueryString;
string queryString = query is null ? string.Empty : GetHttpContext().Request.QueryString.ToString();
string requestBody = string.Empty;
using (StreamReader reader = new(GetHttpContext().Request.Body))
{
requestBody = await reader.ReadToEndAsync();
}
RestRequestContext context;
// If request has resolved to a stored procedure entity, initialize and validate appropriate request context
if (dbObject.SourceType is EntitySourceType.StoredProcedure)
{
if (!IsHttpMethodAllowedForStoredProcedure(entityName))
{
throw new DataApiBuilderException(
message: "This operation is not supported.",
statusCode: HttpStatusCode.MethodNotAllowed,
subStatusCode: DataApiBuilderException.SubStatusCodes.BadRequest);
}
PopulateStoredProcedureContext(
operationType,
dbObject,
entityName,
queryString,
primaryKeyRoute,
requestBody,
out context);
}
else
{
switch (operationType)
{
case EntityActionOperation.Read:
context = new FindRequestContext(
entityName,
dbo: dbObject,
isList: string.IsNullOrEmpty(primaryKeyRoute));
break;
case EntityActionOperation.Insert:
RequestValidator.ValidatePrimaryKeyRouteAndQueryStringInURL(operationType, primaryKeyRoute, queryString);
JsonElement insertPayloadRoot = RequestValidator.ValidateAndParseRequestBody(requestBody);
context = new InsertRequestContext(
entityName,
dbo: dbObject,
insertPayloadRoot,
operationType);
if (context.DatabaseObject.SourceType is EntitySourceType.Table)
{
_requestValidator.ValidateInsertRequestContext((InsertRequestContext)context);
}
break;
case EntityActionOperation.Delete:
RequestValidator.ValidatePrimaryKeyRouteAndQueryStringInURL(operationType, primaryKeyRoute);
context = new DeleteRequestContext(entityName,
dbo: dbObject,
isList: false);
break;
case EntityActionOperation.Update:
case EntityActionOperation.UpdateIncremental:
case EntityActionOperation.Upsert:
case EntityActionOperation.UpsertIncremental:
RequestValidator.ValidatePrimaryKeyRouteAndQueryStringInURL(operationType, primaryKeyRoute);
JsonElement upsertPayloadRoot = RequestValidator.ValidateAndParseRequestBody(requestBody);
context = new UpsertRequestContext(
entityName,
dbo: dbObject,
upsertPayloadRoot,
operationType);
if (context.DatabaseObject.SourceType is EntitySourceType.Table)
{
_requestValidator.ValidateUpsertRequestContext((UpsertRequestContext)context);
}
break;
default:
throw new DataApiBuilderException(
message: "This operation is not supported.",
statusCode: HttpStatusCode.BadRequest,
subStatusCode: DataApiBuilderException.SubStatusCodes.BadRequest);
}
if (!string.IsNullOrEmpty(primaryKeyRoute))
{
// After parsing primary key, the Context will be populated with the
// correct PrimaryKeyValuePairs.
RequestParser.ParsePrimaryKey(primaryKeyRoute, context);
_requestValidator.ValidatePrimaryKey(context);
}
if (!string.IsNullOrWhiteSpace(queryString))
{
context.ParsedQueryString = HttpUtility.ParseQueryString(queryString);
RequestParser.ParseQueryString(context, sqlMetadataProvider);
}
}
// At this point for DELETE, the primary key should be populated in the Request Context.
_requestValidator.ValidateRequestContext(context);
// The final authorization check on columns occurs after the request is fully parsed and validated.
// Stored procedures do not yet have semantics defined for column-level permissions
if (dbObject.SourceType is not EntitySourceType.StoredProcedure)
{
await AuthorizationCheckForRequirementAsync(resource: context, requirement: new ColumnsPermissionsRequirement());
}
switch (operationType)
{
case EntityActionOperation.Read:
return await DispatchQuery(context, sqlMetadataProvider.GetDatabaseType());
case EntityActionOperation.Insert:
case EntityActionOperation.Delete:
case EntityActionOperation.Update:
case EntityActionOperation.UpdateIncremental:
case EntityActionOperation.Upsert:
case EntityActionOperation.UpsertIncremental:
return await DispatchMutation(context, sqlMetadataProvider.GetDatabaseType());
default:
throw new NotSupportedException("This operation is not yet supported.");
}
}