Проверяем текст в Главреде

Мы уже рас­ска­зы­ва­ли, что такое API. Теперь исполь­зу­ем эту тех­но­ло­гию в наших про­ек­тах: возь­мём ранее сде­лан­ный тек­сто­вый редак­тор с ней­ро­ор­фо­кор­рек­то­ром и научим его про­ве­рять текст в сер­ви­се «Главред» — у него откры­тый API, кото­рый неслож­но при­кру­тить.

Логика работы

Как и боль­шин­ство про­грам­ми­стов, мы будем исполь­зо­вать преды­ду­щие нара­бот­ки и гото­вые реше­ния — так про­ще и быст­рее. Для про­ек­та нам пона­до­бит­ся:

Сей­час редак­тор рабо­та­ет так: нажи­ма­е­те про­бел или энтер — текст сра­зу отправ­ля­ет­ся на про­вер­ку. Это не самый раци­о­наль­ный путь, когда у нас будет рабо­тать несколь­ко сер­ви­сов про­вер­ки одно­вре­мен­но, поэто­му сде­ла­ем для это­го отдель­ную кноп­ку. Нажи­ма­ешь — текст уле­та­ет на сер­вер Яндек­са и при­ле­та­ет уже в исправ­лен­ном виде.

То же самое сде­ла­ем и для Главре­да — отдель­ную кноп­ку, кото­рая отпра­вит наш текст на про­вер­ку в сер­вис.

Что­бы не услож­нять про­ект, раз­объ­ём его на две части: сего­дня сде­ла­ем толь­ко под­свет­ку в Главре­де, а во вто­рой части доба­вим оформ­ле­ние, что­бы выгля­де­ло кра­си­во и нагляд­но.

Переделываем страницу

Для рабо­ты нам пона­до­бит­ся исход­ный код тек­сто­во­го редак­то­ра с ней­рон­кой. Для нача­ла изме­ним код на HTML-странице:

Исходный код страницы

<!DOCTYPE html>
<html>
<!-- служебная часть -->

<head>
  <!-- заголовок страницы -->
  <title>Орфокорректор</title>
  <!-- настраиваем служебную информацию для браузеров -->
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style type="text/css">
    /* общие параметры страницы*/
    body {
      text-align: center;
      margin: 10;
      font-family: Verdana, Arial, sans-serif;
      font-size: 16px;
    }

    /* заголовок */
    h1 {
      font-size: 48px;
      text-align: center;
    }

    /* поле ввода */
    .text {
      min-height: 300px;
      min-width: 500px;
      border: solid;
      border-width: 1px;
      text-align: left;
      -webkit-box-shadow: 6px 10px 9px 0px rgba(0, 0, 0, 0.75);
      -moz-box-shadow: 6px 10px 9px 0px rgba(0, 0, 0, 0.75);
      box-shadow: 6px 10px 9px 0px rgba(0, 0, 0, 0.75);
    }
  </style>
  <!-- закрываем служебную часть страницы -->
</head>

<body>
  <!-- подключаем jQuery -->
  <script type="text/javascript" src="http://yastatic.net/jquery/2.1.3/jquery.min.js"></script>
  <!-- подключаем наш скрипт проверки орфографии -->
  <script type="text/javascript" src="script.js"></script>
  <!-- заголовок на странице -->
  <h1>Орфокорректор</h1>
  <!-- пояснительный текст -->
  <p>Напишите что угодно с ошибками. Страница сама всё исправит.</p>
  <!-- поле ввода текста -->
  <textarea id="text_field" class="text"></textarea>
</body>
<!-- конец всей страницы -->

</html>

Так как нам нуж­но будет выде­лять сло­ва, как в Главре­де, то заме­ним <textarea>, кото­рый не уме­ет фор­ма­ти­ро­вать текст, на <div contenteditable="true">, кото­рый фор­ма­ти­ро­вать уме­ет. Из-за это­го у нас поме­ня­ет­ся внеш­ний вид поля вво­да — он рас­тя­нет­ся на всю шири­ну экра­на — но это мы испра­вим в дру­гой раз.

