Using Drupal 8 contact forms via REST

While working on Narwhal CMS, our hosted decoupled / headless CMS service built on Drupal 8, a feature request that has popped up multiple times is the ability to have (contact) forms in the frontend application or website be processed by the Drupal backend through REST.

Drupal 8 provides you with REST services and fieldable contact forms out of the box, but doesn't provide all the pieces to get this specific use case working. In the tutorial below I will show you how to implement this on your Drupal 8 website.

Tutorial:

  1. Prerequisites

    • Install your Drupal 8 website and make sure to enable the "Contact" and "Restful web services" modules, as we'll obviously need those.
    • Install and enable the REST UI module to easily manage which REST resources are activated on your site.
    • Install and enable the "Contact message REST" module.
    • You should also activate an authentication module such as "HTTP Basic Authentication" (in Drupal 8 core) or IP Consumer Auth to be able to restrict form submission access to your frontend application(s) only, and not leave your REST endpoints open to everyone.
  2. Set up REST resource

    • Go to /admin/config/services/rest and enable the "Contact message" resource, with path /contact_message/{entity}: Enable "Contact message" REST resource
    • Configure the supported formats and authentication providers to your preferences. E.g.: Contact message REST service configuration
  3. Configure permissions

    • Go to /admin/people/permissions and grant selected roles access to the permission "Access POST on Contact message resource". This should be set up correctly so your frontend application can authenticate with the correct role and perform the POST method. Only grant anonymous users permissions if you have some method to restrict access to your frontend application, such as IP whitelisting or API keys.
      Set permissions to Contact message POST resource
  4. Create contact form

    • Go to /admin/structure/contact and create a contact form, or use the default "Website feedback" form. Take note of the machine name of the contact form, as we'll need it when performing the REST call.
  5. Submit contact form via REST

    • In your frontend application, you should do a POST method call to the /contact_message REST endpoint: e.g. POST http://mydomain.com/contact_message?_format=json. Make sure you have set up your headers correctly for authentication and the X-CSRF-Token.
    • The body of your method call should provide values for the contact form entity fields. When using the default contact form fields, your request would look like this (in JSON format):
      {
          "contact_form":[{"target_id":"YOUR_FORM_MACHINE_NAME"}],
          "name":[{"value":"SENDER_NAME_VALUE"}],
          "mail":[{"value":"SENDER_MAIL_VALUE"}],
          "subject":[{"value":"FORM_SUBJECT"}],
          "message":[{"value":"FORM_MESSAGE"}]
      }
      
    • For example:
      Contact message REST method call

Extra's:

You could also install the Contact Storage module if you wish to store the submitted form entries, rather then just sending them via mail. In my experience, the module currently still has some bugs that prevent it from being completely usable, but those might get ironed out soon.

Background about "Contact message REST" module

While trying to get the functionality above working with Drupal core, 2 issues came up that prevented it from working:

  • When trying to create a Contact message through the default /entity/contact_message/{contact_message} resource, errors are thrown, because a contact Message entity doesn't get an ID assigned to it (because it uses the ContentEntityNullStorage storage handler). Since this REST resource tries to load the created entity and return it, this fails.
  • The actual sending of the contact form mails happens in the \Drupal\contact\MessageForm submit handler, which doesn't get called when a Message entity gets created through a REST resource.

Hence I created the Contact message REST module to solve these issues. Hopefully they will be resolved in later versions of Drupal 8.x, so the module won't be needed anymore.