I recently had a need to allow users to create a single comment on two node types, of which only the author could access. Part of the decision for limiting users to one comment per node was to keep the database size down. We only wanted one comment to be made per node, and future comments made as edits to the original. Because of the way the comments are displayed to the user, on the node itself, and being that the client wanted to avoid any page refresh for most user actions, the comment creation and edits are all made via Drupal 8’s built-in REST resources and handled with Javascript.
Before getting started you will want to make sure you have the following core modules enabled: HAL, HTTP Basic Authentication, RESTful Web Services, and Serialization. These can be found on the modules page under “Web Services.”
To make the set-up process easier we’re going to leverage a contrib module called REST UI. Once installed and enabled, navigate to Configuration>Web services>REST. Here you can see the list of REST resources available by default in Drupal. Enable the “Comment” resource and click “Edit.”
Here you can see the available methods and their settings for this resource. Since we are only dealing with creating and updating comments we only need to enable POST and PATCH methods. Within each method, there are settings for accepted request formats and authentication providers. For this example, we will be using the same settings for POST and PATCH. Enable hal_json for “Accepted request formats” and basic_auth & cookie for “Authentication providers.”
This completes the setup process. We can now begin to write the JS methods needed to POST and PATCH to our REST resources.
To start we are going create a method to authenticate our request with Drupal. This can be found here.
function getCsrfToken(callback) { $.get(Drupal.url('rest/session/token')).done(function (data) { var csrfToken = data; callback(csrfToken); }); }
This method is used to get the CSRF Token, which in combination with the session ID, is needed to authenticate requests with Drupal.
When I began looking through Drupal 8 documentation for REST services, specifically relating to comments, the information was not complete. Luckily, others had already started related discussions on the forums and in issue queues.
POST:
For creating comments, using POST with a hal+json request format, there are a few extra pieces of information our data object needs before it is sent to our REST resource.
var newComment = { _links: { type: { href: “https://www.example.com/rest/type/comment/comment” }, https://www.example.com/relation/comment/comment/entity_id: { href: “https://www.example.com/rest/type/comment/comment/node/100” // Path to host node. }, }, entity_id: [ { target_id: 100 // The host entity’s ID } ], langcode: [ { value: 'en' } ], subject: [ { value: “The title of the comment” }], uid:[ { target_id: 2 // The user ID of the author for the comment } ], status: [ { value: '1' } ], entity_type: [ { value: 'node' // Host entity type. } ], comment_type: [ { target_id: 'comment' // Machine name of the comment bundle. } ], field_name: [ { value: 'comment' // Name of the field on the node. } ], comment_body: [ { value: “Body text for the comment.” } ] };
Now that we have the values set up for our data object, newComment, we can actually make the request.
function postComment(csrfToken, newComment) { $.ajax({ url: '/entity/comment?_format=hal_json', method: 'POST', headers: { 'X-CSRF-Token': csrfToken, 'Content-Type': 'application/hal+json' }, data: JSON.stringify(newComment), success: function (createdComment) { console.log(createdComment); }, error: function (jqXHR, textStatus, errorThrown) {} }); }
That’s it, we have the two methods and the data object needed to create a comment via Javascript in D8 with REST. Fire it using:
getCsrfToken(function (csrfToken) { postComment(csrfToken, newComment); });
Now that we can create comments with Javascript, we need to be able to update them. To do this we are going to use PATCH resource for comments. We configured our comment resource for this already above, and we can use the same getCsrfToken function for authentication. The method we will create for editing comments is also very similar to the postComment method from above. The only difference is the addition of the commentId parameter, which is added to the “url” property, and changing the “method” property from POST to PATCH.
function patchComment(csrfToken, comment, commentId) { $.ajax({ url: '/comment/' + commentId + '?_format=hal_json', method: 'PATCH', headers: { 'X-CSRF-Token': csrfToken, 'Content-Type': 'application/hal+json' }, data: JSON.stringify(comment), success: function (updatedComment) { console.log(updatedComment); }, error: function (jqXHR, textStatus, errorThrown) {} }); }
The data object we will be sending to the PATCH resource is much simpler than the one for POST. The same “_links” urls must be sent as before. With hal+json using references, we only need to send the fields we want to update. If we send any read-only fields, such as uid or entity_id, the request will be denied with a 403 response. In this case, our comments only have one field to be updated, the body, so all we have to send is the new value.
var updatedComment = { _links: { type: { href: type_href }, }, comment_body: [ { value: note } ] };
Use the same way we fired the POST request to fire the PATCH request:
getCsrfToken(function (csrfToken) { patchComment(csrfToken, updatedComment, commentId); });
There you have it. Once everything is enabled, configured, and your variables are where you want them, it actually isn’t too bad to get Drupal’s built-in REST resources to work. A few simple methods and you should be good to go.
Additional Resources
Registering Migrations in Drupal 8 | Mediacurrent Blog
8 Insights and Useful Snippets for the D8 Rest Module | Mediacurrent Blog
Migrating From Excel Sheets to Drupal with migrate_spreadsheet | Mediacurrent Blog