Что­бы выде­лять сло­ва, кото­рые нам при­шлёт Главред, мы будем исполь­зо­вать тег <span> — в него удоб­но заво­ра­чи­вать отдель­ные эле­мен­ты тек­ста и поме­чать их любым обра­зом. Сего­дня выде­лим их про­стой светло-голубой под­свет­кой, а позд­нее части заме­ним на кра­си­вое под­чёр­ки­ва­ние. Для это­го доба­вим опи­са­ние ново­го сти­ля в соот­вет­ству­ю­щий раз­дел на стра­ни­це:

/* слова, которые нашёл Главред */ span{      background-color: lightblue; }

Для того что­бы исполь­зо­вать API Главре­да, его нуж­но под­клю­чить. В нашем слу­чае это скрипт на JavaScript, поэто­му под­клю­ча­ем его на стра­ни­це, как и любой дру­гой внеш­ний скрипт:

<!-- подключаем API Главреда -->   <script type="text/javascript" src="https://api.glvrd.ru/v1/glvrd.js"></script>

Послед­нее, что нам оста­лось сде­лать, — доба­вить кноп­ки управ­ле­ния. Их будет три: исправ­ле­ние орфо­гра­фии, отправ­ка в Главред и отме­на обра­бот­ки Главре­дом. Послед­няя кноп­ка нуж­на для того, что­бы отме­нить теку­щую про­вер­ку, если обра­бот­ка идёт слиш­ком дол­го или вам про­вер­ка уже ока­за­лась не нуж­на:

<!-- добавляем отступ -->   <br>   <!-- добавляем кнопки на страницу -->   <button id="spell_b" onclick="spell()">Исправить</button>   <button id="glvrd_b" onclick="glvrdz()">Главред</button>   <button id="abort_b" onclick="abort_glvrdz()" disabled>Отменить проверку Главреда</button>
Готовый код страницы

<!DOCTYPE html>
<html>
<!-- служебная часть -->
<head>
  <!-- заголовок страницы -->
  <title>Орфокорректор</title>
  <!-- настраиваем служебную информацию для браузеров -->
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style type="text/css">
    /* общие параметры страницы*/
    body {
      text-align: center;
      margin: 10;
      font-family: Verdana, Arial, sans-serif;
      font-size: 16px;
    }
    /* заголовок */
    h1 {
      font-size: 48px;
      text-align: center;
    }
    /* поле ввода */
    .text {
      min-height: 300px;
      min-width: 500px;
      border: solid;
      border-width: 1px;
      text-align: left;
      -webkit-box-shadow: 6px 10px 9px 0px rgba(0, 0, 0, 0.75);
      -moz-box-shadow: 6px 10px 9px 0px rgba(0, 0, 0, 0.75);
      box-shadow: 6px 10px 9px 0px rgba(0, 0, 0, 0.75);
    }
    /* слова, которые нашёл Главред */
    span {
      background-color: lightblue;
    }
  </style>
  <!-- закрываем служебную часть страницы -->
</head>
<body>
  <!-- подключаем jQuery -->
  <script type="text/javascript" src="http://yastatic.net/jquery/2.1.3/jquery.min.js"></script>
  <!-- подключаем наш скрипт проверки орфографии -->
  <script type="text/javascript" src="script.js"></script>
  <!-- подключаем API Главреда -->
  <script type="text/javascript" src="https://api.glvrd.ru/v1/glvrd.js"></script>
  <!-- заголовок на странице -->
  <h1>Орфокорректор</h1>
  <!-- пояснительный текст -->
  <p>Напишите что угодно с ошибками. Страница сама всё исправит.</p>
  <!-- поле ввода текста -->
  <div id="text_field" contenteditable="true" class="text"></div>
  <!-- добавляем отступ -->
  <br>
  <!-- добавляем кнопки на страницу -->
  <button id="spell_b" onclick="spell()">Исправить</button>
  <button id="glvrd_b" onclick="glvrdz()">Главред</button>
  <button id="abort_b" onclick="abort_glvrdz()" disabled>Отменить проверку Главреда</button>
</body>
<!-- конец всей страницы -->
</html>

По нажа­тию на кноп­ки будут вызы­вать­ся соот­вет­ству­ю­щие функ­ции, кото­рых у нас пока нет. Что­бы это испра­вить, все изме­не­ния будем вно­сить в .js-файл из ори­ги­наль­но­го про­ек­та:

Исходный код скрипта орфокорректора

