DBSlayer прокси на BASH за 5 минут или еще один способ отдать JSON из MySQL

в 11:18, , рубрики: bash, javascript, json, linux, mysql, метки: , , , ,

DBSlayer прокси на BASH за 5 минут или еще один способ отдать JSON из MySQL

Дело было вечером, делать было нечего, но дурная голова уркам покоя не давала… Данный пост создан как результат чисто-академического интереса. А началось все с того, что при разработке небольшого клиентского приложения для своих нужд, реализованного на Javascript, появилась необходимость взаимодействовать с уже существующей базой, где хранятся искомые данные. База — MySQL. Один из простых способов — реализация серверного скрипта (на PHP или еще каком языке), который по входящим параметрам делает нужный запрос и возвращает результат в JSON виде.

Другой вариант — это DBSlayer-прокси для MySQL. Кто про него не слышал, рассказываю в крадце: был создан в недрах New York Times как средство абстракции и балансирования нагрузки на БД. Подробнее можно почитать на сайте code.nytimes.com/projects/dbslayer/wiki/WhyUseIt. DBSlayer предоставляет API на основе JSON, известен в кругу NodeJS разработчиков.

Но это тоже не наш метод. Под катом приведено простое решение данной задачи на BASH.

Ну вот лень мне ставить было эту приблуду, да и задача, напомню, решается чисто для себя, никаких нагрузок и прочих радостей продакшн решений. Писать на PHP немного надоело, душа просила разнообразия и какого-нить выпендрежа. Решил сделатьс вою простую прослойку, в виде HTTP сервера на BASH, с реализацией нужного функционала.

Ни для кого не секрет, что Netcat в связке с дописыванием пары строк на баше можно превратить в WEB сервер. На хабре даже были посты про это. Взяв эту идею и доработав, мы можем получить простой аналог DBSlayer на коленке bash за пять минут.

От слов к действию...

Сначала напишем простую вспомогательную утилиту, для конвертирования вывода результатов из консольного клиента mysql в JSON формат:

cat ~/bin/mysql2json.sh
#!/bin/bash

sed -e 's/t/","/g' 
    -e 's/^/["/'    
    -e 's/$/"],/'   
    -e '1s/(.*)/{"fields":1 "data":[/g' -e '$s/.$/]}/' 
| tr -d "n"

Используется она просто:

mysql -e "SELECT * FROM `mytable`" | ./mysql2json.sh

{"fields":["field_1","field_2","field_3"],"data":[["1","2","3"],["4","5","6"],["7","8","9"]]}

Теперь сам код сервера, который помещаем в файл dbjs.sh:

#!/bin/bash

:;while [ $? -eq 0 ]
do.
  nc -vlp 8880 -c '(
    r=read;
    e=echo;

    $r a b c;

    z=$r;

    while [ ${#z} -gt 2 ]
    do.
      $r z;
    done;

    f=`$e $b|sed 's/[^a-z0-9_.-]//gi'`;

    h="HTTP/1.0";
    o="$h 200 OKrn";
    c="Content";

    m="mysql -ulol -ptrololo"
    m2j="~/bin/mysql2json.sh"

    $e "$o$c-Type: text/json";
    $e;

    if [[ ( -n "$f" ) && ( "$f" != "favicon.ico" ) ]]
    then.
      $e "+ Connect to [$f]">&2;

      db=${f%.*};
      tb=${f#*.};

      if [ "$tb" = "$db" ]
      then
        $e `$m ${db:-test} -e "show tables" | $m2j`;
      else
        $e `$m ${db:-test} -e "select * from $tb" | $m2j`;
      fi;

    else
      $e `$m -e "show databases" | $m2j`;
    fi
  )';
done

Собственно и все. Запускаем и видим в консоли что-то вроде:

[ bash: ./dbjs.sh
listening on [any] 8880 ...

Далее просто обращаемся к нашему серверу, по указанному порту и получаем вывод:

// http://127.0.0.1:8880 - Выводит список баз данных
{
    fields: [
           "Database"
    ],
    data: [
         [ "information_schema" ],
         [ "test" ]
    ]
}
// http://127.0.0.1:8880/test - Выводит список таблиц базы данных test
{
          fields: [
              "Tables_in_test"
          ],
         data: [
             ["prods"],
             ["shops"],
             ["sp"],
             ["stat"]
         ]
}
// http://127.0.0.1:8880/test.shops - Выводит данные таблицы test.shops

{
     "fields": [
           "id",
           "name",
           "adress"
     ],
     "data": [
           ["1","aaaaa",""],
           ["2","bbbbbbbbb",""],
           ["3","cccccccccccccccc","ccc"]
     ]
}

Скрипт не идеален, но никто не мешает его дорабатывать, если в этом вообще есть нужда.

П.С.: На вопрос: Зачем?, сразу отвечу: по фану. Жизнь должна приносит радость. Мне нравится получать позитив от таких вот нестандартных решений.

Автор: 0xy

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js