DEV Community

Rahul Khan
Rahul Khan

Posted on • Edited on

16

User Create in Drupal 10 using REST API

Hello. Today we will be creating a custom module to create users using REST API in Drupal 10. We will be doing basic operations namely, user-registration, user-login, read and edit user details and user-logout.

Step 1: Addition three new text fields for the user (First Name, Last Name, City).
Image description

Step 2: Download and install HAL & REST UI module.
Image description

Step 3: Create a custom module named 'restapi' and add the info.yml file and create a folder structure in the 'restapi' module folder as 'src\Plugin\rest\resource'
Image description

Step 4: Create the php files for different operations.
UserRegistrationRest.php - For user registration



<?php

namespace Drupal\restapi\Plugin\rest\resource;
use Drupal\rest\Plugin\ResourceBase;
use Psr\Log\LoggerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Drupal\user\Entity\User;

/**
* Provides a resource to get view modes by entity and bundle.
* @RestResource(
*   id = "user_registration_rest",
*   label = @Translation("User Registration API"),
*   uri_paths = {
*     "create" = "/api/user-registration",
*   }
* )
*/
class UserRegistrationRest extends ResourceBase {
    /**
    * A current user instance which is logged in the session.
    * @var \Drupal\Core\Session\AccountProxyInterface
    */
    protected $loggedUser;

    /**
    * Constructs a Drupal\rest\Plugin\ResourceBase object.
    *
    * @param array $config
    *   A configuration array which contains the information about the plugin instance.
    * @param string $module_id
    *   The module_id for the plugin instance.
    * @param mixed $module_definition
    *   The plugin implementation definition.
    * @param array $serializer_formats
    *   The available serialization formats.
    * @param \Psr\Log\LoggerInterface $logger
    *   A logger instance.
    * @param \Drupal\Core\Session\AccountProxyInterface $current_user
    *   A currently logged user instance.
    */
    public function __construct(array $config, $module_id, $module_definition, array $serializer_formats, LoggerInterface $logger, AccountProxyInterface $current_user) {
        parent::__construct($config, $module_id, $module_definition, $serializer_formats, $logger);
        $this->loggedUser = $current_user;
    }

    /**
    * {@inheritdoc}
    */
    public static function create(ContainerInterface $container, array $config, $module_id, $module_definition) {
        return new static(
            $config,
            $module_id,
            $module_definition,
            $container->getParameter('serializer.formats'),
            $container->get('logger.factory')->get('user_registration_api'),
            $container->get('current_user')
        );
    }