$(document).ready(function () {
  // эта функция получает наш результат проверки орфографии
  fix_spell = function (data) {
    data.forEach(function (elem) {
      // она находит наше поле ввода по имени
      $('#text_field').val(
        // и меняет всё на правильные слова без ошибок
        $('#text_field').val().replace(
          elem['word'],
          elem['s'][0] || elem['word']
        )
      );
    });
  }
});
// обработчик нажатия на клавиши
document.addEventListener('keydown', function (e) {
  // если нажат пробел или энтер
  if ((e.keyCode == 32) || (e.keyCode == 13)) {
    // делим текст на строки
    var lines = $('#text_field').val().replace(/\r\n|\n\r|\n|\r/g, "\n").split("\n");
    // и обрабатываем каждую строчку:
    lines.forEach(function (line) {
      if (line.length) {
        // отправляем строку со словами на проверку в Спеллер, результат сразу отправляется в функцию fix_spell
        $.getScript('http://speller.yandex.net/services/spellservice.json/checkText?text=' + line + '&callback=fix_spell');
      }
    });
  }
});

Проверка орфографии по кнопке

Нам боль­ше не нуж­но обра­ба­ты­вать каж­дое нажа­тие про­бе­ла или энте­ра, поэто­му нам боль­ше не нужен обра­бот­чик собы­тий по нажа­тию. Вме­сто это­го нам нуж­но заве­сти новую функ­цию spell() — имен­но она она вызы­ва­ет­ся по нажа­тию на кноп­ку «Испра­вить».

Что­бы не было тако­го, что пока текст на про­вер­ке, мы отправ­ля­ем его в Главред, давай­те отклю­чать обе эти кноп­ки на вре­мя про­вер­ки орфо­гра­фии. Как толь­ко про­вер­ка закон­чит­ся — кноп­ки сно­ва будут рабо­тать. Это помо­жет нам избе­жать ситу­а­ции, когда на про­вер­ку отпра­вят­ся раз­ные вер­сии тек­ста.

Рань­ше мы обра­ща­лись к тек­сту, напи­сан­но­му поль­зо­ва­те­лем, через вот такое закли­на­ние:

$('#text_field').val()

Это рабо­та­ло, пото­му что чело­век писал в поле вида Textarea, у кото­ро­го есть зна­че­ние value, в кото­ром и хра­нил­ся текст.

Теперь у нас вме­сто тек­сто­вой обла­сти (textarea) про­сто блок на стра­ни­це — тег <div>. Поль­зо­ва­тель будет писать в него, а мы будем доста­вать из него напи­сан­ное. Для это­го нуж­но такое закли­на­ние:

document.getElementById('text_field').innerHTML 

Теперь захо­дим в уже напи­сан­ную нами функ­цию fix_spell() и меня­ем обра­ще­ние к тек­сту.

Вот что у нас полу­чит­ся после всех исправ­ле­ний:

// эта функция исправляет в тексте слова с ошибками
function fix_spell(data) {
  data.forEach(function (elem) {
    // берём наш текст и последовательно заменяем все слова с ошибками на правильные
    document.getElementById('text_field').innerHTML = document.getElementById('text_field').innerHTML.replace(
      elem['word'],
      elem['s'][0] || elem['word']
    );
  });
}
// обрабатываем нажатие на кнопку «Исправить»
function spell() {
  // делаем кнопки недоступными для нажатия
  document.getElementById('glvrd_b').disabled = true;
  document.getElementById('spell_b').disabled = true;
  // получаем текст из окна редактора
  var lines = document.getElementById('text_field').innerHTML.replace(/\r\n|\n\r|\n|\r/g, "\n").split("\n");
  // и обрабатываем его
  lines.forEach(function (line) {
    // если есть хоть один символ —
    if (line.length) {
      // отправляем строку со словами на проверку в Спеллер, результат сразу отправляется в функцию fix_spell
      $.getScript('http://speller.yandex.net/services/spellservice.json/checkText?text=' + line + '&callback=fix_spell');
    }
  });
  // снова делаем кнопки доступными для нажатия
  document.getElementById('spell_b').disabled = false;
  document.getElementById('glvrd_b').disabled = false;
}

API Главреда — подготовка

На офи­ци­аль­ной стра­ни­це API про­ек­та мож­но най­ти гото­вый при­мер — возь­мём его за осно­ву и немно­го пере­де­ла­ем под наши зада­чи.

