v1 REST API - Part 4 - Managing Nodes

cancel
Showing results for 
Search instead for 
Did you mean: 

v1 REST API - Part 4 - Managing Nodes

gavincornwell
Senior Member
9 18 8,340

In the last post we looked at how to create files and folders in the repository, this time we're going to retrieve and update node information, retrieve and update content and remove nodes from the repository.

To keep with tradition, all of the endpoints we'll cover in this post have been provided in a Postman collection and can be imported by clicking on the "Run in Postman" button below.

button.svg

There is something a little different about this one though, it uses the testing capabilities of Postman. After the create request is executed some JavaScript is run to grab the id of the newly created file and store it in a global variable. The URL of subsequent requests in the collection then refer to the global variable using Postman's {{variable}} syntax. Explaining the full testing capabilities of Postman is beyond the scope of this blog post so I'll leave that as an exercise for the reader!

OK, let's start by creating an empty file. POST the body below using a Content-Type of application/json to http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/nodes/-my-/children

{
  "name": "content.txt",
  "nodeType": "cm:content",
  "properties": {
    "cm:title": "The Title"
  }
}

Copy the value of the id property from the resulting response (or use the first request in the Postman collection).

Now let's retrieve some information about this node. We do this by doing a GET on http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/nodes/8c37b5b7-b96f-49ef-817... (you'll obviously need to replace the id with the one you copied from your response or use the 2nd request in the Postman collection). This results in the following response:

{
  "entry": {
    "isFile": true,
    "createdByUser": {
      "id": "test",
      "displayName": "Test Test"
    },
    "modifiedAt": "2016-11-01T14:57:24.388+0000",
    "nodeType": "cm:content",
    "content": {
      "mimeType": "text\/plain",
      "mimeTypeName": "Plain Text",
      "sizeInBytes": 0,
      "encoding": "UTF-8"
    },
    "parentId": "bd8f1283-3e84-4585-aafc-12da26db760f",
    "aspectNames": [
      "cm:titled",
      "cm:auditable"
    ],
    "createdAt": "2016-11-01T14:57:24.388+0000",
    "isFolder": false,
    "modifiedByUser": {
      "id": "test",
      "displayName": "Test Test"
    },
    "name": "my-file.txt",
    "id": "8c37b5b7-b96f-49ef-817e-9808bf2309f9",
    "properties": {
      "cm:title": "The Title"
    }
  }
}

All the data returned by the /nodes/{id}/children endpoint we examined in the second post is present plus the node's properties (line 29) and a list of aspect names (line 17). As we saw with create in the previous post this endpoint is also following our "performance first" principle. If we wanted to also determine whether the node represents a link and see it's full path, we can use the include query parameter to ask for this data, for example (3rd request in the Postman collection):

http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/nodes/8c37b5b7-b96f-49ef-817...

{
  "entry": {
    "isLink": false,
    "isFolder": false,
    "isFile": true,
    "path": {
      "name": "/Company Home/User Homes/test",
      "isComplete": true,
      "elements": [
        {
          "id": "03acc816-b42f-4d87-ab1f-4d4ae16e73ef",
          "name": "Company Home"
        },
        {
          "id": "fb402fa3-3a59-446e-a69e-a1c769b62281",
          "name": "User Homes"
        },
        {
          "id": "bd8f1283-3e84-4585-aafc-12da26db760f",
          "name": "test"
        }
      ]
    },
    ...
  }
}

Take a look at the OpenAPI specification http://localhost:8080/api-explorer/#!/nodes/getNode for other additional data you can request.

Let's now turn our attention to updating a node. We have decided to implement partial update via PUT (although technically this is not RESTful we feel it's worth bending the rules here to keep things as simple as possible for clients) meaning the client only needs to send the data that is changing, with one exception, that we'll come to shortly.

To set some properties we use the same base URL (4th request in the Postman collection) of http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/nodes/8c37b5b7-b96f-49ef-817... but PUT a body using a Content-Type of application/json.

{
  "properties":
  {
    "cm:description": "The Description",
    "exif:manufacturer": "Canon"
  }
}

The response shows the state of the updated node, note that the exif aspect has also been added automatically (line 20).

{
  "entry": {
    "isFile": true,
    "createdByUser": {
      "id": "test",
      "displayName": "Test Test"
    },
    "modifiedAt": "2016-11-02T00:40:51.931+0000",
    "nodeType": "cm:content",
    "content": {
      "mimeType": "text\/plain",
      "mimeTypeName": "Plain Text",
      "sizeInBytes": 0,
      "encoding": "UTF-8"
    },
    "parentId": "bd8f1283-3e84-4585-aafc-12da26db760f",
    "aspectNames": [
      "cm:titled",
      "cm:auditable",
      "exif:exif"
    ],
    "createdAt": "2016-11-01T14:57:24.388+0000",
    "isFolder": false,
    "modifiedByUser": {
      "id": "test",
      "displayName": "Test Test"
    },
    "name": "my-file.txt",
    "id": "8c37b5b7-b96f-49ef-817e-9808bf2309f9",
    "properties": {
      "cm:title": "The Title",
      "exif:manufacturer": "Canon",
      "cm:description": "The Description"
    }
  }
}

