Записать данные json в переменную
Нужно загрузить json и записать его данные в переменную, что бы я смог вытаскивать разную информацию из переменной в любой момент. Не могу понять как это сделать!
Отслеживать
задан 5 апр 2020 в 13:06
олег логвинов олег логвинов
39 7 7 бронзовых знаков
4 ответа 4
Сортировка: Сброс на вариант по умолчанию
var test = JSON.parse( data );
И консоль должна быть внутри success, а не под запросом, потому что запрос не синхронный
Отслеживать
ответ дан 5 апр 2020 в 13:08
user347472 user347472
В том то и дело, мне нужно данные забрать из success и использовать их вне ajax
5 апр 2020 в 13:11
JavaScript так не работает. Если код стал асинхронным, то его уже нельзя привести в синхронный вид. Так что у вас либо всё далее будет идти в другой функции а не снизу, либо как вариант через async-await через промисы, но там тоже только видимость синхронности.
– user347472
5 апр 2020 в 13:13
Т.к. ajax — асинхронная операция, то она может длиться и 2 секунды и 22 секунды, хотя в это время может и страницу прогрузиться и пользователь что-то понажимать.
Если я правильно разглядел, то никакая работа не предполагается, пока не будет загружен json . Отсюда есть минимум один выход: вешать картинку «loading» перед запросом и убирать после получения ответа. Можно это сделать на весь экран, чтоб пользователь ничего не трогал.
let test = null; $.ajax(< url: 'http://atom-web.github.io/wattson/style-components/sity.json', beforeSend: function( xhr ) < // Здесь включаем какой-то loader.gif чтобы дать пользователю понять, // что идёт загрузка данных >, success: function(data)< test = data; // Здесь выключаем loader.gif и разблокируем элементы, // чтобы пользователь мог начать работать >, >);
Также можно обратить внимание на async/await функции, что позволит дождаться загрузки аякса и тоже выполнять функции далее.
WordPress & JS
При разработке приложений на JavaScript, будь то чиcтый js или один из многочисленных фреймворков, рано или поздно возникает вопрос — как наладить общение с базой данных?
Варианты ответа вроде элементарны:
- используем Node.js для разработки серверной части приложения (это ведь тоже JavaScript);
- используем Python / Django для той же цели;
- используем классический вариант — PHP.
Хорошо, когда вы работаете в команде и есть back-end разработчик, который все эти вопросы возьмёт на себя, вам же выдаст инструкцию — куда какие запросы посылать, чтобы получить данные из базы.
Но иногда приходится косплеить fullstack-разработчика. Данная статья как раз об этом.
Здесь мы не будем рассматривать очевидные и популярные варианты (Node.js и Python), а сделаем своё собственное API на PHP, и поможет нам в этом старый-добрый WordPress.
В этой статье мы в общем виде и кратко, но ёмко рассмотрим, как можно организовать этакий middle-end. Здесь мы не будем рассматривать подробно разработку на javascript, только в общем виде покажем части некоего абстрактного приложения.
Перед самым началом
Прежде всего установим сам WordPress и создадим в нем простую тему, в которой и будет размещено наше приложение. Для нашего сегодняшнего урока я разработал специальную техническую тему, с помощью которой мы будем учиться работать с API. Скачать её можно по этой ссылке.
Также рекомендую — если вдруг у вас ещё в арсенале не присутствует — классную программу Postman, с помощью которой очень удобно отлаживать работу API.
Подготовка
Для начала разберёмся, что за приложение мы будем создавать — это поможет нам разобраться, какую именно информацию мы будем запрашивать из базы данных через WordPress.
Допустим, мы решили сделать приложение, которое имеет следующий функционал:
- Авторизует пользователя — просто проверим, есть ли такой пользователь вообще. Регистрацию / восстановление мы вынесенем за рамки статьи, ибо по прочтении её такое вы сможете сделать уже самостоятельно (пусть будет домашкой).
- Выводит авторизованному пользователю записи из базы данных.
Да, функционал очень простой, но не будем заморачиваться — у нас только учебный проект.
Итак, соответственно нам необходимо создать 2 энд-поинта, с помощью которых мы будем общаться со всей системой. Предлагаю их назвать кратко и лаконично — auth и post.
Забегая немного вперед, скажу что мы не будем пользоваться стандартными роутами WordPress для получения постов / записей, а сделаем все ручками.
Создаём роуты
Итак, мы договорились, что никаким образом не будем пользоваться стандартными средствами. Поэтому наш путь — в functions.php.
Нам необходимо создать новый action для для хука rest_api_init, который поможет нам создать новый маршрут для REST API:
// Энд-поинты приложения add_action('rest_api_init', function() < >);
Как видите, к хуку ‘rest_api_init’ я добавил неименованную функцию, потому что у нас будет несколько маршрутов.
Авторизация пользователя
Начнем с базового функционала — посмотрим, есть ли у нас пользователь с такими учетными данными, и вернем ответ.
Напишем первую функцию маршрута и разберёмся, что же здесь написано.
// Маршрут авторизации register_rest_route('api/', 'auth/', [ 'methods' => 'POST', 'callback' => 'auth', 'args' => array( 'login' => array( 'default' => $login ), 'password' => array( 'default' => $pass ), ), ]);
Первые два аргумента функции — это переменные адреса, по которому мы будем посылать запрос, что соответсвует такому адресу:
https://awesomesite.com/wp-json/api/auth
Далее, в параметре ‘methods’ мы определяем метод, с помощью которого мы данные отправим (POST).
Параметр ‘callback’ вызывает функцию, которая должна будет сработать при обращении на этот адрес.
И наконец параметр ‘args’ массивом указывает, какие ключи в этом запросе имеются. В нём мы указываем, что передаем на обработку логин пользователя и пароль.
Строим запрос от приложения
Первый роут готов, мы пока его оставим в таком виде и ненадолго отвлечёмся от WordPress и вернемся к нашему приложению — давайте посмотрим, как мы будем такой запрос строить.
Мы уже договорились, что подробно расписывать устройство JS-приложения не будем. Условимся, что в нашем приложении при первоначальной загрузке мы просим указать пользователя email и пароль. После того, как он эти данные ввёл, мы передаем эти данные примерно вот таким образом:
// Формируем объект из логина и пароля пользователя let data = < login, password >; // Адрес к энд-поинту авторизации let pathToAPI = 'https://awesomesite.com/wp-json/api/auth'; // Запрос fetch(pathToAPI, < method: 'POST', body: JSON.stringify(data), headers: < 'content-type': 'application/json' >>).then((response) => < return response.json(); >).then((data) => < handle(data); >)
Мы написали простейший fetch-запрос (настолько простейший, что даже catch не указали), с помощью которого забросим данные по нужному нам адресу.
Здесь я вынес адрес в отдельную переменную, чтобы лучше воспринимался визуально. Рекомендую сделать функцию, которая будет в зависимости от нужной операции возвращать соответствующий адрес к API.
Также обратите внимание на headers — там обязательно нужно указать строку ‘content-type’: ‘application/json’, иначе магии не получится.
Обрабатываем запрос
Теперь, когда практически всё готово, мы возвращаемся в WordPress и напишем обработчик запроса по маршруту авторизации.
Сначала обдумаем схему работы функции (это полезно и экономит время). Вот мы отправили логин (email) и пароль серверу. Он их должен проверить и если такой пользователь существует, то вернуть нам его ID. А если нет — то сообщить, что введённые данные неправильные.
Используя стандартные функции WordPress, напишем такую функцию, её работу прокомментирую прям по ходу:
// Функция авторизации пользователя function auth($request) < // Вытаскиваем в отдельные переменные ключи из запроса $login = $request['login']; $password = $request['password']; // Проверяем пользователя $auth = wp_authenticate($login, $password); // Если ошибки нет if (!is_wp_error($auth)) < // Получаем id пользователя по email $user = get_user_by('email', $login); $user_ID = $user->data->ID; // Формируем объект ответа $response = array( "id" => $user_ID ); // В случае ошибки > else < $response = array( "state" =>'error', "response" => 'Неправильный логин / пароль' ); > // Возвращаем объект ответа return $response; >
Итак, первый маршрут готов. Можем попробовать послать запрос от приложения к API и получить ответ в виде объекта, который уже нужным нам образом можно обработать.
Запрос данных
Перейдем ко второму маршруту — запросим список последних постов для пользователя. Аналогичным образом добавляем новый роут для API:
// Маршрут получения постов register_rest_route('api/', 'posts/', [ 'methods' => 'POST', 'callback' => 'getPosts', 'args' => array( 'id' => array( 'default' => $id ), 'type' => array( 'default' => $type ), 'counts' => array( 'default' => $counts ), ), ]);
Здесь повысим ставки — теперь нам нужно 3 параметра передать: это id пользователя (зачем-то мы его получали же!), тип поста и количество постов.
Теперь напишем саму функцию по обработке:
// Функция авторизации пользователя function getPosts($request) < // Вытаскиваем в отдельные переменные ключи из запроса $id = $request['id']; $type = $request['type']; $counts = $request['counts']; // Если id передано if($id) < // Массив постов $posts = array(); // Формируем запрос с помощью WP_Query $query = new WP_Query(array( 'post_type' =>$type, 'posts_per_page' => $counts )); // Пройдемся по массиву while ($query->have_posts()) : $query->the_post(); // Получаем заголовок и описание $title = esc_html(get_the_title()); $desc = get_the_excerpt(); // Получаем ссылку на изображение (если оно есть) if(has_post_thumbnail()) < $thumb_id = get_post_thumbnail_id(); $thumb_cover_url = wp_get_attachment_image_src($thumb_id, full, true); $imgUrl = $thumb_cover_url[0]; >else < $imgUrl = 'null'; // Или можно указать ссылку на картинку-заглушку >// Формируем объект поста $post = array( "title" => $title, "description" => $desc, "img" => $imgUrl ); // Добавляем его в массив постов array_push($posts, $post); endwhile; wp_reset_postdata(); // Ответ - это массив постов $response = $posts; // В случае, если id передано > else < $response = array( "state" =>'error', "response" => 'Мне нужен ID' ); > // Возвращаем объект ответа return $response; >
В результате мы получим массив объектов, который можно спокойно использовать в своём приложении.
У нас даже получилось лучше, чем в стандартной реализации, потому что отдаётся меньший по составу объект и кроме того, у нас уже имеется ссылка на изображение-обложку поста, а не только ID медиафайла.
Итого
Вот так с помощью WordPress и его немудрёного функционала можно достаточно быстро собрать себе API для приложения. Осталось только взять любимый фреймворк и наладить взаимодействие.
Надеюсь, что материал будет полезен для вас и поможет разрешить некоторые трудности.
Автор блога, веб-разработчик
Запись данных в формате JSON
В одной из моих программ понадобилась запись данных в формате JSON. Вкратце — XML-подобный формат, вполне подходит на замену Windows INI-файлам или тому же XML. Удобен тем, что поддерживает массивы и вложенность собственных структур, но при этом не замусоривает файл данных своими тегами до полной нечитабельности человеком. Вот пример файла данных:
< "Comment":"My comment", "Count":10, "DiskParam": < "DB":10.000000, "DBAngle":1.234000 >, "Range":true, "Blades": [ < "Caption":"A", "Value":65 >, < "Caption":"B", "Value":66 >, < "Caption":"C", "Value":67 >], "Slots": [ 0,1,2 ] >
Формат довольно простой, вполне можно работать с ним без всяких библиотек. Поэтому первоначально за запись отвечал примерно такой участок кода:
fprintf(pOut, "<\n"); fprintf(pOut, " \"Comment\":\"%s\"", Header->Comment); fprintf(pOut, ",\n \"NumSt\":%d", Header->NumSt); //Пропущено немного кода fprintf(pOut, ",\n \"DBMax\":%lf", Header->DBMax); fprintf(pOut, ",\n \"Range\":%s", Header->Range?"true":"false"); fprintf(pOut, ",\n \"Blades\":\n ["); for(int i=0; iCount; i++) < TElement &e=Element[i]; fprintf(pOut, i?",\n "); > fprintf(pOut, "\n ]"); //Пропущено много кода fprintf(pOut, "\n>");
Корявенько, хотя вполне работоспособно. Но программа активно дорабатывалась, формат данных менялся по 5 раз на дню и остро встала проблема отслеживания всех изменений. Несмотря на некоторое форматирование исходника было тяжело не забыть закрыть какой-нибудь тег или правильно напечатать нужное число пробелов для форматирования уже собственно файла данных. Даже в приведенном фрагменте перед публикацией обнаружилась ошибка, не ставилась запятая между элементами массива.
Решил я этот техпроцесс слегка механизировать и создать микробиблиотеку для работы с JSON.
Что я хотел? Чтобы в своей программе я писал что-то на псевдоязыке:
Key("Ключ1"); Value("Значение1"); Key("Ключ2"); Value("Значение2"); Object("Объект1"); Key("Ключ3"); Value("Значение3"); //Ключ3,Ключ4 являются элементами Объект1 Key("Ключ4"); Value("Значение4"); Array("Массив1"); Key("Ключ5"); Value("Значение5"); //Ключ5. КлючN являются элементами Массив1 Key("Ключ6"); Value("Значение6"); . Key("КлючN"); Value("ЗначениеN");
А компилятор/программа пусть сами учтут отступы, которые определяют структуру файла данных. В нужный момент подставят открывающий и, главное, закрывающий тег. Дело осложнялось тем, что внутри этого скрипта хотелось использовать конструкции C++, например циклы внутри массивов.
После нескольких дней непрерывной мозговой осады этой проблемы нашлось довольно изящное решение. Для контроля за вложением друг в друга JSON-сущностей и своевременного закрытия тегов используется область видимости переменных. Все очень просто, создается экземпляр одного из классов TJson*** — записывается ключ и открывающий тег и все следующие созданные объекты считаются его вложениями. Уничтожается экземпляр — ставится закрывающий тег.
#define TCF_USED 1 class TTagCloser < public: TTagCloser *Owner; static TTagCloser *Current; static int Depth; int Flags; int Count; int operator()()TTagCloser() ~TTagCloser() >; TTagCloser *TTagCloser::Current=NULL; int TTagCloser::Depth=-1;
Простой класс, все назначение которого — временно связать порожденные объекты в некое подобие дерева. Для чего нужен перегруженный operator() будет понятно чуть позже.
У этого класса есть наследник, в котором заложен базовый функционал записи в JSON-формате. Программист должен только переопределить функции Write***.
#define TCF_OBJECT 4 #define TCF_ARRAY 2 class TJsonTagCloser:public TTagCloser < public: void WriteTab(); void WriteInt(int); void WriteDouble(double); void WriteStr(char *); TJsonTagCloser(char *Key); >; //---------------------------------------------------------------------------- TJsonTagCloser::TJsonTagCloser(char *Key):TTagCloser() < if(Owner) < if(Owner->Count) WriteStr(","); if(Owner->Flags&TCF_ARRAY) < if(!Owner->Count) WriteTab(); > else < WriteTab(); WriteStr("\""); if(Key) WriteStr(Key); WriteStr("\":"); >Owner->Count++; > >
Функция WriteTab() введена в программу удобства гиков, любящих лазить в файлы данных «Блокнотом». Она должна записать в файл данных перевод строки и число пробелов, соответствующее глубине вложения (TTagCloser::Depth). Если бы форматирование не было нужно, то функция выродилась бы в WriteTab().
У меня в тестовом примере функции Write*** определены так:
#include void TJsonTagCloser::WriteTab()void TJsonTagCloser::WriteInt(int Value) void TJsonTagCloser::WriteDouble(double Value) void TJsonTagCloser::WriteStr(char *Value)
JSON-формат предполагает наличие в потоке данных Объектов (смахивают на СИшные структуры), Массивов (они и в Африке массивы) и просто пар «Ключ: Значение». Все это многообразие может быть перемешано и вложено друг в дружку, например в паре «Ключ: Значение» Значением может быть Массив Объектов. Для работы с этими сущностями созданы следующие классы:
class TJsonArray:public TJsonTagCloser < public: TJsonArray(char *Key); ~TJsonArray(); >; class TJsonObject:public TJsonTagCloser < public: TJsonObject(char *Key); ~TJsonObject(); >; class TJsonValue:public TJsonTagCloser < public: TJsonValue(char *Key, int Value):TJsonTagCloser(Key)TJsonValue(char *Key, double Value):TJsonTagCloser(Key) TJsonValue(char *Key, bool Value):TJsonTagCloser(Key) TJsonValue(char *Key, char *Value); >; TJsonArray::TJsonArray(char *Key):TJsonTagCloser(Key) < Flags|=TCF_ARRAY; if(Owner && (!(Owner->Flags&TCF_ARRAY) || Owner->Count>1)) WriteTab(); WriteStr("["); > TJsonArray::~TJsonArray() < WriteTab(); WriteStr("]"); >//---------------------------------------------------------------------------- TJsonObject::TJsonObject(char *Key):TJsonTagCloser(Key) < Flags|=TCF_OBJECT; if(Owner && (!(Owner->Flags&TCF_ARRAY) || Owner->Count>1)) WriteTab(); WriteStr(" <"); >TJsonObject::~TJsonObject() < WriteTab(); WriteStr(">"); > TJsonValue::TJsonValue(char *Key, char *Value):TJsonTagCloser(Key) < if(Value) < WriteStr("\""); WriteStr(Value); WriteStr("\""); >else WriteStr("null"); >
Для удобства использования библиотеки в своей программе определены макросы:
#define ARRAY(k) for(TJsonArray array(k); array();) #define OBJECT(k) for(TJsonObject object(k); object();) #define VALUE(k,v)
Вот и добрались до перегруженного operator(). Он нужен для однократного выполнения тела цикла for, то есть в первый вызов он возвращает true, а в последующие — false.
А вот так в теле программы выглядит скрипт, на котором пишется заполнение файла данных:
void main() < OBJECT("") < VALUE("Comment", "My comment"); VALUE("Count", 10); OBJECT("DiskParam") < VALUE("DB", 10.0); VALUE("DBAngle", 1.234); >VALUE("Range", true); ARRAY("Blades") < for(int i='A'; i> ARRAY("Slots") for(int i=0; i >
Как выглядит сформированный этой программой JSON-файл можно посмотреть в начале статьи. Все запятые проставлены, все скобочки закрыты когда нужно, в каждой строке нужное количество ведущих пробелов — красота!
3 способа валидации форм
Валидация формы — это проверка данных, которые ввёл пользователь. Если на вашем сайте есть форма без валидации, пользователи будут заполнять её как захотят. Кто-то пропустит важное поле, кто-то неправильно введёт телефон или номер банковской карты. В результате обрабатывать такие данные станет сложнее, да и небезопасно.
Валидация на стороне клиента
Валидация на стороне клиента — это проверка данных до отправки формы. Она помогает пользователю быстро узнать об ошибках при заполнении полей и исправить их. Вы можете проверить поля для ввода логина, пароля, почты, номера телефона и других типов данных, которые должны соответствовать определённым критериям.
Атрибуты для валидации формы
Самый простой способ проверки — добавить HTML-атрибуты полям ввода. С помощью атрибутов вы можете указать тип данных, который ожидаете в каждом поле, отметить обязательные поля, задать ограничение по длине строки или установить максимальное и минимальное значение для чисел.

Атрибут type указывает тип поля. Например, type=»email» означает, что это поле для адреса электронной почты, а type=»phone» — для номера телефона.
Атрибут required указывает, что поле обязательно для заполнения:
Атрибут pattern проверяет значение поля с помощью регулярного выражения. Например, здесь мы указываем паттерн для телефона: номер начинается с +7 , а затем идут ещё 10 цифр от нуля до девяти.
$" required>
Атрибуты minlength и maxlength указывают минимальное и максимальное количество символов, которые можно ввести в поле.
Атрибуты min и max задают минимальное и максимальное значение для полей с числами и датами.
Не пренебрегайте атрибутами, даже если используете для валидации JavaScript. Порой скрипты не загружаются на страницу, например, при слабом интернет-соединении. В таком случае именно атрибуты не позволяют пользователю ввести данные в некорректном формате.
Валидация на JavaScript
Дополнительно стоит настроить валидацию с помощью JavaScript. На JS пишутся функции, которые проверяют данные и выводят сообщение, если пользователь неправильно заполнил поле. Такие подсказки можно показывать как в момент набора текста, так и при попытке отправить форму.
Какой-то единой функции для проверки валидации не существует — вам нужно написать свои под вашу конкретную задачу. Например, простая валидация формы входа в личный кабинет может выглядеть так:
В реальных проектах валидация формы бывает сложнее, поэтому для неё могут использоваться библиотеки, например, PristineJS, Formik, Validator.js и другие.
Валидация на стороне сервера
Проверку на стороне клиента можно обойти, поэтому важно валидировать данные и на стороне сервера — то есть после отправки формы. Такая проверка надёжнее, так как не зависит от клиента и помогает точнее обнаружить ошибки в данных.
Обычно валидация выполняется на PHP, Python, Ruby, Java и других языках программирования. Этой задачей занимаются бэкендеры. При проверке они используют регулярные выражения, условные операторы и другие средства своего языка программирования. Например, в PHP можно воспользоваться встроенной функцией filter_var() .
В каждом языке свои особенности валидации. Если обобщить, то проверка может выглядеть так:
- Получаем данные от клиента через HTTP-запрос и сохраняем в переменные на сервере.
- Определяем правила валидации. Проверяем, что данные соответствуют ожидаемому формату, например, что они не пустые.
- Пишем код для валидации.
- Обрабатываем результаты валидации. Если данные не проходят проверку, возвращаем ошибку клиенту и даём инструкции по исправлению. Если данные корректны, продолжаем выполнение запроса.
- Обрабатываем введённые данные. Если валидация прошла успешно, можно сохранить их в базе данных или использовать для выполнения других действий.
При проведении валидации на стороне сервера также важно помнить о безопасности. Например, можно экранировать все входные данные, чтобы предотвратить XSS-атаки.
Валидация — это важная задача, за которую отвечают и фронтендеры, и бэкендеры. Первые должны настроить валидацию на стороне клиента. Вторые — позаботиться о проверке на стороне сервера.
Если же вы работаете над проектом в одиночку, валидация — только ваша задача. Не пренебрегайте ею, чтобы ваше веб-приложение работало без ошибок и оставалось безопасным.
Материалы по теме
- Как защитить приложение от хакеров
- Частые ошибки в HTML-коде
- Авторизация и аутентификация: в чём разница
«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.