Сна­ча­ла доба­вим блок про­вер­ки доступ­но­сти сер­ви­са — если Главред недо­сту­пен, мы сра­зу полу­чим сооб­ще­ние об этом. Про­сто ско­пи­ру­ем из при­ме­ра и вста­вим в нача­ло наше­го .js-файла:

// блок проверки работоспособности сервера Главреда if(!glvrd) { alert('Главред не загружен'); } else { glvrd.getStatus(function(result) {      if(result.status == 'ok') {          InitButtons();      } else {          alert('Главред выключен: ' + result.message);      } }) }

Там же нахо­дим коман­ду отме­ны про­вер­ки и встав­ля­ем его в функ­цию abort_glvrdz(), кото­рая вызы­ва­ет­ся при нажа­тии на кноп­ку «Отме­нить про­вер­ку Главре­да»:

// отмена проверки на сервере function abort_glvrdz(){      glvrd.abortProofreading(); }

API Главреда — отправка и расшифровка результатов

Теперь пора­бо­та­ем с самим API и резуль­та­том, кото­рый мы полу­чим в ответ. Если вни­ма­тель­но почи­тать код и опи­са­ние функ­ций, то мож­но заме­тить, что:

  • мы долж­ны сна­ча­ла отпра­вить наш текст на сер­вер с помо­щью мето­да glvrd.proofread();
  • в ответ мы полу­чим объ­ект result, в кото­ром будет всё, что сер­вис дума­ет по пово­ду наше­го тек­ста;
  • сре­ди содер­жи­мо­го result есть свой­ство fragments — это мас­сив, в кото­ром содер­жат­ся най­ден­ные сло­ва, кото­рые нам нуж­но выде­лить;
  • у каж­до­го эле­мен­та тако­го мас­си­ва есть свои свой­ства: нача­ло стоп-слова (с како­го сим­во­ла по поряд­ку оно начи­на­ет­ся), конец и под­сказ­ка. Под­сказ­ка нам пока не нуж­на, а вот нача­ло и конец при­го­дят­ся.

Полу­ча­ет­ся, что нам извест­ны коор­ди­на­ты нача­ла и кон­ца най­ден­ных слов, на кото­рые сер­вис обра­тил вни­ма­ние, а зна­чит, мы можем в этих местах поста­вить тег <span>..</span>. Мы в этот тег завер­нём все най­ден­ные стоп-слова, а так как мы всё дела­ем на стра­ни­це в эле­мен­те <div>, то бра­у­зер сам выде­лит эти сло­ва так, как напи­са­но у нас в сти­лях.

Так как мы можем узнать раз­мер мас­си­ва fragments, то сде­ла­ем это в цик­ле — будем нахо­дить каж­дое сло­во и отправ­лять его в функ­цию, кото­рая доба­вит нуж­ные теги до и после сло­ва. В каче­стве пара­мет­ров функ­ции мы будем пере­да­вать коор­ди­на­ты нача­ла и кон­ца слов.

Здесь есть один тон­кий момент: когда мы доба­вим в стро­ку наши теги <span>..</span>, то у нас изме­нит­ся дли­на стро­ки и собьют­ся все коор­ди­на­ты осталь­ных стоп-слов. Что­бы это­го не про­изо­шло, мы доба­вим пере­мен­ную сме­ще­ния — в ней будем хра­нить то коли­че­ство сим­во­лов, на сколь­ко мы уве­ли­чи­ли дли­ну стро­ки. Напри­мер, когда мы доба­вим тег <span>, то этим мы уве­ли­чим дли­ну стро­ки на 6 сим­во­лов, а когда закры­ва­ю­щий тег — на 7 сим­во­лов.

Что­бы при каж­дой отправ­ке мы полу­ча­ли новый резуль­тат, на кото­рый не вли­я­ет под­свет­ка ста­рых слов, мы будем очи­щать наш текст от тега<span>..</span> при каж­дой отправ­ке. Это поз­во­лит нам каж­дый раз полу­чать новую и пра­виль­ную раз­мет­ку тек­ста.

С кноп­ка­ми на стра­ни­це посту­па­ем так же, как и при про­вер­ке на ошиб­ки — на вре­мя про­вер­ки дела­ем их неак­тив­ны­ми, а кноп­ку отме­ны про­вер­ки в Главре­де, наобо­рот, актив­ной.