PUT can also be used to rename by just providing a cm:name property in the properties as shown below:

{
  "properties":
  {
    "cm:name": "renamed-name.txt"
  }
}

Alternatively, the top level name property can also be used (5th request in the Postman collection):

{
  "name": "renamed-file.txt"
}

Similarly, the owner of the node can be updated, just provide the cmSmiley Surprisedwner property as follows (6th request in the Postman collection):

{
  "properties":
  {
    "cm:owner": "gavinc"
  }
}

As mentioned earlier there is one exception to the partial update rule and that is for managing aspects. To change the aspects applied to a node the whole complete array has to be provided. Any aspects the node has applied but are not present in the array will be removed. Conversely, any aspects in the array that the node does not have applied are added.

To remove the exif aspect from the node we created earlier PUT the following body (7th request in the Postman collection):

{
  "aspectNames": [
    "cm:titled",
    "cm:ownable",
    "cm:auditable"
  ]
}

Finally, the type of the node can also be changed by updating the nodeType property, for example to change our node type to cm:savedquery use the following body (8th request in the Postman collection):

{
  "nodeType": "cm:savedquery"
}

In the examples above we've used a file, everything we went through can obviously also be done for folders.

Let's now turn our attention to the actual content. At the start of the post we created an empty text file, you can see this via the content property:

"content": {
  "mimeType": "text/plain",
  "mimeTypeName": "Plain Text",
  "sizeInBytes": 0,
  "encoding": "UTF-8"
}

To set some plain text content do a PUT against http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/nodes/8c37b5b7-b96f-49ef-817... using a Content-Type of text/plain and the following body (9th request in the Postman collection):

This is the initial content for the file.

The response will show the content has been updated and the encoding set accordingly:

{
  "entry": {
     ....
    "content": {
      "mimeType": "text/plain",
      "mimeTypeName": "Plain Text",
      "sizeInBytes": 41,
      "encoding": "ISO-8859-1"
    }
  }
}

The PUT endpoint accepts any binary stream so we could also use Postman to choose a file to upload as shown in the screenshot below:

Screen_Shot_2016-11-02_at_08_10_27.png

To retrieve the content simply use a GET against the content URL (10th request in the Postman collection):

http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/nodes/8c37b5b7-b96f-49ef-817...

The last thing we're going to cover in this post is deleting. To delete the file we just created use the DELETE method against the URL we've been using throughout this post (11th request in the Postman collection), for example:

DELETE http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/nodes/8c37b5b7-b96f-49ef-817...

This will actually perform a soft delete, the node gets moved to the trash can so it can be restored if necessary, we'll cover the trash can endpoints in a future post. If you want to take a look before then have a look through the documentation.

To permanently delete the node i.e. skip the trash can, use the permanent query parameter set to true, for example (12th request in the Postman collection):

DELETE http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/nodes/8c37b5b7-b96f-49ef-817...

Hopefully you've found these posts useful so far, if there's anything I can improve to make things easier or any other suggestions, please let me know via comments.

In the next post we're going to start looking into some more advanced topics, starting with versioning and locking.

18 Comments
mitpatoliya
Established Member II

Hi Gavin Cornwell​ thank you for starting this series. This will be very helpful to everyone because every Alfresco developer has to deal with these APIs and this kind of series can be a central place for them to refer. I appreciate your effort in putting this together.

One issue: when I am trying click on "PostMan Collection" link to import postman collection it is not able to do so. It opensup my postman and shows error  "Failed to import collection: filetype not recognized"

gavincornwell
Senior Member

Are you using the "Import From Link" option in Postman? Is it just the collection links in this post that's not working for you?

Alternatively, you could try creating a local file with the contents of https://www.getpostman.com/collections/1080590a4ee7008d4061 and importing that way.

I've also "updated" the collection link from within Postman, let me know if that's helped.

noufionline
Member II

How to delete a linked file using Rest API?

gavincornwell
Senior Member

Just to be clear, are you asking how to delete just the link between two documents?

noufionline
Member II

Yes Gavin,

I manage to link using the Rest Api but removing the link was the question.

gavincornwell
Senior Member

The cm:link object is a node in it's own right so using DELETE /nodes/{id-of-cm:link-node} should work.

noufionline
Member II

I want to keep the original file intact and delete only the link. your proposed solution will delete the entire file itself. Hope I was clear on the question.

