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.

API Trace View

Struggling with slow API calls? 👀

Dan Mindru walks through how he used Sentry's new Trace View feature to shave off 22.3 seconds from an API call.

Get a practical walkthrough of how to identify bottlenecks, split tasks into multiple parallel tasks, identify slow AI model calls, and more.

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

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay