diff --git a/.cspell.json b/.cspell.json
new file mode 100644
index 0000000000000000000000000000000000000000..623863d19a5bd724e1bda548d52bb633d31b71a8
--- /dev/null
+++ b/.cspell.json
@@ -0,0 +1,20 @@
+{
+  "version": "0.2",
+  "language": "en",
+  "ignoreWords": [
+    "Apath",
+    "Holovachek",
+    "Pradeep",
+    "Venugopal",
+    "Viktor",
+    "adipiscing",
+    "amet",
+    "apath",
+    "clicksorter",
+    "countquery",
+    "elit",
+    "firstname",
+    "lastname",
+    "venugopp"
+  ]
+}
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c39db76a058e974fb032a404b993489262ef726
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,26 @@
+{
+  "name": "drupal/views_json_source",
+  "description": "Views Json Source is an extension of views module to work with external JSON data.",
+  "type": "drupal-module",
+  "license": "GPL-2.0-or-later",
+  "keywords": ["Drupal"],
+  "homepage": "https://www.drupal.org/project/views_json_source",
+  "authors": [
+    {
+      "name": "Pradeep Venugopal (venugopp)",
+      "homepage": "https://www.drupal.org/u/venugopp",
+      "role": "Maintainer"
+    },
+    {
+      "name": "Viktor Holovachek (AstonVictor)",
+      "homepage": "https://www.drupal.org/u/astonvictor",
+      "role": "Maintainer"
+    }
+  ],
+  "minimum-stability": "dev",
+  "support": {
+    "issues": "https://www.drupal.org/project/issues/views_json_source",
+    "source": "https://git.drupalcode.org/project/views_json_source"
+  },
+  "require": {  }
+}
diff --git a/config/optional/views.view.views_json_source.yml b/config/optional/views.view.views_json_source.yml
index 77d81030ab4999ed1d50b489cd397331f8936194..d43e5dc9714454a132cb616de28c019049a40388 100644
--- a/config/optional/views.view.views_json_source.yml
+++ b/config/optional/views.view.views_json_source.yml
@@ -27,6 +27,7 @@ display:
         type: views_query
         options:
           json_file: '[site:url]modules/contrib/views_json_source/data/sample/example1.json'
+          request_method: 'get'
           row_apath: data/nodes
           show_errors: 1
       exposed_form:
@@ -196,6 +197,7 @@ display:
         type: views_query
         options:
           json_file: '[site:url]modules/contrib/views_json_source/data/sample/example1.json'
+          request_method: 'get'
           row_apath: data/nodes
           headers: ''
           show_errors: 1
@@ -225,6 +227,7 @@ display:
         type: views_query
         options:
           json_file: '/modules/contrib/views_json_source/data/sample/example2.json'
+          request_method: 'get'
           row_apath: data/%/contents
           headers: ''
           show_errors: 1
@@ -278,6 +281,7 @@ display:
         type: views_query
         options:
           json_file: '/modules/contrib/views_json_source/data/sample/example3.json'
+          request_method: 'get'
           row_apath: nid=2/related
           headers: ''
           show_errors: 1
diff --git a/src/Plugin/views/filter/ViewsJsonFilter.php b/src/Plugin/views/filter/ViewsJsonFilter.php
index f9ea4a9618a2ebbffd79d52bf1f9cc5bd4d401a2..33f80c764596ae760389ff80adae0a0f400b6877 100644
--- a/src/Plugin/views/filter/ViewsJsonFilter.php
+++ b/src/Plugin/views/filter/ViewsJsonFilter.php
@@ -231,11 +231,19 @@ class ViewsJsonFilter extends FilterPluginBase {
    * Generate the filter criteria.
    */
   public function generate() {
+    $options = $this->options;
+
     $operator = $this->options['operator'];
-    $key = $this->options['key'];
-    $value = !empty($this->value) && $this->isExposed() ? reset($this->value) : $this->options['value'];
+    if ($options['exposed'] && $options['expose']['use_operator']) {
+      $operator = $this->operator;
+    }
+
+    $value = $this->options['value'];
+    if ($options['exposed'] && !empty($this->value)) {
+      $value = $options['expose']['multiple'] ? $this->value : reset($this->value);
+    }
 
-    return [$key, $operator, $value];
+    return !empty($value) ? [$this->options['key'], $operator, $value] : [];
   }
 
 }
diff --git a/src/Plugin/views/query/ViewsJsonQuery.php b/src/Plugin/views/query/ViewsJsonQuery.php
index dd790a6c02f7079fccc4fb5b54d9d3fcfb5e11b7..ac107274ab24d0831aeb596c9be675edc65ed72e 100755
--- a/src/Plugin/views/query/ViewsJsonQuery.php
+++ b/src/Plugin/views/query/ViewsJsonQuery.php
@@ -3,7 +3,9 @@
 namespace Drupal\views_json_source\Plugin\views\query;
 
 use Drupal\Component\Datetime\TimeInterface;
-use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
+use Drupal\Component\Serialization\Json;
+use Drupal\Component\Transliteration\TransliterationInterface;
+use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Form\FormStateInterface;
@@ -15,6 +17,7 @@ use Drupal\views_json_source\Event\PreCacheEvent;
 use GuzzleHttp\ClientInterface;
 use Psr\Log\LoggerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Base query handler for views_json_source.
@@ -58,7 +61,7 @@ class ViewsJsonQuery extends QueryPluginBase {
   /**
    * The event dispatcher.
    *
-   * @var \Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
    */
   protected $eventDispatcher;
 
@@ -121,6 +124,13 @@ class ViewsJsonQuery extends QueryPluginBase {
    */
   public $filter = [];
 
+  /**
+   * Transliteration service.
+   *
+   * @var \Drupal\Component\Transliteration\TransliterationInterface
+   */
+  protected $transliteration;
+
   /**
    * {@inheritdoc}
    */
@@ -206,9 +216,13 @@ class ViewsJsonQuery extends QueryPluginBase {
     else {
       // Add the request headers if available.
       $headers = $this->options['headers']
-        ? json_decode($this->options['headers'], TRUE) ?? []
+        ? Json::decode($this->options['headers']) ?? []
         : [];
 
+      foreach ($headers as $key => $value) {
+        $headers[$key] = $this->token->replacePlain($value);
+      }
+
       $result = $this->getRequestResponse($uri, $headers);
       if (isset($result->error)) {
         $args = ['%error' => $result->error, '%uri' => $uri];
@@ -359,6 +373,10 @@ class ViewsJsonQuery extends QueryPluginBase {
    * Define ops for using in filter.
    */
   public function ops($op, $l, $r) {
+    // Transliterate values before comparison.
+    $l = $this->transliterateValue($l);
+    $r = $this->transliterateValue($r);
+
     $table = [
       '=' => function ($l, $r) {
         return $l == $r;
@@ -367,44 +385,51 @@ class ViewsJsonQuery extends QueryPluginBase {
         return $l != $r;
       },
       'contains' => function ($l, $r) {
-        return stripos($l, $r) !== FALSE;
+        return $l !== NULL && $r !== NULL ? stripos($l, $r) !== FALSE : FALSE;
       },
       'starts' => function ($l, $r) {
-        return strpos($l, $r) === 0;
+        return $l !== NULL && $r !== NULL ? strpos($l, $r) === 0 : FALSE;
       },
       'not_starts' => function ($l, $r) {
-        return strpos($l, $r) !== 0;
+        return $l !== NULL && $r !== NULL ? strpos($l, $r) !== 0 : FALSE;
       },
       'ends' => function ($l, $r) {
-        $len = strlen($r);
+        $len = $l !== NULL && $r !== NULL ? strlen($r) : 0;
         return $len > 0 ? substr($l, -$len) === $r : TRUE;
       },
       'not_ends' => function ($l, $r) {
-        $len = strlen($r);
+        $len = $l !== NULL && $r !== NULL ? strlen($r) : 0;
         return $len > 0 ? substr($l, -$len) !== $r : TRUE;
       },
       'not' => function ($l, $r) {
-        return stripos($l, $r) === FALSE;
+        return $l !== NULL && $r !== NULL ? stripos($l, $r) === FALSE : FALSE;
       },
       'shorterthan' => function ($l, $r) {
-        return strlen($l) < $r;
+        return $l !== NULL ? strlen($l) < $r : FALSE;
       },
       'longerthan' => function ($l, $r) {
-        return strlen($l) > $r;
+        return $l !== NULL ? strlen($l) > $r : FALSE;
       },
       'regular_expression' => function ($l, $r) {
-        return preg_match($r, $l) === 1;
+        return $l !== NULL && $r !== NULL ? preg_match($r, $l) === 1 : FALSE;
       },
     ];
 
-    return call_user_func_array($table[$op], [$l, $r]);
+    return array_key_exists($op, $table) ? call_user_func($table[$op], $l, $r) : FALSE;
+  }
+
+  /**
+   * Transliterate.
+   */
+  protected function transliterateValue($value) {
+    return $this->transliteration->transliterate($value);
   }
 
   /**
    * Parse.
    */
   public function parse(ViewExecutable &$view, $data) {
-    $ret = json_decode($data->contents, TRUE);
+    $ret = Json::decode($data->contents);
     if (!$ret) {
       return FALSE;
     }
@@ -422,7 +447,8 @@ class ViewsJsonQuery extends QueryPluginBase {
       foreach ($view->build_info['query'] as $filter) {
         // Filter only when value is present.
         if (!empty($filter[0])) {
-          $l = $row[$filter[0]];
+          $filter_keys = explode('/', trim($filter[0], '//'));
+          $l = NestedArray::getValue($row, $filter_keys);
           $check = $this->ops($filter[1], $l, $filter[2]);
           if ($group_conditional_operator === "AND") {
             // With AND condition.
@@ -443,6 +469,9 @@ class ViewsJsonQuery extends QueryPluginBase {
       }
     }
 
+    // Save the total number of results in the view.
+    $total_number_results = count($ret);
+
     try {
       if ($view->pager->useCountQuery() || !empty($view->get_total_rows)) {
         // Hackish execute_count_query implementation.
@@ -487,7 +516,8 @@ class ViewsJsonQuery extends QueryPluginBase {
         $row->index = $index++;
       }
 
-      $view->total_rows = count($result);
+      // Pass the total number of the results.
+      $view->total_rows = $total_number_results;
 
       $view->pager->postExecute($view->result);
 
@@ -547,6 +577,8 @@ class ViewsJsonQuery extends QueryPluginBase {
     $options['json_file'] = ['default' => ''];
     $options['row_apath'] = ['default' => ''];
     $options['headers'] = ['default' => ''];
+    $options['request_method'] = ['default' => 'get'];
+    $options['request_body'] = ['default' => ''];
     $options['single_payload'] = ['default' => ''];
     $options['show_errors'] = ['default' => TRUE];
 
@@ -578,6 +610,29 @@ class ViewsJsonQuery extends QueryPluginBase {
       '#description' => $this->t("Headers to be passed for the REST call.<br />Pass the headers as JSON string. Ex:<br /><pre>{&quot;Authorization&quot;:&quot;Basic xxxxx&quot;,&quot;Content-Type&quot;:&quot;application/json&quot;}</pre><br />.Here we are passing 2 headers for making the REST API call."),
       '#required' => FALSE,
     ];
+    $form['request_method'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Request method'),
+      '#default_value' => $this->options['request_method'],
+      '#options' => [
+        'get' => $this->t('GET'),
+        'post' => $this->t('POST'),
+      ],
+      '#description' => $this->t('The request method to the REST call.'),
+    ];
+    $form['request_body'] = [
+      '#type' => 'textarea',
+      '#title' => $this->t('Request body'),
+      '#default_value' => $this->options['request_body'],
+      '#states' => [
+        'visible' => [
+          'select[name="query[options][request_method]"]' => [
+            'value' => 'post',
+          ],
+        ],
+      ],
+      '#description' => $this->t('The POST request body to the REST call.<br/>Pass the form values as JSON string. Ex: <br/><pre>[{&quot;name&quot;:&quot;item_key&quot;,&quot;contents&quot;:&quot;item value&quot;,&quot;headers&quot;:{&quot;Content-type&quot;:&quot;application/json&quot;}}]</pre> See <a href="https://docs.guzzlephp.org/en/stable/request-options.html#multipart" target="_blank">the documentation for GuzzleHttp multipart request options</a>.'),
+    ];
     $form['single_payload'] = [
       '#type' => 'checkbox',
       '#title' => $this->t('Response contain single node.'),
@@ -722,7 +777,23 @@ class ViewsJsonQuery extends QueryPluginBase {
    *   The request response.
    */
   private function getRequestResponse(string $uri, array $headers = []) {
-    return $this->httpClient->get($uri, ['headers' => $headers]);
+    $this->options['request_method'] = $this->options['request_method'] ?? 'get';
+    switch ($this->options['request_method']) {
+      case 'post':
+        $options = [];
+        $options['headers'] = $headers;
+        if (!empty($this->options['request_body'])) {
+          $options['multipart'] = Json::decode($this->options['request_body']);
+        }
+        $result = $this->httpClient->post($uri, $options);
+        break;
+
+      default:
+        $result = $this->httpClient->get($uri, ['headers' => $headers]);
+        break;
+    }
+
+    return $result;
   }
 
 }
diff --git a/views_json_source.services.yml b/views_json_source.services.yml
index 7657bbed28a1c25b683c5dda0edf4d47b509ca1c..2f2f0e49f445ee232f2afcee05d70d7f430ecd3a 100644
--- a/views_json_source.services.yml
+++ b/views_json_source.services.yml
@@ -1,4 +1,4 @@
 services:
   logger.channel.views_json_source:
     parent: logger.channel_base
-    arguments: [ 'views_json_source' ]
\ No newline at end of file
+    arguments: [ 'views_json_source' ]