// тут будем хранить количество символов, которое мы добавляем в строку нашими тегами <span>
var rep = 0;
// переменные для обработки строк
var str = '';
var temp_s = '';
var temp_s_2 = '';
// подсвечиваем слова, которые нашёл Главред
function mark(s, st, en) {
  // разбиваем текст по переменным на до и после начала очередного слова из Главреда
  temp_s = s.substring(0, st + rep);
  temp_s_2 = s.substring(st + rep, s.lenght);
  // так как добавляем <span>, то увеличиваем общую длину строки на 6 символов
  rep += 6;
  // добавляем открывающий тег и соединяем всё в одну строку
  s = temp_s + '<span>' + temp_s_2;
  // делаем то же самое, чтобы добаавить закрываюший тег </span> после нужного слова
  temp_s = s.substring(0, en + rep);
  temp_s_2 = s.substring(en + rep, s.lenght);
  s = temp_s + '</span>' + temp_s_2;
  rep += 7;
  // результат помещаем в исходную строку для следующей итерации
  str = s;
}
// отправка текста в Главред и обработка результатов
function glvrdz() {
  // запрещаем все кнопки, кроме остановки проверки в Главреде
  document.getElementById('spell_b').disabled = true;
  document.getElementById('glvrd_b').disabled = true;
  document.getElementById('abort_b').disabled = false;
  // получаем текст из окна редактора
  var text = document.getElementById('text_field').innerHTML;
  // убираем теги разметки, которые мы сами добавили
  text = text.replace(/\B<span>\B/gi, '');
  text = text.replace(/\B<\/span>\B/gi, '');
  // помещаем очищенный текст назад в окно редактора
  document.getElementById('text_field').innerHTML = text;
  // обнуляем переменную сдвига количества символов
  rep = 0;
  // используем API — отправляем текст на проверку на сервер Главреда
  glvrd.proofread(text, function (result) {
    // если всё в порядке
    if (result.status == 'ok') {
      // получаем содержимое окна редактора
      str = document.getElementById('text_field').innerHTML;
      // цикл выполнится столько раз, сколько слов нужно пометить
      for (var i = 0; i < result.fragments.length; i++) {
        // помечаем каждое найденное слово, зная его начало и конец
        mark(str, result.fragments[i].start, result.fragments[i].end);// }
      }
      // выводим результат в окно редактора
      document.getElementById('text_field').innerHTML = str;
      // если сервер не отвечает — выведем ошибку
    } else {
      alert(result.message);
    }
  });
  // снова делаем все кнопки доступными для нажатия, кроме кнопки отмены
  document.getElementById('spell_b').disabled = false;
  document.getElementById('glvrd_b').disabled = false;
  document.getElementById('abort_b').disabled = true;
}
Готовый код скрипта

