// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.cloud.dataplex.v1;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/field_info.proto";
import "google/api/resource.proto";
import "google/cloud/dataplex/v1/approval_workflow.proto";
import "google/cloud/dataplex/v1/service.proto";
import "google/longrunning/operations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";

option go_package = "cloud.google.com/go/dataplex/apiv1/dataplexpb;dataplexpb";
option java_multiple_files = true;
option java_outer_classname = "DataProductsProto";
option java_package = "com.google.cloud.dataplex.v1";

// `DataProductService` provides APIs for managing data products and
// the underlying data assets.
service DataProductService {
  option (google.api.default_host) = "dataplex.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform,"
      "https://www.googleapis.com/auth/cloud-platform.read-only,"
      "https://www.googleapis.com/auth/dataplex.read-write,"
      "https://www.googleapis.com/auth/dataplex.readonly";

  // Creates a data product.
  rpc CreateDataProduct(CreateDataProductRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*}/dataProducts"
      body: "data_product"
    };
    option (google.api.method_signature) =
        "parent,data_product,data_product_id";
    option (google.longrunning.operation_info) = {
      response_type: "DataProduct"
      metadata_type: "OperationMetadata"
    };
  }

  // Deletes a data product. The deletion will fail if the data product is not
  // empty (i.e. contains at least one data asset).
  rpc DeleteDataProduct(DeleteDataProductRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      delete: "/v1/{name=projects/*/locations/*/dataProducts/*}"
    };
    option (google.api.method_signature) = "name";
    option (google.longrunning.operation_info) = {
      response_type: "google.protobuf.Empty"
      metadata_type: "OperationMetadata"
    };
  }

  // Gets a data product.
  rpc GetDataProduct(GetDataProductRequest) returns (DataProduct) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/dataProducts/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Lists data products for a given project.
  rpc ListDataProducts(ListDataProductsRequest)
      returns (ListDataProductsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*}/dataProducts"
    };
    option (google.api.method_signature) = "parent";
  }

  // Updates a data product.
  rpc UpdateDataProduct(UpdateDataProductRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      patch: "/v1/{data_product.name=projects/*/locations/*/dataProducts/*}"
      body: "data_product"
    };
    option (google.api.method_signature) = "data_product,update_mask";
    option (google.longrunning.operation_info) = {
      response_type: "DataProduct"
      metadata_type: "OperationMetadata"
    };
  }

  // Requests access to a data product. This will trigger an access approval
  // workflow, and the requester will need to wait for the approval to be
  // granted before they will be able to access the data product assets.
  rpc RequestDataProductAccess(RequestDataProductAccessRequest)
      returns (RequestDataProductAccessResponse) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*/dataProducts/*}:requestAccess"
      body: "*"
    };
    option (google.api.method_signature) = "parent,change_request";
  }

  // Creates a data asset.
  rpc CreateDataAsset(CreateDataAssetRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*/dataProducts/*}/dataAssets"
      body: "data_asset"
    };
    option (google.api.method_signature) = "parent,data_asset,data_asset_id";
    option (google.longrunning.operation_info) = {
      response_type: "DataAsset"
      metadata_type: "OperationMetadata"
    };
  }

  // Updates a data asset.
  rpc UpdateDataAsset(UpdateDataAssetRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      patch: "/v1/{data_asset.name=projects/*/locations/*/dataProducts/*/dataAssets/*}"
      body: "data_asset"
    };
    option (google.api.method_signature) = "data_asset,update_mask";
    option (google.longrunning.operation_info) = {
      response_type: "DataAsset"
      metadata_type: "OperationMetadata"
    };
  }

  // Deletes a data asset.
  rpc DeleteDataAsset(DeleteDataAssetRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      delete: "/v1/{name=projects/*/locations/*/dataProducts/*/dataAssets/*}"
    };
    option (google.api.method_signature) = "name";
    option (google.longrunning.operation_info) = {
      response_type: "google.protobuf.Empty"
      metadata_type: "OperationMetadata"
    };
  }

  // Gets a data asset.
  rpc GetDataAsset(GetDataAssetRequest) returns (DataAsset) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/dataProducts/*/dataAssets/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Lists data assets for a given data product.
  rpc ListDataAssets(ListDataAssetsRequest) returns (ListDataAssetsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*/dataProducts/*}/dataAssets"
    };
    option (google.api.method_signature) = "parent";
  }
}

// A data product is a curated collection of data assets, packaged to address
// specific use cases. It's a way to manage and share data in a more organized,
// product-like manner.
message DataProduct {
  option (google.api.resource) = {
    type: "dataplex.googleapis.com/DataProduct"
    pattern: "projects/{project}/locations/{location}/dataProducts/{data_product}"
    plural: "dataProducts"
    singular: "dataProduct"
  };

  // Represents the principal entity associated with an access group, as per
  // https://cloud.google.com/iam/docs/principals-overview.
  message Principal {
    // The type of the principal entity.
    oneof type {
      // Optional. Email of the Google Group, as per
      // https://cloud.google.com/iam/docs/principals-overview#google-group.
      string google_group = 1 [(google.api.field_behavior) = OPTIONAL];
    }

    // Optional. Specifies the email of the producer service account, as per
    // https://cloud.google.com/iam/docs/principals-overview#service-account.
    optional string service_account = 2
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Custom user defined access groups at the data product level. These are used
  // for granting different levels of access (IAM roles) on the individual data
  // product's data assets.
  message AccessGroup {
    // Required. Unique identifier of the access group within the data product.
    // User defined. Eg. "analyst", "developer", etc.
    string id = 1 [(google.api.field_behavior) = REQUIRED];

    // Required. User friendly display name of the access group.
    // Eg. "Analyst", "Developer", etc.
    string display_name = 2 [(google.api.field_behavior) = REQUIRED];

    // Optional. Description of the access group.
    string description = 3 [(google.api.field_behavior) = OPTIONAL];

    // Required. The principal entity associated with this access group.
    Principal principal = 4 [(google.api.field_behavior) = REQUIRED];
  }

  // Configuration for access approval for the data product.
  message AccessApprovalConfig {
    // Optional. Specifies the email addresses of users who are potential
    // approvers and are notified when an access request is made for the data
    // product. The maximum number of emails allowed is 10.
    repeated string approver_emails = 2
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Identifier. Resource name of the data product.
  // Format:
  // `projects/{project_id_or_number}/locations/{location_id}/dataProducts/{data_product_id}`.
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Output only. System generated unique ID for the data product.
  // This ID will be different if the data product is deleted and re-created
  // with the same name.
  string uid = 2 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OUTPUT_ONLY
  ];

  // Required. User-friendly display name of the data product.
  string display_name = 3 [(google.api.field_behavior) = REQUIRED];

  // Output only. The time at which the data product was created.
  google.protobuf.Timestamp create_time = 4
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time at which the data product was last updated.
  google.protobuf.Timestamp update_time = 5
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. This checksum is computed by the server based on the value of
  // other fields, and may be sent on update and delete requests to ensure the
  // client has an up-to-date value before proceeding.
  string etag = 6 [(google.api.field_behavior) = OPTIONAL];

  // Optional. User-defined labels for the data product.
  //
  // Example:
  //  ```
  //  {
  //    "environment": "production",
  //    "billing": "marketing-department"
  //  }
  //  ```
  map<string, string> labels = 7 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Description of the data product.
  string description = 8 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Base64 encoded image representing the data product. Max
  // Size: 3.0MiB Expected image dimensions are 512x512 pixels, however the API
  // only performs validation on size of the encoded data. Note: For byte
  // fields, the content of the fields are base64-encoded (which increases the
  // size of the data by 33-36%) when using JSON on the wire.
  bytes icon = 10 [(google.api.field_behavior) = OPTIONAL];

  // Required. Emails of the data product owners.
  repeated string owner_emails = 11 [(google.api.field_behavior) = REQUIRED];

  // Output only. Number of data assets associated with this data product.
  int32 asset_count = 13 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. Data product access groups by access group id as key.
  // If data product is used only for packaging data assets, then access groups
  // may be empty. However, if a data product is used for sharing data assets,
  // then at least one access group must be specified.
  //
  // Example:
  //  ```
  //  {
  //    "analyst": {
  //      "id": "analyst",
  //      "displayName": "Analyst",
  //      "description": "Access group for analysts",
  //      "principal": {
  //        "googleGroup": "analysts@example.com"
  //      }
  //    }
  //  }
  //  ```
  map<string, AccessGroup> access_groups = 14
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Configuration for access approval for the data product.
  optional AccessApprovalConfig access_approval_config = 15
      [(google.api.field_behavior) = OPTIONAL];
}

// Represents a data asset resource that can be packaged and shared via a data
// product.
message DataAsset {
  option (google.api.resource) = {
    type: "dataplex.googleapis.com/DataAsset"
    pattern: "projects/{project}/locations/{location}/dataProducts/{data_product}/dataAssets/{data_asset}"
    plural: "dataAssets"
    singular: "dataAsset"
  };

  // Configuration for access group inherited from the parent data product.
  message AccessGroupConfig {
    // Optional. IAM roles granted on the resource to this access group. Role
    // name follows https://cloud.google.com/iam/docs/reference/rest/v1/roles.
    //
    // Example: `[ "roles/bigquery.dataViewer" ]`
    repeated string iam_roles = 1 [(google.api.field_behavior) = OPTIONAL];
  }

  // Identifier. Resource name of the data asset.
  // Format:
  // projects/{project_id_or_number}/locations/{location_id}/dataProducts/{data_product_id}/dataAssets/{data_asset_id}
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Output only. System generated globally unique ID for the data asset.
  // This ID will be different if the data asset is deleted and re-created
  // with the same name.
  string uid = 2 [
    (google.api.field_info).format = UUID4,
    (google.api.field_behavior) = OUTPUT_ONLY
  ];

  // Output only. The time at which the data asset was created.
  google.protobuf.Timestamp create_time = 3
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time at which the data asset was last updated.
  google.protobuf.Timestamp update_time = 4
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. This checksum is computed by the server based on the value of
  // other fields, and may be sent on update and delete requests to ensure the
  // client has an up-to-date value before proceeding.
  string etag = 5 [(google.api.field_behavior) = OPTIONAL];

  // Optional. User-defined labels for the data asset.
  //
  // Example:
  //  ```
  //  {
  //    "environment": "production",
  //    "billing": "marketing-department"
  //  }
  //  ```
  map<string, string> labels = 6 [(google.api.field_behavior) = OPTIONAL];

  // Required. Immutable. Full resource name of the cloud resource represented
  // by the data asset. This must follow
  // https://cloud.google.com/iam/docs/full-resource-names. Example:
  // `//bigquery.googleapis.com/projects/my_project_123/datasets/dataset_456/tables/table_789`
  // Only BigQuery tables and datasets are currently supported.
  // Data asset creator must have getIamPolicy and setIamPolicy permissions on
  // the resource. Data asset creator must also have resource specific get
  // permission, for instance, bigquery.tables.get for BigQuery tables.
  string resource = 7 [
    (google.api.field_behavior) = IMMUTABLE,
    (google.api.field_behavior) = REQUIRED
  ];

  // Optional. Access groups configurations for this data asset.
  //
  // The key is `DataProduct.AccessGroup.id` and the value is
  // `AccessGroupConfig`.
  //
  // Example:
  // ```
  //  {
  //    "analyst": {
  //      "iamRoles": ["roles/bigquery.dataViewer"]
  //    }
  //  }
  // ```
  //
  // Currently, at most one IAM role is allowed per access group. For providing
  // multiple predefined IAM roles, wrap them in a custom IAM role as per
  // https://cloud.google.com/iam/docs/creating-custom-roles.
  map<string, AccessGroupConfig> access_group_configs = 9
      [(google.api.field_behavior) = OPTIONAL];
}

// Request message for creating a data product.
message CreateDataProductRequest {
  // Required. The parent resource where this data product will be created.
  // Format: projects/{project_id_or_number}/locations/{location_id}
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "locations.googleapis.com/Location"
    }
  ];

  // Optional. The ID of the data product to create.
  //
  // The ID must conform to RFC-1034 and contain only lower-case letters (a-z),
  // numbers (0-9), or hyphens, with the first character a letter, the last a
  // letter or a number, and a 63 character maximum. Characters outside of
  // ASCII are not permitted.
  // Valid format regex: `^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$`
  // If not provided, a system generated ID will be used.
  string data_product_id = 2 [(google.api.field_behavior) = OPTIONAL];

  // Required. The data product to create.
  DataProduct data_product = 3 [(google.api.field_behavior) = REQUIRED];

  // Optional. Validates the request without actually creating the data product.
  // Default: false.
  bool validate_only = 4 [(google.api.field_behavior) = OPTIONAL];
}

// Request message for deleting a data product.
message DeleteDataProductRequest {
  // Required. The name of the data product to delete.
  // Format:
  // projects/{project_id_or_number}/locations/{location_id}/dataProducts/{data_product_id}
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dataplex.googleapis.com/DataProduct"
    }
  ];

  // Optional. The etag of the data product.
  //
  // If an etag is provided and does not match the current etag of the data
  // product, then the deletion will be blocked and an ABORTED error will be
  // returned.
  string etag = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Validates the request without actually deleting the data product.
  // Default: false.
  bool validate_only = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Request message for getting a data product.
message GetDataProductRequest {
  // Required. The name of the data product to retrieve.
  // Format:
  // projects/{project_id_or_number}/locations/{location_id}/dataProducts/{data_product_id}
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dataplex.googleapis.com/DataProduct"
    }
  ];
}

// Request message for listing data products.
message ListDataProductsRequest {
  // Required. The parent, which has this collection of data products.
  //
  // Format: `projects/{project_id_or_number}/locations/{location_id}`.
  //
  // Supports listing across all locations with the wildcard `-` (hyphen)
  // character. Example: `projects/{project_id_or_number}/locations/-`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "locations.googleapis.com/Location"
    }
  ];

  // Optional. Filter expression that filters data products listed in the
  // response.
  //
  // Example of using this filter is: `display_name="my-data-product"`
  string filter = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The maximum number of data products to return. The service may
  // return fewer than this value. If unspecified, at most 50 data products will
  // be returned. The maximum value is 1000; values above 1000 will be coerced
  // to 1000.
  int32 page_size = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A page token, received from a previous `ListDataProducts` call.
  // Provide this to retrieve the subsequent page.
  //
  // When paginating, all other parameters provided to `ListDataProducts` must
  // match the call that provided the page token.
  string page_token = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Order by expression that orders data products listed in the
  // response.
  //
  // Supported Order by fields are: `name` or `create_time`.
  //
  // If not specified, the ordering is undefined.
  //
  // Ordering by `create_time` is not supported when listing resources across
  // locations (i.e. when request contains `/locations/-`).
  string order_by = 5 [(google.api.field_behavior) = OPTIONAL];
}

// Response message for listing data products.
message ListDataProductsResponse {
  // The data products for the requested filter criteria.
  repeated DataProduct data_products = 1;

  // A token, which can be sent as `page_token` to retrieve the next page.
  // If this field is empty, then there are no subsequent pages.
  string next_page_token = 2;

  // Unordered list. Locations that the service couldn't reach.
  repeated string unreachable = 3
      [(google.api.field_behavior) = UNORDERED_LIST];
}

// Request message for updating a data product.
message UpdateDataProductRequest {
  // Required. The data product to update.
  // The data product's `name` field is used to identify the data product to
  // update.
  DataProduct data_product = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. The list of fields to update.
  // If this is empty or not set, then all the fields will be updated.
  google.protobuf.FieldMask update_mask = 2
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Validates the request without actually updating the data product.
  // Default: false.
  bool validate_only = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Message for requesting access to a Data Product.
message RequestDataProductAccessRequest {
  // Required. The resource name of the data product.
  // Format:
  // projects/{project_number}/locations/{location_id}/dataProducts/{data_product_id}
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dataplex.googleapis.com/DataProduct"
    }
  ];

  // Required. The change request for the data product access request.
  ChangeRequest change_request = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. Validates the request without actually creating the access change
  // request. Defaults to false.
  bool validate_only = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Response message for requesting access to a Data Product.
message RequestDataProductAccessResponse {
  // The resource name of the created ChangeRequest.
  // Format:
  // projects/{project_number}/locations/{location_id}/changeRequests/{change_request_id}
  string change_request_name = 1 [(google.api.resource_reference) = {
    type: "dataplex.googleapis.com/ChangeRequest"
  }];
}

// Request message for creating a data asset.
message CreateDataAssetRequest {
  // Required. The parent resource where this data asset will be created.
  // Format:
  // projects/{project_id_or_number}/locations/{location_id}/dataProducts/{data_product_id}
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dataplex.googleapis.com/DataProduct"
    }
  ];

  // Optional. The ID of the data asset to create.
  //
  // The ID must conform to RFC-1034 and contain only lower-case letters (a-z),
  // numbers (0-9), or hyphens, with the first character a letter, the last a
  // letter or a number, and a 63 character maximum. Characters outside of
  // ASCII are not permitted.
  // Valid format regex: `^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$`
  // If not provided, a system generated ID will be used.
  string data_asset_id = 2 [(google.api.field_behavior) = OPTIONAL];

  // Required. The data asset to create.
  DataAsset data_asset = 3 [(google.api.field_behavior) = REQUIRED];

  // Optional. Validates the request without actually creating the data asset.
  // Defaults to false.
  bool validate_only = 4 [(google.api.field_behavior) = OPTIONAL];
}

// Request message for updating a data asset.
message UpdateDataAssetRequest {
  // Required. The data asset to update.
  // The data asset's `name` field is used to identify the data asset to update.
  DataAsset data_asset = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. The list of fields to update.
  // If this is empty or not set, then all the fields will be updated.
  google.protobuf.FieldMask update_mask = 2
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Validates the request without actually updating the data asset.
  // Defaults to false.
  bool validate_only = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Request message for deleting a data asset.
message DeleteDataAssetRequest {
  // Required. The name of the data asset to delete.
  // Format:
  // projects/{project_id_or_number}/locations/{location_id}/dataProducts/{data_product_id}/dataAssets/{data_asset_id}
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dataplex.googleapis.com/DataAsset"
    }
  ];

  // Optional. The etag of the data asset.
  // If this is provided, it must match the server's etag.
  // If the etag is provided and does not match the server-computed etag,
  // the request must fail with a ABORTED error code.
  string etag = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Validates the request without actually deleting the data asset.
  // Defaults to false.
  bool validate_only = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Request message for getting a data asset.
message GetDataAssetRequest {
  // Required. The name of the data asset to retrieve.
  // Format:
  // projects/{project_id_or_number}/locations/{location_id}/dataProducts/{data_product_id}/dataAssets/{data_asset_id}
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dataplex.googleapis.com/DataAsset"
    }
  ];
}

// Request message for listing data assets.
message ListDataAssetsRequest {
  // Required. The parent, which has this collection of data assets.
  // Format:
  // projects/{project_id_or_number}/locations/{location_id}/dataProducts/{data_product_id}
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "dataplex.googleapis.com/DataProduct"
    }
  ];

  // Optional. Filter expression that filters data assets listed in the
  // response.
  string filter = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Order by expression that orders data assets listed in the
  // response.
  //
  // Supported `order_by` fields are: `name` or `create_time`.
  //
  // If not specified, the ordering is undefined.
  string order_by = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The maximum number of data assets to return. The service may
  // return fewer than this value. If unspecified, at most 50 data assets will
  // be returned. The maximum value is 1000; values above 1000 will be coerced
  // to 1000.
  int32 page_size = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A page token, received from a previous `ListDataAssets` call.
  // Provide this to retrieve the subsequent page.
  //
  // When paginating, all other parameters provided to `ListDataAssets` must
  // match the call that provided the page token.
  string page_token = 5 [(google.api.field_behavior) = OPTIONAL];
}

// Response message for listing data assets.
message ListDataAssetsResponse {
  // The data assets for the requested filter criteria.
  repeated DataAsset data_assets = 1;

  // A token, which can be sent as `page_token` to retrieve the next page.
  // If this field is empty, then there are no subsequent pages.
  string next_page_token = 2;
}
