User Create in Drupal 10 using REST API
Tags: drupal, restapi, api
Published: 2023-09-09 20:59:43

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wqfzck1mma3m4npwsogk.jpg)

**Step 2**: Download and install HAL & REST UI module.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qjzaxthuo8d3zqsrpsc7.jpg)

**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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dn93jgmimqdztk1gt2cy.jpg)

**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());
		}
	}
}
```

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);
	}
}
```

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());
		}
	}
}
```

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());
		}
	}
}
```

**Step 5**: Enable the 'restapi' custom module and then enable the APIs from REST UI interface.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69ihcxae9f2u3blvn9fv.jpg)

**Step 6**: Set the permissions for each individual APIs.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i2tu30l7aa34y6fcjs8s.jpg)

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

- 
Registration
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nt34i3e0hkug3kqh7vuz.jpg)

- 
Login

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2lrx1qbm0ty5vjrgz22p.jpg)

- 
User Details

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/moe2b2fbnwhuheb0ehj4.jpg)

- 
Edit Details

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f099bit9x8z1tu2srbs8.jpg)

- 
Logout

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o3ieu1auo1zhgpydw2wr.jpg)

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.