How to return a BIM360 based model's custom attributes and description
Tags: forge, aps, autodesk, buildinginformationmodelling
Published: 2024-05-04 14:11:53


## Introduction

Autodesk has updated and renamed their Common Data Environment (CDE) from BIM360 to Autodesk Construction Cloud (ACC). For highways designers or other infrastructre engineers, who use Civil3D, an important part of the ecosystem of Autodesk's suite of AEC applications, the ability to reference ACC custom attributes into your drawings/models is lacking, potentially affecting model quality.

Custom attributes are defined by the BIM360/ACC project adminstrator, and can vary from project to project. 

Until now it had been impossible, however Autodesk has recently exposed its ACC API custom attributes. By using a POST method, one can retrieve custom attributes as documented by Autodesk here: 
[Custom attributes documentation](https://aps.autodesk.com/en/docs/acc/v1/reference/http/document-management-versionsbatch-get-POST/)

However this will not include the model description, even though it is technically a custom attribute. Using the GET request documented below, will return the description attribute: 
[Description attribute documentation](https://aps.autodesk.com/en/docs/data/v2/reference/http/projects-project_id-folders-folder_id-contents-GET/)

So, how can we return both the Custom attributes and Description of a model? Well, I have used python to acheieve this and its availabe as a toolkit here: [APSTooler](https://github.com/01U2/APSTooler.git)


### Description:
*The APStooler module provides functions to retrieve model details from Autodesk's BIM360 platform.*

### Functions:
`_get_model_desc(self, project_id, folder_id, model_name)`
   - Description: Recursively retrieves model descriptions from the specified specified project and folder
   - Parameters:
     - `project_id` (str): The ID of the BIM360 project.
     - `folder_id` (str): The ID of the folder within the project.
     - `model_name` (str): Optional. The name of the model to retrieve. If not specified, retrieves all models.
   - Returns:
     - list: A list of tuples containing model details (ID, display name, version, description).

```python
    def _get_model_desc(self, project_id, folder_id, model_name):
        url = f"{self.host}/data/v1/projects/{project_id}/folders/{folder_id}/contents"
        data = self._get(url)
        model_details = []
        for item in data:
            if item['type'] == 'folders':
                model_details.extend(self._get_model_desc(project_id, item['id'], model_name))
            elif model_name is None or item['attributes']['name'] == model_name:
                model_attributes = item['attributes'].get('extension', {})
                version = model_attributes.get('version', None)
                description = model_attributes.get('data', {}).get('description', None)
                model_details.append((item['id'], item['attributes']['displayName'], version, description))
                if model_name:
                    break
        return model_details
```


`_get_model_details(self, project_id, model_desc)`
   - Description: Retrieves detailed information for each model description.
   - Parameters:
     - `project_id` (str): The ID of the BIM360 project.
     - `model_desc` (list): A list of tuples containing model descriptions.
   - Returns:
     - list: A list of dictionaries containing detailed model information.

```Python
    def _get_model_details(self, project_id, model_desc):
        url = f"{self.host}/bim360/docs/v1/projects/{project_id}/versions:batch-get"
        data = {"urns": [item[0] for item in model_desc]}
        results = self._post(url, data)["results"]
        model_details = []

        for i, result in enumerate(results):
            model_attributes = {attr['name']: attr['value'] for attr in result.get('customAttributes', [])}
            formatted_result = {
                'itemUrn': result.get('itemUrn', ''),
                'name': result.get('name', ''),
                'title': result.get('title', ''),
                'description': model_desc[i][3],
                'Status': model_attributes.get('Status', ''),
                'Revision Status': model_attributes.get('Revision Status', ''),
                'MCHW Series': model_attributes.get('MCHW Series', '')
            }
            model_details.append(formatted_result)

        return model_details
```

### Example results

![How to get all ACC model custom description]
(https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4p72mtz7lw6sy6bjibct.jpg)

### Conclusion

In the next part, I would be showing how you can use the generated attibutes to populate your title blocks.