<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Rahul Khan</title>
    <description>The latest articles on Forem by Rahul Khan (@rahulk1011).</description>
    <link>https://forem.com/rahulk1011</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F766508%2F0aa9cf0d-6604-4932-8347-7a7bd3d46c91.jpeg</url>
      <title>Forem: Rahul Khan</title>
      <link>https://forem.com/rahulk1011</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rahulk1011"/>
    <language>en</language>
    <item>
      <title>User Create in Drupal 10 using REST API</title>
      <dc:creator>Rahul Khan</dc:creator>
      <pubDate>Sat, 09 Sep 2023 20:59:43 +0000</pubDate>
      <link>https://forem.com/rahulk1011/rest-api-in-drupal-10-97o</link>
      <guid>https://forem.com/rahulk1011/rest-api-in-drupal-10-97o</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Addition three new text fields for the user (First Name, Last Name, City).&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqfzck1mma3m4npwsogk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqfzck1mma3m4npwsogk.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Download and install HAL &amp;amp; REST UI module.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjzaxthuo8d3zqsrpsc7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjzaxthuo8d3zqsrpsc7.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: 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'&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdn93jgmimqdztk1gt2cy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdn93jgmimqdztk1gt2cy.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Create the php files for different operations.&lt;br&gt;
UserRegistrationRest.php - For user registration&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?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-&amp;gt;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-&amp;gt;getParameter('serializer.formats'),
            $container-&amp;gt;get('logger.factory')-&amp;gt;get('user_registration_api'),
            $container-&amp;gt;get('current_user')
        );
    }

    /*
    * User Registration API
    */
    public function post(Request $data) {
        global $base_url;
        try {
            $content = $data-&amp;gt;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" =&amp;gt; "Error",
                    "message" =&amp;gt; "Mandatory Fields Missing",
                    "result" =&amp;gt; "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')-&amp;gt;accessCheck(TRUE)-&amp;gt;condition('mail', $user_email)-&amp;gt;execute();
                $username_check = \Drupal::entityQuery('user')-&amp;gt;accessCheck(TRUE)-&amp;gt;condition('name', $user_name)-&amp;gt;execute();
                if (!empty($email_check) || !empty($username_check)) {
                    $final_api_reponse = array(
                        "status" =&amp;gt; "Error",
                        "message" =&amp;gt; "Registration Failed",
                        "result" =&amp;gt; "User details already exists. Please try with different Name or Email-ID."
                    );
                }
                else {
                    // Create new user
                    $new_user = User::create([
                        'name' =&amp;gt; $user_name,
                        'pass' =&amp;gt; $params['password'],
                        'mail' =&amp;gt; $user_email,
                        'roles' =&amp;gt; array('general', 'authenticated'),
                        'field_first_name' =&amp;gt; ucfirst($params['first_name']),
                        'field_last_name' =&amp;gt; ucfirst($params['last_name']),
                        'field_city' =&amp;gt; $params['city'],
                        'status' =&amp;gt; 1,
                    ])-&amp;gt;save();

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


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;UserLoginRest.php - For user login&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?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-&amp;gt;loggedUser = $current_user;
        $this-&amp;gt;userStorage = $user_storage;
        $this-&amp;gt;csrfToken = $csrf_token;
        $this-&amp;gt;userAuth = $user_auth;
        $this-&amp;gt;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-&amp;gt;getParameter('serializer.formats'),
            $container-&amp;gt;get('entity_type.manager')-&amp;gt;getStorage('user'),
            $container-&amp;gt;get('csrf_token'),
            $container-&amp;gt;get('user.auth'),
            $container-&amp;gt;get('router.route_provider'),
            $container-&amp;gt;get('logger.factory')-&amp;gt;get('user_login_api'),
            $container-&amp;gt;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-&amp;gt;getContent();
            $params = json_decode($content, TRUE);
            $email = $params['email'];
            $password = $params['pass'];
            if (empty($email) || empty($password)) {
                $final_api_reponse = array(
                    "status" =&amp;gt; "Error",
                    "message" =&amp;gt; "Missing Credentials"
                );
            }
            else {
                $user = user_load_by_mail($email);
                if(empty($user)) {
                    $final_api_reponse = array(
                        "status" =&amp;gt; "Error",
                        "message" =&amp;gt; "User Not Found",
                        "result" =&amp;gt; "No user registered with ".$email
                    );
                }
                else {
                    $user_name = $user-&amp;gt;get('name')-&amp;gt;value;
                    if ($uid = $this-&amp;gt;userAuth-&amp;gt;authenticate($user_name, $password)) {
                        $user = $this-&amp;gt;userStorage-&amp;gt;load($uid);
                        $this-&amp;gt;userLoginFinalize($user);
                        $response_data = array();
                        if ($user-&amp;gt;get('uid')-&amp;gt;access('view', $user)) {
                            $response_data['current_user']['uid'] = $user-&amp;gt;id();
                        }
                        if ($user-&amp;gt;get('name')-&amp;gt;access('view', $user)) {
                            $response_data['current_user']['name'] = $user-&amp;gt;getAccountName();
                        }
                        $response_data['csrf_token'] = $this-&amp;gt;csrfToken-&amp;gt;get('rest');
                        $logout_route = $this-&amp;gt;routeProvider-&amp;gt;getRouteByName('user.logout.http');
                        $logout_path = ltrim($logout_route-&amp;gt;getPath(), '/');
                        $response_data['logout_token'] = $this-&amp;gt;csrfToken-&amp;gt;get($logout_path);
                        $final_api_reponse = array(
                            "status" =&amp;gt; "Success",
                            "message" =&amp;gt; "Login Success",
                            "result" =&amp;gt; $response_data
                        );
                    }
                    else {
                        $final_api_reponse = array(
                            "status" =&amp;gt; "Error",
                            "message" =&amp;gt; "Invalid Credentials"
                        );
                    }
                }
            }
            return new JsonResponse($final_api_reponse);
        }
        catch(Exception $exception) {
            $this-&amp;gt;exception_error_msg($exception-&amp;gt;getMessage());
        }
    }

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


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;UserAccountRest.php - For fetching and editing user details&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?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-&amp;gt;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-&amp;gt;getParameter('serializer.formats'),
            $container-&amp;gt;get('logger.factory')-&amp;gt;get('user_account_api'),
            $container-&amp;gt;get('current_user')
        );
    }

    /*
    * Fetch User Account Details API
    */
    public function get() {
        global $base_url;
        try {
            $logged_user = User::load(\Drupal::currentUser()-&amp;gt;id());
            $user_id = $logged_user-&amp;gt;get('uid')-&amp;gt;value;
            $role = $logged_user-&amp;gt;get('roles')-&amp;gt;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-&amp;gt;get('field_first_name')-&amp;gt;value;
            $user_data['last_name'] = $logged_user-&amp;gt;get('field_last_name')-&amp;gt;value;
            $user_data['email'] = $logged_user-&amp;gt;get('mail')-&amp;gt;value;
            $user_data['city'] = $logged_user-&amp;gt;get('field_city')-&amp;gt;value;

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

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

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

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


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;UserLogoutRest.php - For user logout&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?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-&amp;gt;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-&amp;gt;getParameter('serializer.formats'),
            $container-&amp;gt;get('logger.factory')-&amp;gt;get('user_logout_api'),
            $container-&amp;gt;get('current_user')
        );
    }

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

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


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Enable the 'restapi' custom module and then enable the APIs from REST UI interface.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69ihcxae9f2u3blvn9fv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69ihcxae9f2u3blvn9fv.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt;: Set the permissions for each individual APIs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi2tu30l7aa34y6fcjs8s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi2tu30l7aa34y6fcjs8s.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7&lt;/strong&gt;: Now we can test these APIs in postman.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Registration&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnt34i3e0hkug3kqh7vuz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnt34i3e0hkug3kqh7vuz.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Login&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lrx1qbm0ty5vjrgz22p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lrx1qbm0ty5vjrgz22p.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
User Details&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmoe2b2fbnwhuheb0ehj4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmoe2b2fbnwhuheb0ehj4.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Edit Details&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff099bit9x8z1tu2srbs8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff099bit9x8z1tu2srbs8.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Logout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo3ieu1auo1zhgpydw2wr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo3ieu1auo1zhgpydw2wr.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