    /*
    * User Registration API
    */
    public function post(Request $data) {
        global $base_url;
        try {
            $content = $data->getContent();
            $params = json_decode($content, TRUE);

            $message_string = "";
            $message_string .= empty($params['email']) ? "Email ID. " : "";
            $message_string .= empty($params['password']) ? "Password. " : "";
            $message_string .= empty($params['first_name']) ? "First Name. " : "";
            $message_string .= empty($params['last_name']) ? "Last Name. " : "";
            $message_string .= empty($params['city']) ? "City. " : "";
            if($message_string) {
                $final_api_reponse = array(
                    "status" => "Error",
                    "message" => "Mandatory Fields Missing",
                    "result" => "Required fields: ".$message_string
                );
            }
            else {
                $user_name = strtolower($params['first_name'].'.'.$params['last_name']);
                $user_full_name = ucfirst($params['first_name']).' '.ucfirst($params['last_name']);
                $user_email = $params['email'];

                // Checking for duplicate user entries
                $email_check = \Drupal::entityQuery('user')->accessCheck(TRUE)->condition('mail', $user_email)->execute();
                $username_check = \Drupal::entityQuery('user')->accessCheck(TRUE)->condition('name', $user_name)->execute();
                if (!empty($email_check) || !empty($username_check)) {
                    $final_api_reponse = array(
                        "status" => "Error",
                        "message" => "Registration Failed",
                        "result" => "User details already exists. Please try with different Name or Email-ID."
                    );
                }
                else {
                    // Create new user
                    $new_user = User::create([
                        'name' => $user_name,
                        'pass' => $params['password'],
                        'mail' => $user_email,
                        'roles' => array('general', 'authenticated'),
                        'field_first_name' => ucfirst($params['first_name']),
                        'field_last_name' => ucfirst($params['last_name']),
                        'field_city' => $params['city'],
                        'status' => 1,
                    ])->save();

                    $final_api_reponse = array(
                        "status" => "Success",
                        "message" => "Registration Successful",
                        "result" => "Thank You. Account for ".$user_full_name." has been created."
                    );
                }
            }
            return new JsonResponse($final_api_reponse);
        }
        catch(Exception $exception) {
            $this->exception_error_msg($exception->getMessage());
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

UserLoginRest.php - For user login



<?php

namespace Drupal\restapi\Plugin\rest\resource;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\user\UserAuthInterface;
use Drupal\user\UserFloodControlInterface;
use Drupal\user\UserInterface;
use Drupal\user\UserStorageInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Serializer;
use Drupal\user\Entity\User;

/**
* Provides a resource to get view modes by entity and bundle.
* @RestResource(
*   id = "user_login_rest",
*   label = @Translation("User Login API"),
*   uri_paths = {
*     "create" = "/api/user-login",
*   }
* )
*/
class UserLoginRest extends ResourceBase {
    /**
    * String sent in responses, to describe the user as being logged in.
    * @var string
    */
    const LOGGED_IN = 1;
    /**
    * String sent in responses, to describe the user as being logged out.
    * @var string
    */
    const LOGGED_OUT = 0;
    /**
    * The user flood control service.
    * @var \Drupal\user\UserFloodControl
    */
    protected $userFloodControl;
    /**
    * The user storage.
    * @var \Drupal\user\UserStorageInterface
    */
    protected $userStorage;
    /**
    * The CSRF token generator.
    * @var \Drupal\Core\Access\CsrfTokenGenerator
    */
    protected $csrfToken;
    /**
    * The user authentication.
    * @var \Drupal\user\UserAuthInterface
    */
    protected $userAuth;
    /**
    * The route provider.
    * @var \Drupal\Core\Routing\RouteProviderInterface
    */
    protected $routeProvider;
    /**
    * The serializer.
    * @var \Symfony\Component\Serializer\Serializer
    */
    protected $serializer;
    /**
    * The available serialization formats.
    * @var array
    */
    protected $serializerFormats = [];
    /**
    * A logger instance.
    * @var \Psr\Log\LoggerInterface
    */
    protected $logger;
    /**
    * Constructs a new UserAuthenticationController object.
    *
    * @param \Drupal\user\UserFloodControlInterface $user_flood_control
    *   The user flood control service.
    * @param \Drupal\user\UserStorageInterface $user_storage
    *   The user storage.
    * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
    *   The CSRF token generator.
    * @param \Drupal\user\UserAuthInterface $user_auth
    *   The user authentication.
    * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
    *   The route provider.
    * @param \Symfony\Component\Serializer\Serializer $serializer
    *   The serializer.
    * @param array $serializer_formats
    *   The available serialization formats.
    * @param \Psr\Log\LoggerInterface $logger
    *   A logger instance.
    */
    public function __construct(array $config, $module_id, $module_definition, array $serializer_formats, UserStorageInterface $user_storage, CsrfTokenGenerator $csrf_token, UserAuthInterface $user_auth, RouteProviderInterface $route_provider, LoggerInterface $logger, AccountProxyInterface $current_user) {
        parent::__construct($config, $module_id, $module_definition, $serializer_formats, $logger);
        $this->loggedUser = $current_user;
        $this->userStorage = $user_storage;
        $this->csrfToken = $csrf_token;
        $this->userAuth = $user_auth;
        $this->routeProvider = $route_provider;
    }

    /**
    * {@inheritdoc}
    */
    public static function create(ContainerInterface $container, array $config, $module_id, $module_definition) {
        return new static(
            $config,
            $module_id,
            $module_definition,
            $container->getParameter('serializer.formats'),
            $container->get('entity_type.manager')->getStorage('user'),
            $container->get('csrf_token'),
            $container->get('user.auth'),
            $container->get('router.route_provider'),
            $container->get('logger.factory')->get('user_login_api'),
            $container->get('current_user')
        );
    }

    /**
    * Logs in a user.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request.
    * @return \Symfony\Component\HttpFoundation\Response
    *   A response which contains the ID and CSRF token.
    */
    public function post(Request $data) {
        global $base_url;
        try {
            $content = $data->getContent();
            $params = json_decode($content, TRUE);
            $email = $params['email'];
            $password = $params['pass'];
            if (empty($email) || empty($password)) {
                $final_api_reponse = array(
                    "status" => "Error",
                    "message" => "Missing Credentials"
                );
            }
            else {
                $user = user_load_by_mail($email);
                if(empty($user)) {
                    $final_api_reponse = array(
                        "status" => "Error",
                        "message" => "User Not Found",
                        "result" => "No user registered with ".$email
                    );
                }
                else {
                    $user_name = $user->get('name')->value;
                    if ($uid = $this->userAuth->authenticate($user_name, $password)) {
                        $user = $this->userStorage->load($uid);
                        $this->userLoginFinalize($user);
                        $response_data = array();
                        if ($user->get('uid')->access('view', $user)) {
                            $response_data['current_user']['uid'] = $user->id();
                        }
                        if ($user->get('name')->access('view', $user)) {
                            $response_data['current_user']['name'] = $user->getAccountName();
                        }
                        $response_data['csrf_token'] = $this->csrfToken->get('rest');
                        $logout_route = $this->routeProvider->getRouteByName('user.logout.http');
                        $logout_path = ltrim($logout_route->getPath(), '/');
                        $response_data['logout_token'] = $this->csrfToken->get($logout_path);
                        $final_api_reponse = array(
                            "status" => "Success",
                            "message" => "Login Success",
                            "result" => $response_data
                        );
                    }
                    else {
                        $final_api_reponse = array(
                            "status" => "Error",
                            "message" => "Invalid Credentials"
                        );
                    }
                }
            }
            return new JsonResponse($final_api_reponse);
        }
        catch(Exception $exception) {
            $this->exception_error_msg($exception->getMessage());
        }
    }

    /**
    * Finalizes the user login.
    * @param \Drupal\user\UserInterface $user
    * The user.
    */
    protected function userLoginFinalize(UserInterface $user) {
        user_login_finalize($user);
    }
}


Enter fullscreen mode Exit fullscreen mode

UserAccountRest.php - For fetching and editing user details



<?php

namespace Drupal\restapi\Plugin\rest\resource;
use Drupal\rest\Plugin\ResourceBase;
use Psr\Log\LoggerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Drupal\user\Entity\User;

/**
* Provides a resource to get view modes by entity and bundle.
* @RestResource(
*   id = "user_account_rest",
*   label = @Translation("User Account API"),
*   uri_paths = {
*     "canonical" = "/api/user-account",
*     "create" = "/api/edit-account",
*   }
* )
*/

class UserAccountRest extends ResourceBase {
    /**
    * A current user instance which is logged in the session.
    * @var \Drupal\Core\Session\AccountProxyInterface
    */
    protected $loggedUser;

    /**
    * Constructs a Drupal\rest\Plugin\ResourceBase object.
    *
    * @param array $config
    *   A configuration array which contains the information about the plugin instance.
    * @param string $module_id
    *   The module_id for the plugin instance.
    * @param mixed $module_definition
    *   The plugin implementation definition.
    * @param array $serializer_formats
    *   The available serialization formats.
    * @param \Psr\Log\LoggerInterface $logger
    *   A logger instance.
    * @param \Drupal\Core\Session\AccountProxyInterface $current_user
    *   A currently logged user instance.
    */
    public function __construct(array $config, $module_id, $module_definition, array $serializer_formats, LoggerInterface $logger, AccountProxyInterface $current_user) {
        parent::__construct($config, $module_id, $module_definition, $serializer_formats, $logger);
        $this->loggedUser = $current_user;
    }

    /**
    * {@inheritdoc}
    */
    public static function create(ContainerInterface $container, array $config, $module_id, $module_definition) {
        return new static(
            $config,
            $module_id,
            $module_definition,
            $container->getParameter('serializer.formats'),
            $container->get('logger.factory')->get('user_account_api'),
            $container->get('current_user')
        );
    }

    /*
    * Fetch User Account Details API
    */
    public function get() {
        global $base_url;
        try {
            $logged_user = User::load(\Drupal::currentUser()->id());
            $user_id = $logged_user->get('uid')->value;
            $role = $logged_user->get('roles')->getValue();
            $user_role = $role[0]['target_id'];

            $user_data['user_id'] = $user_id;
            $user_data['role'] = ucfirst($user_role);
            $user_data['first_name'] = $logged_user->get('field_first_name')->value;
            $user_data['last_name'] = $logged_user->get('field_last_name')->value;
            $user_data['email'] = $logged_user->get('mail')->value;
            $user_data['city'] = $logged_user->get('field_city')->value;

            $final_api_reponse = array(
                "status" => "Success",
                "message" => "User Account",
                "result" => $user_data
            );
            return new JsonResponse($final_api_reponse);
        }
        catch(Exception $exception) {
            $this->exception_error_msg($exception->getMessage());
        }
    }

    /*
    * Edit User Details API
    */
    public function post(Request $data) {
        global $base_url;
        try {
            $logged_user = User::load(\Drupal::currentUser()->id());
            $user_id = $logged_user->get('uid')->value;
            $content = $data->getContent();
            $params = json_decode($content, TRUE);

            if($params['first_name'] != "") {
                $logged_user->set('field_first_name', $params['first_name']);
            }
            if($params['last_name'] != "") {
                $logged_user->set('field_last_name', $params['last_name']);
            }
            if($params['city'] != "") {
                $logged_user->set('field_city', $params['city']);
            }
            $logged_user->save();

            $final_api_reponse = array(
                "status" => "Success",
                "message" => "User Details Updated",
                "result" => "Your details have been updated."
            );
            return new JsonResponse($final_api_reponse);
        }
        catch(Exception $exception) {
            $this->exception_error_msg($exception->getMessage());
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

UserLogoutRest.php - For user logout



<?php

namespace Drupal\restapi\Plugin\rest\resource;
use Drupal\rest\Plugin\ResourceBase;
use Psr\Log\LoggerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Drupal\user\Entity\User;

/**
* Provides a resource to get view modes by entity and bundle.
* @RestResource(
*   id = "user_logout_rest",
*   label = @Translation("User Logout API"),
*   uri_paths = {
*     "create" = "/api/user-logout",
*   }
* )
*/

class UserLogoutRest extends ResourceBase {
    /**
    * A current user instance which is logged in the session.
    * @var \Drupal\Core\Session\AccountProxyInterface
    */
    protected $loggedUser;

    /**
    * Constructs a Drupal\rest\Plugin\ResourceBase object.
    *
    * @param array $config
    *   A configuration array which contains the information about the plugin instance.
    * @param string $module_id
    *   The module_id for the plugin instance.
    * @param mixed $module_definition
    *   The plugin implementation definition.
    * @param array $serializer_formats
    *   The available serialization formats.
    * @param \Psr\Log\LoggerInterface $logger
    *   A logger instance.
    * @param \Drupal\Core\Session\AccountProxyInterface $current_user
    *   A currently logged user instance.
    */
    public function __construct(array $config, $module_id, $module_definition, array $serializer_formats, LoggerInterface $logger, AccountProxyInterface $current_user) {
        parent::__construct($config, $module_id, $module_definition, $serializer_formats, $logger);
        $this->loggedUser = $current_user;
    }

    /**
    * {@inheritdoc}
    */
    public static function create(ContainerInterface $container, array $config, $module_id, $module_definition) {
        return new static(
            $config,
            $module_id,
            $module_definition,
            $container->getParameter('serializer.formats'),
            $container->get('logger.factory')->get('user_logout_api'),
            $container->get('current_user')
        );
    }

    /*
    * User Logout API
    */
    public function post(Request $data) {
        global $base_url;
        try {
            $content = $data->getContent();
            $params = json_decode($content, TRUE);
            $user_id = $params['user_id'];

            $logged_user = User::load(\Drupal::currentUser()->id());
            $current_id = $logged_user->get('uid')->value;
            if(empty($user_id) || ($current_id != $user_id)) {
                $final_api_reponse = array(
                    "status" => "Error",
                    "message" => "Logout Error",
                    "result" => "Please provide valid User-ID"
                );
            }
            else {
                user_logout();
                $final_api_reponse = array(
                    "status" => "Success",
                    "message" => "Logout Success",
                    "result" => "You have successfully logged out from your account."
                );
            }
            return new JsonResponse($final_api_reponse);
        }
        catch(Exception $exception) {
            $this->exception_error_msg($exception->getMessage());
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

Step 5: Enable the 'restapi' custom module and then enable the APIs from REST UI interface.
Image description

Step 6: Set the permissions for each individual APIs.

Image description

Step 7: Now we can test these APIs in postman.

  • Registration
    Image description

  • Login

Image description

  • User Details

Image description

  • Edit Details

Image description

  • Logout

Image description

So, in this way we can do basic operations using REST API in Drupal. I hope you find this simple use of REST API helpful.

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (1)

Collapse
 
jeetpatel_32 profile image
JEET

Hi,
This is very helpful articles.
Can you please share the "Authentication providers" screenshot of the User Details API?

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more