As my understanding even when we make a link the id remains the same as the id of original file. In my case only link to be removed.

gavincornwell
Senior Member

Yes, you're question was clear.

I had presumed that the API would handle the cm:link object but examining the code it appears it doesn't so I'm afraid it's not possible currently. Feel free to raise an enhancement request at issues.alfresco.com.

zhihailiu
Active Member

Gavin,

"Update content" didn't seem to work for me for a PDF document. In 2nd request to update the content, the response status was 200 OK and it showed the right size. However, the content didn't seem to get updated. The after-update (3rd request) showed the same information as the before-update (1st request). By the way, the document was from bulk import and didn't have cm:versionable aspect to start with. Not sure if that matters. Thanks in advance.

1. Check existing content

GET /nodes/{id}

"content": {
"mimeType": "application/pdf",
"mimeTypeName": "Adobe PDF Document",
"sizeInBytes": 809777,
"encoding": "UTF-8"
}

2. Update content

PUT /nodes/{id}/content

200 OK

"content": {
"mimeType": "application/pdf",
"mimeTypeName": "Adobe PDF Document",
"sizeInBytes": 479082,
"encoding": "UTF-8"
}

3. Check content again

GET /nodes/{id}

"content": {
"mimeType": "application/pdf",
"mimeTypeName": "Adobe PDF Document",
"sizeInBytes": 809777,
"encoding": "UTF-8"
}

gavincornwell
Senior Member

Hmm, that does indeed sound strange, if you received a 200 response the request was successful and the underlying transaction must have completed successfully. 

Were there any errors visible in the log file(s)?

zhihailiu
Active Member

Gavin, nothing in the log. Any particular log4j settings I need to add to debug it?

gavincornwell
Senior Member

You can try adding "log4j.logger.org.alfresco.rest" or "log4j.logger.org.alfresco.rest.api" if the first one is too verbose.

 

If this doesn't highlight anything I would suggest raising an issue in JIRA.

noufionline
Member II

Hi Gavin,

How can I add custom properties? 

I have tried the following code but did not succeed.


var request = new RestRequest(Method.POST);

request.AddParameter("name", name);
request.AddParameter("overwrite", true);
request.AddParameter("cm:title", "Test Title");
request.AddParameter("cm:description", " Test Description");
request.AddParameter("properties", " {\n\t \"cm:title\":\"Folder title\",\n\t \"cicon:Name\":\"CICON\",\n\t \"ciconSmiley TongueROJECT\":\"CICON PROJECT\",\n\t \"cicon:ISSUEDATE\":\"2019-01-01\",\n\t \"cicon:EXPDATE\":\"2018-12-31\"\n\t }");

byte[] filedata = File.ReadAllBytes(path);

request.AddFile("filedata", filedata, name, "application/pdf");

gavincornwell
Senior Member

I can see two potential issues.

Firstly, it appears that you are trying to upload using multipart/form-data, in which case everything has to be passed as fields, to set your custom properties you should add them separately using AddParameter.

Secondly, to add custom properties they need to be defined in a custom model and the custom node type specified as a parameter i.e. request.AddParameter("nodeType", "cicon:myType");

Hope that helps, if not, post the error message/logs you see.

noufionline
Member II

Thanks, Gavin Cornwell

Excellent! It worked. Now I ran into another issue. When I upload the same document again the custom property is not getting updated.

I have created 4 custom properties and when the document is added all properties are updated. but subsequent updates only increase the version numbers and properties are not updated.

request.AddParameter("name", name);
request.AddParameter("overwrite", true);
request.AddParameter("cm:title", "Test");@
request.AddParameter("cm:description", " Test Description");

request.AddParameter("abs:issueddate", "2018-06-20");
request.AddParameter("abs:expirydate", "2020-06-19");
request.AddParameter("abs:customer", "Test Customer 1");
request.AddParameter("absSmiley Tongueroject", "Test Projdddect");

All the properties include the default properties are not getting updated.

Could you please help me on this?

Noufal

gavincornwell
Senior Member

Update works differently than creation (PUT vs. POST). Also you have to update content and properties separately.

What URL are you using above?

When you use PUT /nodes/id/content you just pass the binary content. When you use PUT /nodes/id you pass the properties in JSON form.

udayakumar_p
Active Member

Are these APIs available in Alfresco 5.0 or it is present only from 5.2?

When i try to hit the following end point in 5.0, i got error.

alfresco/api/-default-/public/alfresco/versions/1/nodes/-my-/children

{"error":{"errorKey":"Unable to locate resource resource for :nodes children","statusCode":400,"briefSummary":"01250241 Unable to locate resource resource for :nodes 

"http://developer.alfresco.com/ErrorsExplained.html#Unable to locate resource resource for :nodes children"}}
gavincornwell
Senior Member

I'm afraid these APIs are only available in 5.2 and higher.