// блок проверки работоспособности сервера Главреда
if (!glvrd) {
  alert('Главред не загружен');
} else {
  glvrd.getStatus(function (result) {
    if (result.status == 'ok') {
      InitButtons();
    } else {
      alert('Главред выключен: ' + result.message);
    }
  })
}
// эта функция исправляет в тексте слова с ошибками
function fix_spell(data) {
  data.forEach(function (elem) {
    // берём наш текст и последовательно заменяем все слова с ошибками на правильные
    document.getElementById('text_field').innerHTML = document.getElementById('text_field').innerHTML.replace(
      elem['word'],
      elem['s'][0] || elem['word']
    );
  });
}
// обрабатываем нажатие на кнопку «Исправить»
function spell() {
  // делаем кнопки недоступными для нажатия
  document.getElementById('glvrd_b').disabled = true;
  document.getElementById('spell_b').disabled = true;
  // получаем текст из окна редактора
  var lines = document.getElementById('text_field').innerHTML.replace(/\r\n|\n\r|\n|\r/g, "\n").split("\n");
  // и обрабатываем его
  lines.forEach(function (line) {
    // если есть хоть один символ —
    if (line.length) {
      // отправляем строку со словами на проверку в Спеллер, результат сразу отправляется в функцию fix_spell
      $.getScript('http://speller.yandex.net/services/spellservice.json/checkText?text=' + line + '&callback=fix_spell');
    }
  });
  // снова делаем кнопки доступными для нажатия
  document.getElementById('spell_b').disabled = false;
  document.getElementById('glvrd_b').disabled = false;
}
// тут будем хранить количество символов, которое мы добавляем в строку нашими тегами <span>
var rep = 0;
// переменные для обработки строк
var str = '';
var temp_s = '';
var temp_s_2 = '';
// подсвечиваем слова, которые нашёл Главред
function mark(s, st, en) {
  // разбиваем текст по переменным на до и после начала очередного слова из Главреда
  temp_s = s.substring(0, st + rep);
  temp_s_2 = s.substring(st + rep, s.lenght);
  // так как добавляем <span>, то увеличиваем общую длину строки на 6 символов
  rep += 6;
  // добавляем открывающий тег и соединяем всё в одну строку
  s = temp_s + '<span>' + temp_s_2;
  // делаем то же самое, чтобы добаавить закрываюший тег </span> после нужного слова
  temp_s = s.substring(0, en + rep);
  temp_s_2 = s.substring(en + rep, s.lenght);
  s = temp_s + '</span>' + temp_s_2;
  rep += 7;
  // результат помещаем в исходную строку для следующей итерации
  str = s;
}
// отправка текста в Главред и обработка результатов
function glvrdz() {
  // запрещаем все кнопки, кроме остановки проверки в Главреде
  document.getElementById('spell_b').disabled = true;
  document.getElementById('glvrd_b').disabled = true;
  document.getElementById('abort_b').disabled = false;
  // получаем текст из окна редактора
  var text = document.getElementById('text_field').innerHTML;
  // убираем теги разметки, которые мы сами добавили
  text = text.replace(/\B<span>\B/gi, '');
  text = text.replace(/\B<\/span>\B/gi, '');
  // помещаем очищенный текст назад в окно редактора
  document.getElementById('text_field').innerHTML = text;
  // обнуляем переменную сдвига количества символов
  rep = 0;
  // используем API — отправляем текст на проверку на сервер Главреда
  glvrd.proofread(text, function (result) {
    // если всё в порядке
    if (result.status == 'ok') {
      // получаем содержимое окна редактора
      str = document.getElementById('text_field').innerHTML;
      // цикл выполнится столько раз, сколько слов нужно пометить
      for (var i = 0; i < result.fragments.length; i++) {
        // помечаем каждое найденное слово, зная его начало и конец
        mark(str, result.fragments[i].start, result.fragments[i].end);// }
      }
      // выводим результат в окно редактора
      document.getElementById('text_field').innerHTML = str;
      // если сервер не отвечает — выведем ошибку
    } else {
      alert(result.message);
    }
  });
  // снова делаем все кнопки доступными для нажатия, кроме кнопки отмены
  document.getElementById('spell_b').disabled = false;
  document.getElementById('glvrd_b').disabled = false;
  document.getElementById('abort_b').disabled = true;
}
// отмена проверки на сервере
function abort_glvrdz() {
  glvrd.abortProofreading();
}

Попро­буй­те теперь собрать этот про­ект само­му или про­те­сти­руй­те его на нашем сер­ве­ре. Срав­ним резуль­тат с ори­ги­на­лом:

Вот так выгля­дит текст, кото­рый про­ве­рил насто­я­щий Главред. Кро­ме стоп-слов он про­ве­ря­ет чита­е­мость и удоб­ство чте­ния.
А вот, что мы полу­чи­ли с API. Отли­чие в том, что на момент напи­са­ния этой ста­тьи досту­пен толь­ко ста­рый API, где есть толь­ко про­вер­ка на стоп-слова.

Что дальше

Наш при­мер хоть и пока­зы­ва­ет, как мож­но исполь­зо­вать API для сво­их про­ек­тов, но выгля­дит при этом очень нека­зи­сто:

  • пло­хие отсту­пы от кра­ёв экра­на
  • под­свет­ка тек­ста вме­сто под­чёр­ки­ва­ния
  • нет под­ска­зок
  • нет ссы­лок на пра­ви­ла хоро­ше­го тек­ста
  • нет оцен­ки

Всё это мы испра­вим в сле­ду­ю­щей ите­ра­ции, а пока попро­буй­те сде­лать это сами.

API — это бэкенд
А как стать бэкен­дом, рас­ска­жут в Прак­ти­ку­ме. Пер­вые 20 часов — бес­плат­но.