</description>
      <category>drupal</category>
      <category>restapi</category>
      <category>api</category>
    </item>
    <item>
      <title>Sending mails using Cron in Drupal 8</title>
      <dc:creator>Rahul Khan</dc:creator>
      <pubDate>Thu, 15 Sep 2022 09:21:38 +0000</pubDate>
      <link>https://forem.com/rahulk1011/sending-mails-using-cron-in-drupal-8-4369</link>
      <guid>https://forem.com/rahulk1011/sending-mails-using-cron-in-drupal-8-4369</guid>
      <description>&lt;p&gt;In this post, we will be sending a simple birthday greeting email to the users using cron.&lt;/p&gt;

&lt;p&gt;First, we have to create a module file in our custom module folder. We will name it as 'MODULE_NAME.module'. Using the &lt;em&gt;hook_cron()&lt;/em&gt;, we will call a function to send the emails to the users where the mail-body is defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function MODULE_NAME_cron() {
    user_birthday_mails();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will fetch the details of the users, namely User-Name, Email-ID &amp;amp; Date of Birth.&lt;/p&gt;

&lt;p&gt;In this scenario, I'm fetching the user details from a custom table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
function user_birthday_mails() {
    // this is used to send HTML emails
    $send_mail = new \Drupal\Core\Mail\Plugin\Mail\PhpMail();

    $current_m_d = date('m-d', \Drupal::time()-&amp;gt;getRequestTime());
    $fetch_query = \Drupal::database()-&amp;gt;query("SELECT `firstname`, `email`, `dob` FROM `TABLE_NAME`");
    $query_result = $fetch_query-&amp;gt;fetchAll();

    foreach($query_result as $result){
        $birthday = explode('-', $result-&amp;gt;dob);
        $birth_m_d = $birthday[1].'-'.$birthday[2];

        $user_name = $result-&amp;gt;firstname;
        $user_mail = $result-&amp;gt;email;

        if($birth_m_d == $current_m_d){
            $from = 'sitename@example.com';
            $to = $user_mail;
            $message['headers'] = array(
                'content-type' =&amp;gt; 'text/html',
                'MIME-Version' =&amp;gt; '1.0',
                'reply-to' =&amp;gt; $from,
                'from' =&amp;gt; 'Site Admin &amp;lt;'.$from.'&amp;gt;'
            );
            $message['to'] = $to;
            $message['subject'] = "Happy Birthday ".$user_name."!!!";

            $message['body'] = 'Dear '.$user_name.',
            &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;
            We value your special day just as much as we value you. On your birthday, we send you our warmest and most heartfelt wishes..
            &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;
            Regards,&amp;lt;br&amp;gt;
            Site Admin';

            $send_mail-&amp;gt;mail($message);
            \Drupal::logger('userinfo')-&amp;gt;notice('Birthday mail sent to '.$user_name);
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope you find this simple use of cron helpful.&lt;/p&gt;

</description>
      <category>php</category>
      <category>drupal</category>
      <category>drupal8</category>
      <category>cron</category>
    </item>
    <item>
      <title>Custom Module &amp; DB Table in Drupal 9</title>
      <dc:creator>Rahul Khan</dc:creator>
      <pubDate>Fri, 22 Apr 2022 13:15:20 +0000</pubDate>
      <link>https://forem.com/rahulk1011/custom-module-db-table-in-drupal-9-9in</link>
      <guid>https://forem.com/rahulk1011/custom-module-db-table-in-drupal-9-9in</guid>
      <description>&lt;p&gt;We will be creating a custom module in Drupal 9 to build a custom form &amp;amp; store the data in a custom table in the database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Name of the Module&lt;/strong&gt;&lt;br&gt;
We need to create a custom module under 'modules/custom' folder. We will name the folder as 'userinfo'&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Creating the info.yml file&lt;/strong&gt;&lt;br&gt;
We have to create a yaml file with the machine name of our module for Drupal to be able recognize the module. We will name the file as 'userinfo.info.yml'&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: User Info
type: module
description: A custom module to enter user information
package: Custom
version: 1.0
core_version_requirement: ^8 || ^9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Creating the routing.yml file&lt;/strong&gt;&lt;br&gt;
Next step is to add a userinfo.routing.yml file under the 'userinfo' directory.&lt;br&gt;
Under path, we specify the URL path for adding user information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;userinfo.form:
 path: '/add-user-info'
 defaults:
  _title: 'Add User Info'
  _form: '\Drupal\userinfo\Form\UserinfoForm'
 requirements:
  _permission: 'access content'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Adding the form&lt;/strong&gt;&lt;br&gt;
We will create a form named 'UserinfoForm.php' under 'modules/custom/userinfo/src/Form'. In this file, we will create a custom form to validate &amp;amp; submit user information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

/**
 * @file
 * Contains \Drupal\userinfo\Form\UserinfoForm.
*/

namespace Drupal\userinfo\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Database\Database;
use Drupal\Core\Url;
use Drupal\Core\Routing;

class UserinfoForm extends FormBase {
    /**
    * {@inheritdoc}
    */
    public function getFormId() {
        return 'userinfo_form';
    }

    /**
    * {@inheritdoc}
    */
    public function buildForm(array $form, FormStateInterface $form_state) {
        $form['form_info'] = array(
            '#markup' =&amp;gt; '&amp;lt;h4&amp;gt;Saving User Info in a custom table in the database&amp;lt;/h4&amp;gt;&amp;lt;br&amp;gt;',
        );
        $form['first_name'] = array(
            '#type' =&amp;gt; 'textfield',
            '#title' =&amp;gt; t('First Name'),
            '#required' =&amp;gt; TRUE,
            '#maxlength' =&amp;gt; 50,
            '#default_value' =&amp;gt; '',
        );
        $form['last_name'] = array(
            '#type' =&amp;gt; 'textfield',
            '#title' =&amp;gt; t('Last Name'),
            '#required' =&amp;gt; TRUE,
            '#maxlength' =&amp;gt; 50,
            '#default_value' =&amp;gt; '',
        );
        $form['user_email'] = array(
            '#type' =&amp;gt; 'textfield',
            '#title' =&amp;gt; t('Email-ID'),
            '#required' =&amp;gt; TRUE,
            '#maxlength' =&amp;gt; 50,
            '#default_value' =&amp;gt; '',
        );
        $form['user_age'] = [
            '#type' =&amp;gt; 'textfield',
            '#title' =&amp;gt; t('Age'),
            '#required' =&amp;gt; TRUE,
            '#maxlength' =&amp;gt; 20,
            '#default_value' =&amp;gt; '',
        ];
        $form['user_city'] = array(
            '#type' =&amp;gt; 'textfield',
            '#title' =&amp;gt; t('City'),
            '#required' =&amp;gt; TRUE,
            '#maxlength' =&amp;gt; 50,
            '#default_value' =&amp;gt; '',
        );

        $form['actions']['#type'] = 'actions';
        $form['actions']['submit'] = array(
            '#type' =&amp;gt; 'submit',
            '#value' =&amp;gt; $this-&amp;gt;t('Save Info'),
            '#button_type' =&amp;gt; 'primary',
        );
        return $form;
    }

    /**
    * {@inheritdoc}
    */
    public function validateForm(array &amp;amp;$form, FormStateInterface $form_state) {
        if ($form_state-&amp;gt;getValue('first_name') == '') {
            $form_state-&amp;gt;setErrorByName('first_name', $this-&amp;gt;t('Please Enter First Name'));
        }
        if ($form_state-&amp;gt;getValue('last_name') == '') {
            $form_state-&amp;gt;setErrorByName('last_name', $this-&amp;gt;t('Please Enter Last Name'));
        }
        if ($form_state-&amp;gt;getValue('user_email') == '') {
            $form_state-&amp;gt;setErrorByName('user_email', $this-&amp;gt;t('Please Enter Email-ID'));
        }
        if ($form_state-&amp;gt;getValue('user_age') == '') {
            $form_state-&amp;gt;setErrorByName('user_age', $this-&amp;gt;t('Please Enter Age'));
        }
        if ($form_state-&amp;gt;getValue('user_city') == '') {
            $form_state-&amp;gt;setErrorByName('user_city', $this-&amp;gt;t('Please Enter City'));
        }
    }

    /**
    * {@inheritdoc}
    */
    public function submitForm(array &amp;amp;$form, FormStateInterface $form_state) {
        try{
            $conn = Database::getConnection();
            $field = $form_state-&amp;gt;getValues();

            $fields["first_name"] = $field['first_name'];
            $fields["last_name"] = $field['last_name'];
            $fields["user_email"] = $field['user_email'];
            $fields["user_age"] = $field['user_age'];
            $fields["user_city"] = $field['user_city'];

            $conn-&amp;gt;insert('user_info')
            -&amp;gt;fields($fields)-&amp;gt;execute();
            \Drupal::messenger()-&amp;gt;addMessage(t("User info has been succesfully saved"));
        }
        catch(Exception $ex){
            \Drupal::logger('userinfo')-&amp;gt;error($ex-&amp;gt;getMessage());
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5: Creating table schema&lt;/strong&gt;&lt;br&gt;
Now, we will create a database table schema in 'userinfo.install' file to store the user information. We will place this file in the module root folder.&lt;br&gt;
The table name is 'user_info' with the following fields: user_id, first_name, last_name, user_email, user_age &amp;amp; user_city.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
use Drupal\Core\Database\Database;

/**
 * Implements hook_schema().
 */
function userinfo_schema(){
    $schema['user_info'] = array(
        'description' =&amp;gt; 'The table for storing the user information',
        'fields' =&amp;gt; array(
            'user_id' =&amp;gt; array(
                'description' =&amp;gt; 'Primary identifier for User',
                'type' =&amp;gt; 'serial',
                'not null' =&amp;gt; TRUE,
                'unsigned' =&amp;gt; TRUE,
            ),
            'first_name' =&amp;gt; array(
                'description' =&amp;gt; 'User First Name',
                'type' =&amp;gt; 'varchar',
                'length' =&amp;gt; 255,
                'not null' =&amp;gt; TRUE,
                'default' =&amp;gt; '',
            ),
           'last_name' =&amp;gt; array(
                'description' =&amp;gt; 'User Last Name.',
                'type' =&amp;gt; 'varchar',
                'length' =&amp;gt; 255,
                'not null' =&amp;gt; TRUE,
                'default' =&amp;gt; '',
            ),
            'user_email' =&amp;gt; array(
                'description' =&amp;gt; 'User Email ID',
                'type' =&amp;gt; 'varchar',
                'length' =&amp;gt; 255,
                'not null' =&amp;gt; TRUE,
            ),
            'user_age' =&amp;gt; array(
                'description' =&amp;gt; 'Age of User',
                'type' =&amp;gt; 'int',
                'length' =&amp;gt; 100,
                'not null' =&amp;gt; TRUE,
            ),
            'user_city' =&amp;gt; array(
                'description' =&amp;gt; 'User City',
                'type' =&amp;gt; 'varchar',
                'length' =&amp;gt; 255,
                'not null' =&amp;gt; TRUE,
                'default' =&amp;gt; '',
            ),
        ),
        'primary key' =&amp;gt; array('user_id'),
    );
    return $schema;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once everything is done, we can enable the module &amp;amp; hit the URL mentioned in the routing file.&lt;/p&gt;

</description>
      <category>drupal</category>
      <category>drupal9</category>
    </item>
    <item>
      <title>Reset Drupal Admin Password using Drush</title>
      <dc:creator>Rahul Khan</dc:creator>
      <pubDate>Thu, 24 Mar 2022 13:22:52 +0000</pubDate>
      <link>https://forem.com/rahulk1011/reset-drupal-admin-password-using-drush-1c7n</link>
      <guid>https://forem.com/rahulk1011/reset-drupal-admin-password-using-drush-1c7n</guid>
      <description>&lt;p&gt;This article describes how to reset the Drupal administrator password using Drush. We can use the Drush command line tool to reset the administrator password (or the password of any other user).&lt;/p&gt;

&lt;p&gt;To do this, we have to first log in with our account using SSH &amp;amp; enter the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\Users\user_name&amp;gt;ssh site_name.dev@site_name.ssh.dev.acquia-sites.com
site_name@dev-1234:~$ cd ..
site_name@dev-1234:/home$ cd ..
site_name@dev-1234:/$ cd var/www/html/site_name/docroot
site_name@dev-1234:/var/www/html/site_name/docroot$ drush --uri=site_name.com upwd admin --password=Password123
Changes password for admin
site_name@dev-1234:/var/www/html/site_name/docroot$ exit
logout
Connection to site_name.ssh.dev.acquia-sites.com closed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I did this for my project in DEV environment. I hope this is helpful &amp;amp; I would appreciate if any better solution is available.&lt;/p&gt;

</description>
      <category>drupal</category>
      <category>drush</category>
      <category>password</category>
    </item>
    <item>
      <title>Custom CRUD API in Drupal 9</title>
      <dc:creator>Rahul Khan</dc:creator>
      <pubDate>Sun, 09 Jan 2022 14:43:25 +0000</pubDate>
      <link>https://forem.com/rahulk1011/custom-crud-api-in-drupal-9-1ia8</link>
      <guid>https://forem.com/rahulk1011/custom-crud-api-in-drupal-9-1ia8</guid>
      <description>&lt;p&gt;We will be creating a custom API for our &lt;a href="https://dev.to/rahulk1011/custom-module-in-drupal-9-3n8j"&gt;custom module in Drupal 9&lt;/a&gt; to perform basic CRUD operations using API. We will perform the operations on our custom content type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Creating new folders in the Custom Module&lt;/strong&gt;&lt;br&gt;
We will create a new folder in our custom module folder (candidates) as the following structure. We will place the API codes in this folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiwrxwn2i7fasftn4zskd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiwrxwn2i7fasftn4zskd.jpg" alt="Controller folder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Creating CandidatesController.php file&lt;/strong&gt;&lt;br&gt;
In this folder, we will create a new file called 'CandidatesController.php'.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
/**
* @file
* Contains \Drupal\candidates\Controller\CandidatesController.
*/
namespace Drupal\candidates\Controller;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Drupal\user\Entity\User;
use Drupal\node\Entity\Node;
use Drupal\Core\Entity;
use Drupal\taxonomy\Entity\Term;

//Controller routines for candidates routes

class CandidatesController extends ControllerBase {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Writing the APIs for CRUD operations&lt;/strong&gt;&lt;br&gt;
Now, we will write the different APIs for adding, fetching, editing &amp;amp; deleting the records.&lt;br&gt;
Get All Candidates Details API: get_candidate_detail&lt;br&gt;
Add Candidates Details API: add_candidate_detail&lt;br&gt;
Fetch Single Candidate Details after adding: fetch_candidate_detail&lt;br&gt;
Edit Candidates Details API: edit_candidate_detail&lt;br&gt;
Delete Candidates Details API: delete_candidate&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
/**
* @file
* Contains \Drupal\candidates\Controller\CandidatesController.
*/
namespace Drupal\candidates\Controller;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Drupal\user\Entity\User;
use Drupal\node\Entity\Node;
use Drupal\Core\Entity;
use Drupal\taxonomy\Entity\Term;

//Controller routines for candidates routes

class CandidatesController extends ControllerBase {
    /**
    * Get All Candidates Details API
    */
    public function get_candidate_detail(Request $request) {
        global $base_url;
        try{
            $content = $request-&amp;gt;getContent();
            $params = json_decode($content, TRUE);
            $uid = $params['uid'];
            $user = User::load($uid);
            $all_candidates = array();

            $query_string = "SELECT node_field_data.langcode AS node_field_data_langcode, node_field_data.created AS node_field_data_created, node_field_data.nid AS nid
            FROM {node_field_data} node_field_data
            WHERE (node_field_data.status = '1') AND (node_field_data.type IN ('candidate'))
            ORDER BY node_field_data_created ASC";
            $candidate_fetch_details = \Drupal::database()-&amp;gt;query($query_string)-&amp;gt;fetchAll();

            foreach($candidate_fetch_details as $key =&amp;gt; $node_id){
                $nodeid = $node_id-&amp;gt;nid;
                $node = Node::load($nodeid);

                $candidate_details['candidate_id'] = $nodeid;
                $candidate_details['candidate_name'] = $node-&amp;gt;get('title')-&amp;gt;value;
                $date = date_create($node-&amp;gt;get('field_birth_date')-&amp;gt;value);
                $birth_date = date_format($date, "d/m/Y");
                $candidate_details['candidate_dob'] = $birth_date;
                $candidate_details['candidate_gender'] = $node-&amp;gt;get('field_gender')-&amp;gt;value;
                $candidate_details['candidate_mobile'] = $node-&amp;gt;get('field_mobile')-&amp;gt;value;
                $candidate_details['candidate_email'] = $node-&amp;gt;get('field_email_id')-&amp;gt;value;
                $candidate_details['candidate_city'] = $node-&amp;gt;get('field_city')-&amp;gt;value;
                $candidate_details['candidate_country'] = $node-&amp;gt;get('field_country')-&amp;gt;value;
                $candidate_details['candidate_description'] = $node-&amp;gt;get('field_description')-&amp;gt;value;
                array_push($all_candidates, $candidate_details);
            }
            $final_api_reponse = array(
                "status" =&amp;gt; "OK",
                "message" =&amp;gt; "All Candidate Details",
                "result" =&amp;gt; $all_candidates
            );
            return new JsonResponse($final_api_reponse);
        }
        catch(Exception $exception) {
            $this-&amp;gt;exception_error_msg($exception-&amp;gt;getMessage());
        }
    }

    /**
    * Add Candidates Details API
    */
    public function add_candidate_detail(Request $request){
        global $base_url;
        try{
            $content = $request-&amp;gt;getContent();
            $params = json_decode($content, TRUE);

            $uid = $params['uid'];
            $user = User::load($uid);

            $date = explode('/', $params['candidate_dob']);
            $birth_date = $date[2] . "-" . $date[1] . "-" . $date[0];

            $newCandidate = Node::create([
                'type' =&amp;gt; 'candidate',
                'uid' =&amp;gt; 1,
                'title' =&amp;gt; array('value' =&amp;gt; $params['candidate_name']),
                'field_birth_date' =&amp;gt; array('value' =&amp;gt; $birth_date),
                'field_gender' =&amp;gt; array('value' =&amp;gt; $params['candidate_gender']),
                'field_mobile' =&amp;gt; array('value' =&amp;gt; $params['candidate_mobile']),
                'field_email_id' =&amp;gt; array('value' =&amp;gt; $params['candidate_email']),
                'field_city' =&amp;gt; array('value' =&amp;gt; $params['candidate_city']),
                'field_country' =&amp;gt; array('value' =&amp;gt; $params['candidate_country']),
                'field_description' =&amp;gt; array('value' =&amp;gt; $params['candidate_description']),
            ]);

            // Makes sure this creates a new node
            $newCandidate-&amp;gt;enforceIsNew();

            // Saves the node, can also be used without enforceIsNew() which will update the node if a $newCandidate-&amp;gt;id() already exists
            $newCandidate-&amp;gt;save();
            $nid = $newCandidate-&amp;gt;id();
            $new_candidate_details = $this-&amp;gt;fetch_candidate_detail($nid);
            $final_api_reponse = array(
                "status" =&amp;gt; "OK",
                "message" =&amp;gt; "Candidate Details Added Successfully",
                "result" =&amp;gt; $new_candidate_details,
            );
            return new JsonResponse($final_api_reponse);
        }
        catch(Exception $exception) {
            $this-&amp;gt;exception_error_msg($exception-&amp;gt;getMessage());
        }
    }

    public function fetch_candidate_detail($nid){
        if(!empty($nid)){
            $node = Node::load($nid);

            $date = date_create($node-&amp;gt;get('field_birth_date')-&amp;gt;value);
            $birth_date = date_format($date, "d/m/Y");
            $candidate_details['candidate_name'] = $node-&amp;gt;get('title')-&amp;gt;value;
            $candidate_details['candidate_dob'] = $birth_date;
            $candidate_details['candidate_gender'] = $node-&amp;gt;get('field_gender')-&amp;gt;value;
            $candidate_details['candidate_mobile'] = $node-&amp;gt;get('field_mobile')-&amp;gt;value;
            $candidate_details['candidate_email'] = $node-&amp;gt;get('field_email_id')-&amp;gt;value;
            $candidate_details['candidate_city'] = $node-&amp;gt;get('field_city')-&amp;gt;value;
            $candidate_details['candidate_country'] = $node-&amp;gt;get('field_country')-&amp;gt;value;
            $candidate_details['candidate_description'] = $node-&amp;gt;get('field_description')-&amp;gt;value;

            $final_api_reponse = array(
                'candidate_detail' =&amp;gt; $candidate_details
            );
            return $final_api_reponse;
        }
        else{
            $this-&amp;gt;exception_error_msg("Candidate details not found.");
        }
    }

    /**
    * Edit Candidates Details API
    */
    public function edit_candidate_detail(Request $request){
        global $base_url;
        try{
            $content = $request-&amp;gt;getContent();/* reads json input from login API callback */
            $params = json_decode($content, TRUE);

            $uid = $params['uid'];
            $user = User::load($uid);

            $nid = $params['nid'];
            $date = explode('/', $params['candidate_dob']);
            $date_of_birth = $date[2] . "-" . $date[1] . "-" . $date[0];

            if(!empty($nid)){
                $node = Node::load($nid);
                $node-&amp;gt;set("field_birth_date", array('value' =&amp;gt; $date_of_birth));
                $node-&amp;gt;set("field_gender", array('value' =&amp;gt; $params['candidate_gender']));
                $node-&amp;gt;set("field_mobile", array('value' =&amp;gt; $params['candidate_mobile']));
                $node-&amp;gt;set("field_email_id", array('value' =&amp;gt; $params['candidate_email']));
                $node-&amp;gt;set("field_city", array('value' =&amp;gt; $params['candidate_city']));
                $node-&amp;gt;set("field_country", array('value' =&amp;gt; $params['candidate_country']));
                $node-&amp;gt;set("field_description", array('value' =&amp;gt; $params['candidate_description']));
                $node-&amp;gt;save();
                $final_api_reponse = array(
                    "status" =&amp;gt; "OK",
                    "message" =&amp;gt; "Candidate Details Updated Successfully",
                );
            }
            else{
                $final_api_reponse = array(
                    "status" =&amp;gt; "FAIL",
                    "message" =&amp;gt; "Candidate ID is reqired",
                );
            }
            return new JsonResponse($final_api_reponse);
        }
        catch(Exception $exception) {
            $this-&amp;gt;exception_error_msg($exception-&amp;gt;getMessage());
        }
    }

    /**
    * Delete Candidates Details API
    */
    public function delete_candidate(Request $request){
        global $base_url;
        try{
            $content = $request-&amp;gt;getContent();
            $params = json_decode($content, TRUE);
            $nid = $params['nid'];
            if(!empty($nid)){
                $node = \Drupal::entityTypeManager()-&amp;gt;getStorage('node')-&amp;gt;load($nid);
                $node-&amp;gt;delete();
                $final_api_reponse = array(
                    "status" =&amp;gt; "OK",
                    "message" =&amp;gt; "Candidate record has been deleted successfully",
                );
            }
            return new JsonResponse($final_api_reponse);
        }
        catch(Exception $exception) {
            $web_service-&amp;gt;error_exception_msg($exception-&amp;gt;getMessage());
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Adding the API in routing.yml&lt;/strong&gt;&lt;br&gt;
Now we will add the API paths in the candidates.routing.yml file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get_candidate_detail:
 path: 'api/get_candidate_detail'
 defaults: { _controller: '\Drupal\candidates\Controller\CandidatesController::get_candidate_detail' }
 methods: [POST]
 requirements:
  _permission: 'access content'

add_candidate_detail:
 path: 'api/add_candidate_detail'
 defaults: { _controller: '\Drupal\candidates\Controller\CandidatesController::add_candidate_detail' }
 methods: [POST]
 requirements:
   _permission: 'access content'

edit_candidate_detail:
 path: 'api/edit_candidate_detail'
 defaults: { _controller: '\Drupal\candidates\Controller\CandidatesController::edit_candidate_detail' }
 methods: [POST]
 requirements:
   _permission: 'access content'

delete_candidate :
 path: 'api/delete_candidate'
 defaults: { _controller: '\Drupal\candidates\Controller\CandidatesController::delete_candidate' }
 methods: [POST]
 requirements:
   _permission: 'access content'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5: Using the APIs&lt;/strong&gt;&lt;br&gt;
Using Postman, we can use the different APIs to add, edit, delete &amp;amp; fetch data from our custom content type.&lt;br&gt;
We will have to set the header Content-Type as application/json &amp;amp; method POST.&lt;br&gt;
The following params can be used to add candidate data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "candidate_name" : "Rahul Khan",
    "candidate_dob" : "10/12/1990",
    "candidate_gender" : "male",
    "candidate_mobile" : "9876543210",
    "candidate_email" : "rahul@khan.com",
    "candidate_city": "Bangalore",
    "candidate_country" : "India",
    "candidate_description" : "Hello. Test description."
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For editing, we can use the above params to edit data. For deleting a record, we will need to pass candidate_id (nid).&lt;/p&gt;

</description>
      <category>php</category>
      <category>drupal</category>
      <category>drupal9</category>
      <category>api</category>
    </item>
    <item>
      <title>Custom Module in Drupal 9</title>
      <dc:creator>Rahul Khan</dc:creator>
      <pubDate>Mon, 03 Jan 2022 06:21:27 +0000</pubDate>
      <link>https://forem.com/rahulk1011/custom-module-in-drupal-9-3n8j</link>
      <guid>https://forem.com/rahulk1011/custom-module-in-drupal-9-3n8j</guid>
      <description>&lt;p&gt;We will be creating a custom module in Drupal 9 to build a custom form &amp;amp; store the data in a custom content type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Name of the Module&lt;/strong&gt;&lt;br&gt;
We need to create a custom module under 'modules/custom' folder. We will name the folder as 'candidates'&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzrq65u7w5i0km55r102a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzrq65u7w5i0km55r102a.jpg" alt="Custom module folder structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Creating the info.yml file&lt;/strong&gt;&lt;br&gt;
We have to create a yaml file with the machine name of our module for Drupal to be able recognize the module. We will name the file as 'candidates.info.yml'&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Candidates Data
type: module
description: A custom module to enter candidate details
package: Custom
version: 1.0
core_version_requirement: ^8 || ^9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Creating the routing.yml file&lt;/strong&gt;&lt;br&gt;
Next step is to add a candidates.routing.yml file under the 'candidates' directory.&lt;br&gt;
Under path, we specify the URL path for adding Candidate data.&lt;br&gt;
Under defaults, the _controller which references a method on the CandidatesController class and the _title specifies the default page title.&lt;br&gt;
Under requirements, we specify the permission to view the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;candidates.form:
 path: '/add-candidate'
 defaults:
  _title: 'Add Candidates'
  _form: '\Drupal\candidates\Form\CandidatesForm'
 requirements:
  _permission: 'access content'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Adding the controller&lt;/strong&gt;&lt;br&gt;
We will create a controller file named 'CandidatesController.php' under 'modules/custom/candidates/src/Controller'. In this file, we will create a custom form to validate &amp;amp; submit candidate data. We will store the data into a custom content type named 'candidate'.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

/**
 * @file
 * Contains \Drupal\candidates\Form\CandidatesForm.
*/

namespace Drupal\candidates\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\node\Entity\Node;

class CandidatesForm extends FormBase {
    /**
    * {@inheritdoc}
    */
    public function getFormId() {
        return 'candidates_form';
    }

    /**
    * {@inheritdoc}
    */
    public function buildForm(array $form, FormStateInterface $form_state) {
        $form['candidate_name'] = array(
            '#type' =&amp;gt; 'textfield',
            '#title' =&amp;gt; t('Candidate Name'),
            '#required' =&amp;gt; TRUE,
        );
        $form['candidate_dob'] = array(
            '#type' =&amp;gt; 'date',
            '#title' =&amp;gt; t('Birth Date'),
            '#required' =&amp;gt; TRUE,
        );
        $form['candidate_gender'] = array(
            '#type' =&amp;gt; 'select',
            '#title' =&amp;gt; ('Gender'),
            '#required' =&amp;gt; TRUE,
            '#options' =&amp;gt; array(
                'male' =&amp;gt; t('Male'),
                'female' =&amp;gt; t('Female'),
                'other' =&amp;gt; t('Other'),
            ),
        );
        $form['candidate_mobile'] = array(
            '#type' =&amp;gt; 'textfield',
            '#title' =&amp;gt; t('Mobile'),
            '#required' =&amp;gt; TRUE,
            '#maxlength' =&amp;gt; 10,
        );
        $form['candidate_email'] = array(
            '#type' =&amp;gt; 'email',
            '#title' =&amp;gt; t('Email-ID'),
            '#required' =&amp;gt; TRUE,
        );
        $form['candidate_city'] = array(
            '#type' =&amp;gt; 'textfield',
            '#title' =&amp;gt; t('City'),
            '#required' =&amp;gt; TRUE,
        );
        $form['candidate_country'] = array(
            '#type' =&amp;gt; 'textfield',
            '#title' =&amp;gt; t('Country'),
            '#required' =&amp;gt; TRUE,
        );
        $form['candidate_description'] = array(
            '#type' =&amp;gt; 'textarea',
            '#title' =&amp;gt; t('Description'),
            '#required' =&amp;gt; TRUE,
        );
        $form['actions']['#type'] = 'actions';
        $form['actions']['submit'] = array(
            '#type' =&amp;gt; 'submit',
            '#value' =&amp;gt; $this-&amp;gt;t('Save Candidate Data'),
            '#button_type' =&amp;gt; 'primary',
        );
        return $form;
    }

    /**
    * {@inheritdoc}
    */
    public function validateForm(array &amp;amp;$form, FormStateInterface $form_state) {
        if ($form_state-&amp;gt;getValue('candidate_name') == '') {
            $form_state-&amp;gt;setErrorByName('candidate_name', $this-&amp;gt;t('Please Enter Name'));
        }
        if ($form_state-&amp;gt;getValue('candidate_dob') == '') {
            $form_state-&amp;gt;setErrorByName('candidate_dob', $this-&amp;gt;t('Please Enter Birth Date'));
        }
        if ($form_state-&amp;gt;getValue('candidate_gender') == '') {
            $form_state-&amp;gt;setErrorByName('candidate_gender', $this-&amp;gt;t('Please Select Gender'));
        }
        if ($form_state-&amp;gt;getValue('candidate_mobile') == '') {
            $form_state-&amp;gt;setErrorByName('candidate_mobile', $this-&amp;gt;t('Please Enter Mobile'));
        }
        if ($form_state-&amp;gt;getValue('candidate_email') == '') {
            $form_state-&amp;gt;setErrorByName('candidate_email', $this-&amp;gt;t('Please Enter Email-ID'));
        }
        if ($form_state-&amp;gt;getValue('candidate_city') == '') {
            $form_state-&amp;gt;setErrorByName('candidate_city', $this-&amp;gt;t('Please Enter City'));
        }
        if ($form_state-&amp;gt;getValue('candidate_country') == '') {
            $form_state-&amp;gt;setErrorByName('candidate_country', $this-&amp;gt;t('Please Enter Country'));
        }
        if ($form_state-&amp;gt;getValue('candidate_description') == '') {
            $form_state-&amp;gt;setErrorByName('candidate_description', $this-&amp;gt;t('Please Enter Description'));
        }
    }

    /**
    * {@inheritdoc}
    */
    public function submitForm(array &amp;amp;$form, FormStateInterface $form_state) {
        $node = Node::create(['type' =&amp;gt; 'candidate']);
        $node-&amp;gt;langcode = "en";
        $node-&amp;gt;uid = 1;
        $node-&amp;gt;promote = 0;
        $node-&amp;gt;sticky = 0;
        $node-&amp;gt;title= $form_state-&amp;gt;getValue('candidate_name');
        $node-&amp;gt;field_birth_date = $form_state-&amp;gt;getValue('candidate_dob');
        $node-&amp;gt;field_gender = $form_state-&amp;gt;getValue('candidate_gender');
        $node-&amp;gt;field_mobile = $form_state-&amp;gt;getValue('candidate_mobile');
        $node-&amp;gt;field_email_id = $form_state-&amp;gt;getValue('candidate_email');
        $node-&amp;gt;field_city = $form_state-&amp;gt;getValue('candidate_city');
        $node-&amp;gt;field_country = $form_state-&amp;gt;getValue('candidate_country');
        $node-&amp;gt;field_description = $form_state-&amp;gt;getValue('candidate_description');
        $node-&amp;gt;save();

        \Drupal::messenger()-&amp;gt;addMessage(t("Candidate Data Save Successful"));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5: Creating custom content type&lt;/strong&gt;&lt;br&gt;
Create a custom content type named 'candidate' to store the data&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5di3qfjvr5iqglwy1wm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5di3qfjvr5iqglwy1wm.jpg" alt="Custom content type fields"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>drupal</category>
      <category>drupal9</category>
    </item>
  </channel>
</rss>
