Аспектно-ориентированное программирование в PHP

Обычно, чтобы было понятнее, что такое аспектно-ориентированное программирование, приводят пример с логированием. Допустим нам нужно веси лог удалений. Причем, удалений всего и вся. Самый простой способ  это добавить вызов логирующего метода в тех местах где происходит удаление сущности, например, в методе deleteUser(). Разумеется логирование придется добавить во все подобные методы всех сущностей. Во первых это муторно, во вторых нарушает четкое предназначение класса(метод не только удаляет, но еще и записывает лог). Еще один способ этот использование паттерна наблюдателя.

АОП придумана как раз таки для реализации такой сквозной функциональности. Как это реализовать в PHP с помощью фреймворка FLOW3 читайте в статье Aspect-Oriented Programming in PHP .

В двух словах это работает так: при написании метода логирования вы даете указание в какик методах он должен вызываться. Примерно вот так:

1
2
3
4
5
6
7
8
/**
* An aspect that is executed on all methods that start with "delete".
*
* @FLOW3\Before("method(.*->delete.*())")
*/

public function logginMethod() {
// Do some logging here.
}

Ну а фреймворк уже сам позаботится о вставке вашего метода в нужные места.

 
Технологии

  • OAuth 2.0 простым и понятным языком - не свежий, но полезный пост про OAuth 2.0
  • Помните отличную презентацию про HTML5? Можно забабахать презентацию не хуже с помощью LakTEK. На первый взгляд всё просто.
  • В хроме появился новый атрибут download у тега A. Атрибут указывает на то, что ресурс указанный в ссылке нужно предложить скачать, а не пытаться открыть его в браузере
  • HTML5 Audio — The State of Play -подробный разбор: методы, атрибуты, события…вплоть до настройки Апача, для корректной отдачи аудио-файлов.

PHP

  • XDebug исполнилось 10 лет! Этому событию посвящен новый релиз 2.2.0.
  • Если вы переживаете за качество вашего php-кода, обратите внимание на инструменты и представленные на сайте The PHP Quality Assurance Toolchain
  • Mobile_Detect — облегченный класс для обнаружения мобильных устройств.

Разное

RESTful API Server – Делай все правильно(2 часть)

Это перевод статьи RESTful API Server – Doing it the right way (Part 2)

В первой части(перевод) я дал понятие основных принципов RESTful и объяснил как организовать архитектуру вашего сервера, чтобы обеспечить легкую версионность и устаревание API. В этой части я буду говорить о HATEOAS и гипермедиа, а затем покажу вам какую роль она играет в разработке нативного мобильного клиента. Но сутью этого поста будет кэширование(или скорее поддержка кэширования серверной стороной). Целевая аудитория это серверные разработчики и до некой степени iOS или разработчики мобильных приложений.

 HTTP API, REST и HATEOAS

Сейчас в мире HTTP API можно разделить на

  • Web Services
  • RPC URI Tunnelling
  • HTTP-based Type 1
  • HTTP-based Type 2
  • REST

Это очень хорошое объяснение от Jon Algermissen. К сожалению, все поставщики API говорят, что они RESTful, хотя это не так.
Что же такое RESTful сервер? Сервер который управляется гипертекстом/гипермедия является RESTful. Это означает, что разработчик/клиент должен иметь возможность открывать для себя  “другие доступные ресурсы”, из API корнего урла. Это, в действительности является наиболее серьезным препятствием для реализации интерфейсов API RESTful. Кроме того чистые RESTful сервер придерживается HATEOAS- ограничениям.

HATEOAS – Hypermedia as the Engine of Application State(гимермедиа как двигатель состояния приложения)

Два основных ограничения, которым нужно следовать при реализации HATEOAS:
1)Возвращать только гипермедиа ресурсы
Гипермедиа ресурсом является тот, кто содержит контент и управление (гиперссылки) на другие ресурсы гипермедиа.
JSON(application/json) — это не гипермендиа-ресурсы. (Опять же, есть много RESTful, HATEOAS серверов, которые обслуживают JSONs) Однако можно добавить дополнительные ключи для JSON, заставляя приложение вести себя как ресурс гипермедиа. (Для примера: ключ для связи ресурса с уменьшенной копией изображения)
2) Единая точка входа для клиентского приложения
На главной странице API, последующие «GET» конечные точки вкладывается в качестве URL-адреса (или ссылки) и последующей «POST», «PUT» или «DELETE» конечные точки вкладывается в качестве формы.
Основное преимущество соблюдения этих ограничений — это упрощение документации.

HATEOAS — это то что нужно вашему следующему API?

Жирное НЕТ
Почему же я говорю об этом? В прошлом, API писались преимущественно для потребления веб-приложениями. Обычно это XHTML-серверы, а приложения запускаются в браузере. Веб-браузер является «клиентом», похожим на мобильный (IOS / Android / Windows Phone) клиент, который может анализировать гипермедиа-ресурсы, понимать HTML формы и «знать», как представить форму пользователю. В реализации для мобильных клиентов, если ваш ресурс это RESTFul-сервер то, что отдается сервером вы не можете(по крайней мере легко) представить элементами мобильной платформы. Ни один из поставщиков платформ, Apple / Google или Microsoft не имеет встроенную поддержку преобразования формы XHTML в UIViewController (iOS) или в Intent (Android) или в страницу Silverlight (на  Windows-телефоне).
Я рекомендую предоставить конечные точки не только для GET-запросов, но и для POST/PUT и DELETE-методов. (например: /friends/add или /venue/checkin). Контроллер конечной точки может (должен) быть встроен в другие ответы(так, что бы клиент или разработчик клиента мог узнать о ней). Конечно, это противоречит REST, но это нормально. Работающие продукты — это лучше, чем придерживаться стандартов с нулевой выгодой.(Вероятно это сделает наш API  “HTTP-based Type 2 API”)

Кэширование

Давайте поговорим о кэшировании. Вы наверно думаете, что кэширование бывает преимущественно на стороне клиента (или на промежуточных прокси). Но знаете ли вы, что API-сервер придерживается соглашений, ожидаемых промежуточными кэширующими прокси?  Это в свою очередь означает, что с их помощью вы сможете балансировать нагрузку. На самом деле, кэширование описано в секции 13 HTTP-спецификации.

Art Taylor затвитил это несколько месяцев назад:

У меня есть два новых правила:

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

#Почему_так_трудно_кэшировать

Но поверьте мне, кэширование можно сделать без этих проблем. Вот два важных принципа, которым я рекомендую придерживаться:

  1. Не внедряйте пользовательские схемы кэширование на клиенте.
  2. Поймите основные принципы кэширования из спецификации HTTP 1.1 RFC. В RFC объясняется два вида моделей кэширования: модель срока действия и модель проверки.

В любом клиент/серверном приложении сервер является авторитетным источником информации. Когда вы скачиваете ресурс(страницу или ответ) с API-сервера, сервер шлет некоторые “подсказки” клиенту как следует кэшировать его. Сервер авторитетно диктует, если(и когда) выходит срок актуальности кэша. Эти “подсказки” могут слаться программно или при конфигурировании серверной стороны. Время жизни кэша обычно настраивается на сервере(ndynx.conf или подобные) и требует некоторых усилий со стороны серверного разработчика. Сервер должен сам определить когда использовать модель срока действия, а когда метод проверки.  Модель срока действия обычно используется когда сервер может уверенно догадаться как долго ресурсы будут актуальными. Иначе используется модель проверки. Позднее я покажу как запрограммировать обе модели. Когда вы поймете эти модели, я расскажу когда какую использовать.

Модель срока действия

Давайте для сначала посмотрим на самую распространенную конфигурацию кэша. Если вы конфигурируете ngynx, то вы добавляете что то похожее в ngynx.conf(Ну а для Апача это пишится в .htaccess)

location ~ \.(jpg|gif|png|ico|jpeg|css|swf)$ {
               expires 7d;
       }

ngynx переводит этот конфиг в аналог кэш заголовка HTTP. В этом случае сервер шлет заголовок “Expires” или “Cache-Control: max-age=n” для всех изображений(среди прочего) и срок действия клиентского кэша закончится через 7 дней. Это обычно означает, что не нужно запрашивать повторно ресурсы в течении 7 дней. Все основные веб-браузеры(и промежуточные прокси) уважают этот заголовок и работают как ожидается. К сожалению, подавляющее большинство опенсорсных фреймворков для работы с кэшем в iOS, содержат популярный SDWebImage, использующий контроль механизма кэширования, который удалит изображения из кэша через n дней. И это проблема. Этот фреймворк не придерживается требования модели валидации и вы дожны прибегать к хакам, если ваше приложение пользуется этим фреймворком.

Давайте я вам покажу пример, где все может пойти не так. Давайте вернемся к нашему приложению “следующий Фейсбук”. Когда ваш пользователь закачивает аватарку, он надеется, что изменения коснется всех отображений. Некоторые умные разработчики очистят кэш памяти после успешного вызова.(Это делается, чтобы каждый контроллер заново скачал ресурс с сервера). Все прошло успешно и все вьюконтроллепы отображают свежее изображение из профиля. Но все же это не решает проблему полностью. Новое изображение из профиля пользователя видимо его друзьям только последующие 7 дней. Совершенно не приемлемо. Так как это решить? Как я уже сказал, вы должны принять тот факт, что только сервер является авторитетным источником данных. Не пользуйтесь грязными трюками с истечением времени жизни кэша на клиенте.

Модель проверки

И Фейсбук и Твиттер решают проблему с истечением срока действия аватарки(после заливки новой) используя метод проверки. В методе проверки, сервер шлет уникальный идентификатор запрошенного ресурса и клиент кэширует и идентификатор и сам ресурс. В терминологии HTTP, этот уникальный идентификатор называется ETag. Когда вы повторно запросите этот же ресурс, вы должны послать этот ETag. Cервер, используя этот идентификатор, проверит изменился ли запрашиваемый ресурс(помните, что сервер является авторитарным источником). Если ресурс изменился, то он пошлет последнюю копию. Иначе, вернет заголовок “304 Not Modified”. Модель проверки требует программистских усилий как на сервере, так и на клиенте. Я разберу это в следующем разделе.

Код клиентской стороны

На самом деле на iOS, если вы используете MKNetworkKit, он делает все это для вас автоматически. Но ради разработчиков под Андроид и Виндовс я раскажу как нужно это реализовывать. Модель проверки использует ETag и HTTP заголовок Last-Modified. Реализация клиентской поддержки метода проверки проще чем реализация на стороне сервера. Если вы получили ETag вместе с ресурсом, то когда будете запрашивать его повторно, отправьте ETag в “IF-NONE-MATCH” заголовке. В качестве альтернативы, если вы получили “Last-Modified” вместе с ресурсом, то отправляйте его в “Last-Modified” заголовке следующих  запросов. Опять же сервер определяет когда нужно использовать “ETag”, а когда “Last-Modified”.

Реализация модели срока действия проста. Просто посчитайте дату окончания срока основываясь на заголовки “Expires” или “Cache-Control:max-age-n” и удалите кэшь на следующий день.

Код серверной стороны

Кэшь основанный на ETag
ETags обычно подсчитывается на сервере с использованием объекта и  алгоритма хэширования. (Большинство серверов высокого уровня используют такие языки как Java/C#/Scala, у которых есть метод хеширования объекта) Прежде чем сериализовать ответ, сервер должен вычислить хеш объекта и добавить полученное значение в ETag заголовок. Теперь, если клиент действительно послал IF-NONE-MATCH в запросе и ETag совпадает с тем, что вы вычислили, отправьте 304 Not Modified. Иначе сериализуете ваш ответ и шлете новый ETag.

Кэшь основанный на Last-Modified

Реализация Last-Modified немного сложнее. Давайте предположим, что у вас есть конечная точка, которая возвращает список друзей

http://api.mynextfacebook.com/friends/

Когда используете ETag, вы сосчитаете хеш от массива друзей. Когда вы используете Last-Modified, вы должны послать дату последней модификации этого списка. Т.к. наш ресурс это список, то эта дата может на самом деле указывать на дату, когда у пользователя в последний раз появился новый друг. Это требует от разработчика сервера хранить последнюю дату модификации списка друзей для всех пользователей. Это сложнее чем ETag, но зато здесь преимущество в огромной производительности.
Когда клиент запрашивает ресурс в первый раз, ему высылается полный список друзей. В последующих запросах клиента будет присутствовать заголовок “IF-MODIFIED-SINCE”. Ваш сервер должен быть запрограммирован так, что бы выслать список друзей, добавленных после этого времени. Псевдо-код по извлечению может быть примерно такой:

select * from friends

потом,

select * from friends where friendedDate > IF-MODIFIED-SINCE

 Если при выборке из базы возвращается нулевой результат, шлите 304 Not Modified. Если у пользователя 300 друзей, но из них только два новых, сериализуйте и отправляйте клиенту только эти две новые записи. Так экономятся огромные ресурсы.

Конечно этот псевдо-код очень упрощен. У разработчика сервера скорее всего есть еще головная боль от удаления и блокирования друзей. Сервер должен уметь отправлять клиенту подсказки, с помощью которых он мог бы знать какие друзья были добавлены, а какие удалены. Этот метод на самом деле требует дополнительных усилий на стороне сервера.

Выбор метода кэширования для ваших ресурсов.

Вот так так! Это было немного тяжеловато. Теперь я собираюсь установить некоторые основные правила, когда использовать какой тип механизма кэширования.

  1. Все статические изображения должны использовать модель срока действия.
  2. Все динамически изменяемые данные должны кэшироваться методом проверки.
  3. Если динамические данные это список, вы должны использовать метод основанный на Last-Modified(пример: друзья). Еще мудрость: следует использовать модель ETag на основе проверки(например:  /friends/firstname.lastname)
  4. Изображения и любые другие ресурсы которые могут быть обновлены пользователем(такие как аватарка) опять таки должны кэшироваться с помощью ETag метода проверки. Хоть это и изображения, но они не статичны(например не как логотип вашей компании). Кроме того вы не сможете надежно вычислить  истечение срока для такого ресурса. Другой (чуть проще в реализации, но немного хакинга) способ заключается в использовании ошибочный URL.

Ошибочный URL работает следующим образом. Когда вы шлете URL на аватарку, убедитесь в том, чтобы часть урла была динамической. Т.е. вместа такого адреса

http://images.mynextfacebook.com/person/firstname.lastname/avatar

шлите такую
http://images.mynextfacebook.com/person/firstname.lastname/avatar/<случайный хеш> 
Обеспечьте изменение случайного хеша тогда, когда пользователь обновит картинку. Теперь интерфейс API, который отправляет список друзей будет содержать изменившийся URL-адрес для друзей, которые обновили свои изображения. Изменение аватарки происходит практически мгновенно!
Если сервер и клиент придерживается уже установленных стандартов кэширования, то ваше iOS-приложение и ваш продукт будут «летать».
То, что я сделал в этом посте — это простое объяснение этих стандартов, которым не следуют подавляющее большинство разработчиков.
На этом заканчивается этот пост. В последней и заключительной части мы будем обсуждать как сообщать о ошибках, как делать правильные обработчики ошибок и  как сделать поддержку интернационализации в вашем приложении.

Рекомендую к прочтению

REST API Design Rulebook, By Mark Masse
http://shop.oreilly.com/product/0636920021575.do

 

 

Губит людей не пиво…

Как появился <blink> - забавная история от разработчика Lynx`a(ну Netscape). Парни пошли выпить пивка. Вели разговор про то, как lynx обидно уступает позиции графическим браузерам. И в шутку придумали тэг BLINK, благодаря которому бы текст немного преобразился. К утру эта фича уже была реализована(!). А потом пошло поехало и уже скоро на всех сайтах появились мигающие «Купи», «Зайди», «Посмотри». Никто не хотел этого(честно, честно), но так получилось.

Технологии

Современная веб-разработка — офигитильное описание средств разработчика в браузере Chrome. Я хоть и сижу в инспекторе целыми днями, но про некоторые вещи не знал.

Файловая система внутри браузера, вернее библиотека для её эмуляции в браузерах, без поддержки HTML5 FileSyste API. Браузеры уже больше напоминают операционные системы, чем просто средства серфинга по интернет.

Отличная библиотека visibility.js, которая позволяет узнать активна ли сейча вкладка с вашим сайтом, или пользователь переключился на другой сайт. Оченб полезная фича, например, не надо постоянно долбать сервер и просить новые данные, если сейчас вкладка с сайтом не активна. Page Visibility API и Visibility.js — хорошая статья на эту тему.

Разное

Тетрис в фав-иконке. Прикольно! Управление через стрелоски на клавиатуре.

Гид покупателя. Как купить электронику или одежду за границей и получить почтой — интересная серия статей от Эльдара Муртазина про покупки за рубежом через интернет. После прочтения можно смело залазить в инет за покупками. 

Расценки в России: Сколько стоит заказать ТЗ на веб-сайт и сделать к нему прототип?! - очень прикольный вопрос. Интересно, как бы ответил Тема? ;)

Просто электронная почта

Электронная почта очень простой инструмент, который делает то, что от него требуется и делает это очень хорошо. Но есть и такие кому это не нравится. Есть возможность использования плагинов в почтовом клиенте, для  навешивания всякой дополнительной функциональности почты(списки todo, календарь…). Идея простая — в заголовке почтового сообщения можно посылать любую информацию какую вам здумается. Если у получателя не стоит плагин для разбора информации, то пользователь увидит обычное письмо. На перовом этапе изменения протокола этого будет достаточно, чтобы испробовать изменения.

Само собой нашлись и защитники электронной почты. Email is not broken: It’s a framework, not an application — руки прочь от  электронной почты. Она реализует асинхронный протокол обмена сообщениями. Если вам чего то не хватает в протоколе, реализуйте это в почтовом клиенте, но не трогайте спецификацию самой почты.

Вот кстати, как можно пользоваться почтой http://angel.co/fluent

Технологии

Разное

  • Evolution of a Web Developer: From PHP Newbie To Python Ninja — парень разложил по пунктикам свою программистскую деятельность. В рассказе указывает на поворотные вехи в своем развитии. Пишет, не без юмора, читать интересно.
  • Интересный проект, который представляет жизненный цикл вирусного видео. Просто нажите play: e.m-bed.de/d/ (открывать лучше в Хроме). Не бойтесь, что оно само все делает )))

Сервисы

  • QArt Coder — сделай красивый QRcode. Например, вот такой:

RESTful API Server – Делай все правильно(1 часть)

Это перевод статьи RESTful API Server – Doing it the right way (Part 1)

В 2007 Стив Джобс назвал iPhone революцией в индустрии высоких технологий, изменяющий способы работы и ведения бизнеса. Сейчас, в 2012, все больше и больше сайтов предлагают нативные  клиенты для iOS и Android в качестве фронд-энд-приложений. Не все стартапы имеют финансирование для разработки приложения в добавок к основному продукту. Для увеличения скорости развития их продукта они предлагают публичный API для разработчиков, которые могут использовать его для написания приложений. Twitter, вероятно, был первой такой компанией и теперь все больше и больше компаний  последовали такой же стратегии, действительно отличным путем развития экосистемы вокруг своего продукта.

Стартапы полны преобразований. Если ваш код не может переориентироваться, вы проиграете. Взяв перерыв или еще на старте, серверный код достаточно гибок, что бы адаптироваться к потребностям бизнеса. Успешными стартапами являются не те у которых присутствует хорошая идея, а те, которые реализуют ее.  Успех стартапа зависит от успеха его продукта, пусть это iOS-приложение или его сервис или его API. За последние 3 года я работал над разнообразными iOS-приложениями(в основном для стартапов), использующие веб-сервисы и в этой статье, я попробовал собрать знания и показать вам лучшие практики, чтобы вы могли применить их при разработке RESTful API. Хороший RESTful API который не сопротивляется изменениям.

Целевая аудитория

Этот пост предназначен для читателей, имеющих средние и продвинутые знания о разработке RESTful API и имеющих простые знания о любом объектно-ориентированном(или функциональном) серверном языке, таком как Java/Ruby/Scala(примечание: я намеренно игнорирую PHP)

Структура и организация

Эта часть статьи довольно детальна: в первой части объясняются основы REST, во второй — документирование и управление версиями вашего API. Первая часть для новичков. Вторая — для профи. Я знаю, вы профи. Так что вот ссылка  к разделу о документировании API, можно перейти прямо сейчас. Возможно это то место, с которого вы начнете читать, если решите, что не нужно тратить много времени на основы.

RESTfull-ограничения

Сервер RESTful это тот, который соответствует REST-ограничениям. Вот ссылка на статью в Википедии. Не только при разработке API, которым будут пользоваться преимущественно мобильные устройства, но и при поддержке и развитии, нужно понимать три основных ограничения. Позвольте объяснить.

Безгражданство

Первое ограничение — это безгражданство. Проще говоря, RESTful-сервер ничего не должен знать о клиенте. Клиент, с другой стороны, может поддерживать состояние контекста сервера. Другими словами, вы не должны делать так, что бы сервер помнил о состоянии мобильного устройства, использующего API.

Представим, что ваш стартап это «следующий Фэйсбук». Хороший пример, того где разработчик может сделать ошибку, это предоставление интерфейса API, который позволит мобильному устройству взять последний элемент потока(говоря о фиде Фейсбука). API обычно возвращает новые элементы, которые появились после последнего считывания. Это ведь разумно, неправда ли? Вы так «оптимизируете»  передачу данных между клиентом и сервером, не так ли? И это неправильно.

Что пойдет не так в этом случае? Когда пользователь пользуется вашим сервисом с двух или трех устройств и одно устройство установило статус последнего прочтенного элемента, то другие устройства уже не смогут получить те элементы которые получило первое устройство.

Данные, возвращаемые  для конкретного вызова API, не должны зависить от вызовов которые были сделаны раннее чем этот.

Верный путь оптимизации, это передача штампа времени, когда был последний вызов API(/feed?lastFeed=20120228). Есть и другой способ, более стандартный, использование заголовка  HTTP Modified Since. Но пока это пропустим. Рассмотрим этот способ во второй части статьи.

Кешируемая и многоуровневая архитектура

Второе ограничение заключается в обеспечении уверенности клиента в том, что ответ может быть закеширован и использоваться в отдаче в какой то период времени, без генерации на сервере. Клиент может быть реальным мобильным клиентом или промежуточным прокси-сервером. Подробно объясню это позднее во второй главе этой статьи.

Клиент-серверное разделение интересов и единый интерфейс

RESTful-сервер должен абстрагироваться и скрывать как можно больше деталей реализации от клиента. Т.е. клиент не должен знать о том какая база данных используется на сервере и сколько баланщировщиков нагрузки сейчас активно или другие подобные вещи. Поддержание хорошоге разделения интересов помогает в расширении, когда продукт становится «вирусным».

Это вероятно три наиболее важных ограничения, которые вы должны помнить, когда разрабатываете RESTful-сервер.

REST-запросы и четыре HTTP-метода

  • GET
  • POST
  • PUT
  • DELETE

Кэшируемое ограничение и GET-запросы

Ключевая идея — это то, что GET-метод не изменяет состояние сервера. Это означает, что ваши запросы могут быть закешированы на любом промежуточном прокси-сервере(для сокращения нагрузки). Как разработчик сервера вы не должны подвергать изменению вашу базу данных. Это противоречит философии RESTful, второму ограничению, о котором я говорил ранее. Ваш «GET» метод даже не должен делать записи в лог и не должен сохранять время последнего обращения к сервису. Если вы вносите изменения в базу данных, то это должно всегда происходить только в методах POST/PUT.

POST или PUT

В спецификации HTTP 1.1 сказано, что PUT — идемпотент((от лат. idem — такой же и potens — сильный, то есть имеющий такую же силу). Это означает, что клиент может выполнить множество PUT-запросов к одному и тому же URI и это не должно создать/изменить дублирующие записи в базе.
Операции присваивания, являются хорошим примером идемпотентных операции.

String userId = this.request["USER_ID"];

Даже если выполнить эту операцию два или три раза, ничего вредного не произойдет.
POST же, с другой стороны, не идемпотичен. Это как оператор прибавления. Вы должны использовать POST или PUT основываясь на то, какой метод должен быть: идемпотентный или нет. Если клиент «знает» URL объекта который может быть создан, то нужно использовать метод PUT. Если клиент знает URL создателя/фабрики, то нужно использовать POST.

PUT www.example.com/post/1234

Используйте PUT, если клиент знает URI, который будет создан в результате вызова. Даже если клиент вызовет PUT -метод несколько раз, ничего вредного не произойдет и не создадутся дублирующие записи.

POST www.example.com/createpost

Используйте POST-метод, если сервер создаст уникальный ключ и вернет результат обратно клиенту. Дублирующиеся запись появятся, если позднее будет запрос с такими же параметрами.

Прочтите этот ответ на Stackoverflow, чтобы узнать больше.

DELETE

DELETE — прямолинеен. Это опять идемпотент, как и PUT, и должен использоваться для удаления записи, если она существует.

REST Responses(ответы)

Ответы вашего RESTfull-сервера могут быть в XML или JSON формате. Лично я предпочитаю JSON, потому что он проще, и размер передаваемых данных меньше, чем при использовании XML-формата. Разница может быть в несколько сотен килобайт, но используя сети 3G и непостоянное соединение мобильного устройства, эти несколько сотен килобайт могут иметь огромное значение при загрузке ответных данных.

Аутентификация

Аутентификация должна проводится по протоколу https и клиент должен отправлять пароль зашифрованный криптографическим алгоритмом. Получение sha1 хэш NSString в Objective-C является довольно прямолинейным и следующий код иллюстрирует это.

- (NSString *) sha1
{
	const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
	NSData *data = [NSData dataWithBytes:cstr length:self.length];

	uint8_t digest[CC_SHA1_DIGEST_LENGTH];

	CC_SHA1(data.bytes, data.length, digest);

	NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];

	for(int i = 0; i <; CC_SHA1_DIGEST_LENGTH; i++)
		[output appendFormat:@"%02x", digest[i]];

	return output;
}

Сервер должен сравнить зашифрованный пароль с зашифрованным паролем, сохраненным на сервере ранее. В любом случае вы не должны передавать пароль в открытом виде между клиентом и сервером. В этом правиле нет исключений. В день, когда пользователь придет и узнает, что вы храните пароли в открытом виде, будет днем смерти вашего стартапа. Потерянное доверие может уже никогда не вернуться.

Спецификация RFC 2617 говорит о двух путях авторизации с HTTP-сервером. Первый это Basic Access Authentication, второй - Digest Authentication. Для внутреннего мобильного клиента использование Basic или Digest-авторизации вполне достаточно и в большинстве серверных языков, такой механизм авторизация реализован.

Если вы планируете сделать ваш API публичным, то вам следует рассмотреть oAuth, а лучше oAuth 2.0. oAuth позволяет вашим конечным пользователям размещать контент, созданный вашим приложением, с другим сторонним поставщиком обработки ключей(логин/пароль). oAuth также позволяет пользователю полностью контролировать, что сделать публичным и какие права могут быть разрешены приложонию третьей стороной.

Facebook Graph API — это крупнейшая реализация oAuth на сегодняшний день. Используя oAuth, пользователь Фейсбуку может обмениваться фотографиями с приложением третей стороны без раскрытия персональной информации и прочих деталей(логин/пароль). А также пользователь может отменить доступ для приложения третей стороны без изменения пароля.

До сих пор я говорил о основах REST. Теперь давайте погрузимся в «мясо» статьи. В последующих разделах я поговорю о лучших практиках, которым вы должны следовать в документировании, контроле версий и устаревания вашего API.

API документация

В самой худшей документация сервера, которую разработчие может написать это та, которая содержит длинный список конечных точек API, параметры, которые необходимы и соответствующие ответы от сервера. Проблема в том, что слишком сложно делать изменения данных ответа по мере развития продукта, и это становится кошмаром. У меня есть несколько предложений как сделать документацию вашего API так, чтобы разработчик клиента мог лучше понять вас. Со временем, это вам поможет стать разработчиком лучшего сервера.

Документация

Для начала, прежде чем преступить к документированию, я бы порекомендовал  подумать о своем верхнем уровне моделей объектов. Подумайте о действиях, которые должны совершать эти объекты.  Foursquare API документация - это хороший пример для начала.  У них есть набор объектов верхнего уровня, такие как места, пользователи и т.д. Также есть действия которые могут быть выполнены над этими объектами. Как только вы узнаете объекты верхнего  уровня и действия над ними, разбор конечных точек становится простым и более четким.  Например, чтобы «добавить» новое место, вероятнее всего, нужно вызвать метод похожий на  /venues/add

Документируйте каждый объект верхнего уровня. Далее, с помощью этих объектов верхнего уровня, документируйте запросы и ответы, а не примитивно, только исходные типы данных. Вместо того, что бы писать, что возвращается три строки: первая — идентификатор, вторая — имя, третья — описание, напишите, что это API — возвращает модель места.

Документирование параметров запроса

Давайте предположим, что у вас есть API, который, для входа использует, авторизацию Фейсбука. Вызовем api /login

Request
/login
Headers
Authorization: Token XXXXX
User-Agent: MyGreatApp/1.0
Accept: application/json
Accept-Encoding: compress, gzip
Parameters
Encoding type – application/x-www-form-urlencoded
token – “Facebook Auth Token” (mandatory)
profileInfo = “json string containing public profile information from Facebook” (optional)

Здесь profileInfo это  top-level object(объект верхнего уровня). Этого достаточно, т.к. вы уже задокументировали внутреннюю структуру этого объекта. Если ваш сервер использует те же Accept, Accept-Encoding и параметры кодирования, вы можете задокументировать их отдельно, а не повторять их везде.

Документирование параметров ответа

Ответы API должны документироваться основываясь на модели объектов верхнего уровня. Цитируя тот же форсквеерсеий пример, метод  /venue/#venueid# возвращает полную модель места.

Если ваша модель окажется большой или вы захотите снизить нагрузку, рассмотрите возможность создания компактной модели. Вы можете воспользоваться этим для API, которые будут возвращать список моделей объектов. Форскверовские API поступают также. Их поиск API возвращает список «компактных мест»

Обмениваетесь идеями, документируя или сообщая другим разработчикам, что Вы возвратите, когда Вы документируете свой API, используя модели объектов. Главный вывод этого раздела — это рассмотрение документации в качестве договора между вами, сервером разработчика и клиентом разработчиков(iOS/Android/Windows Phone/др.)

Причины версионности.

До мобильных приложений, в эру приложений Веб 2.0, версионность API не была проблемой. Клиент(Javascript/AJAX front-end) и сервер разворачивались одновременно, в одно и тоже время. Потребители(ваши заказчики) всегда пользовались последним фронт-энд клиентом доступа к вашей системе. Потому как, ваша компания разрабатывала и клиент и сервер, вы имели полный контроль над тем, как использовать ваш API, и всегда изменяли клиента, если что то изменилось в API на сервере. К сожалению с нативными клиентами это не возможно. Вы можете развернуть API версии 2 и думать, что все будет хорошо, но это «разорвет» старые версии вашего приложения для iOS, даже после обновления его на АппСторе. В конченом итоге это приведет к потере клиентов. Я видел очень много айфонов, в которых, более 100 приложений, ожидают обновления. У вашего приложения есть хорошие шансы стать одним из них. Вы всегда должны быть готовы к версионности API и старению. Но поддерживать ваш API не менее 3 месяцев.

Версионность.

Развертывание серверного кода в другой каталог и используя другие URLы конечных точек автоматически не означает эффективный перенос кода.
Т.е. вместо использования http://example.com/api/v1 проложению нужно будет использовать последнею наилучшую версию 2.0 http://example.com/api/v2

Когда вы производите обновления, вы почти всегда изменяете внутреннюю структуру данных и модели объектов на вашем сервере. Это подразумевает изменения в базе данных(добавление или удаление столбцов). Чтобы внести ясность, предположим, что API вашего «следующего Фейсбука» имеет вызов /feed, который возвращает «Feed»-объект.

Сегодня, в версии 1, ваш «Feed»-объект содержит ссылку на персональную картинку(avatarURL), имя(personName) -текстовое поле(feedEntryText) и временную отметку(timeStamp) новой записи.

Позднее, во второй версии, вы добавляете возможность рекламодателям  продавать свою продукцию. Теперь ваш «Feed»-объект содержит новое поле, скажем, «sourceName», вместо «personalName». Теперь ваш «Feed»-объект, новое поле с именем «sourceName», которое очень уступает человеческому имени в интерфейсе. Т.е. приложение должно отображать «sourceName», вместо «personName». Поскольку для отображения в интерфейсе больше не требуется «personName», когда присутствует «sourceName», вы решили не посылать «personName» когда посылаете «sourceName». Разумнее посылать оба поля: «sourceName» и «personName». Но, друзья мои, в жизни это не всегда не так просто. Как разработчик, вы не можете отслеживать все изменения, которые когда-либо были сделаны для каждого объекта модели в своем классе. Это просто не эффективно и через 6 месяцев, вы почти забудите, почему что-то было добавлено код.

Оглядываясь назад, в веб 2.0, это не было вообще проблемой. Фронт-энед на ява скрипте обновлялся сразу же после изменения API. Однако, IOS приложения будут отключены в отличие от веб-приложений. Только пользователь может его обновить.

Я могу предложить очень элегантное разрешение этой ситуации.

Парадигма версионности URL

Во-первых, различайте несколько версий используемых урлов.

http://api.example.com/v1/feeds будет потребляться первой версией приложения для iOS, и
http://api.example.com/v2/feeds — второй версией приложения.

Хотя это звучит хорошо, вы не должны дублировать разрабатываемый вами код, после каждого изменения, затрагиваемого выходные данные. Я рекомендую это делать, только при больших изменениях. Для небольших изменений, рассмотрите версионность ваших моделей.

Парадигма версионности модели

Ранее я показал как документировать модели. Рассматривайте эту документацию как договорное соглашение между серверными и клиентскими разработчиками. Никогда не следует вносить изменения в модель, без изменения версии. Это значит, что в нашем предыдущем примере, должно быть две модели — Feed1 и Feed2. Feed2 имеет sourceName и выводит sourceName и при наличии sourceName удаляет personName. находится в Feed2 и выводит sourceName и при наличии sourceName удаляет personName. Feed1 ведет себя по прежнему так, как это было задокументировано.

В коде исполнение запроса будет выглядеть примерно так:

Вы должны перенести код создания экземпляра в класс фабричный метод. Код должен выглядеть примерно так:

Feed myFeedObject = Feed.createFeedObject("1.0");
myFeedObject.populateWithDBObject(FeedDao* feedDaoObject);

Где 1.0 или 2.0 определяется в в контроллере из строки UserAgent.

Добавление:
Вместо того, чтобы зависеть от номера версии в строке UserAgent, клиент должен отправить номер версии в заголовке Accept.

Поэтому вместо отправки

Accept: application/json

вы должны отправить

Accept: application/myservice.1.0+json

Таким образом, у вас есть возможность запросить другой вариант ответа на каждый объект RES-ресурса, который вы запрашиваете.
Спасибо читателям «hacker news», которые послали мне это.

Контроллер просит метод  Feed-фабрики создать нужный feed-объект, на основе входящего запроса(все запросы в UserAgent должны выглядят как AppName/1.0) и версию клиента. При такой реализации серверного кода, *любые* изменения будут простыми.  Изменяя серверную часть без нарушения существующих договоров покажется легким бризом. Просто создайте новую модель, изменив фабричный метод, который создаст новую версию модели и вы продвинетесь вперед!

С такой архитектурой модель места, для приложений 1-ой версии и 2-ой все еще могут находиться на том же сервере. Ваш контроллер будет создавать объект 1-ой версии для старых клиентов и 2-ой — для новых.

Устаревание

С парадигмой версионности модели я предположил, что устаревание вашего API упрощается. Это очень важно, когда вы сделаете ваш API публичным.
Когда вы делаете мажорные апдейты, очищайте все фабричные методы ваших моделей, основанных на бизнес-решениях.

Если, после выхода 3-й версии, вы решили больше не поддерживать iOS-приложение 1-ой версии, удалите модели и строки кода, связанные с 1-ой версией API и двигайтесь дальше.

Версионность и устаревание проходят долгий путь в обеспечении долголетия вашей компании и продукта. Они гарантируют достаточную проворность для большинства из поворотных решений. Обычно поворотным изменениям противится именно техническая команда. Такая техника должна разрешить эту проблему.

Кеширование

Следующим важным шагом для повышения производительности, на котором вы должны сосредоточиться при разработки API — это кеширование. Если вы, как и все остальные, думаете о кешировании на стороне клиента, подумайте еще раз. Во второй части я объясню, как поддерживать кэширование, основываясь на стандарты HTTP 1.1.

Обработка ошибок и интернационализация вашего API

Уведомление клиента о произошедших ошибках на сервере, так же важно как и возврат правильных данных. Об этом я расскажу в третей части.

PHP сосет!

PHP Sucks, But It Doesn’t Matter - автор статьи пинает PHP за его не неуклюжесть, не понятность, не прозрачность и т.д. Но не смотря на все недостатки признает, что существует много очень популярных сервисов, которые написаны на PHP(вордпресс, фейсбук(на момент написания статьи),..). Все дело в людях, разрабатывающих эти сервисы, говорит автор, а не в PHP.

И еще одна мега статья про то, почему PHP-отстой. PHP: a fractal of bad design - очень(местами даже очень очень) подробно разбираются всесторонние аспекты языка:переменные, языковые конструкции, функции, работа с ошибками, модули… Чувак не пожалел сил и упорства, что бы расковырять множество косяков языка. Я считаю, что это статья обязательна к изучению для всех php-программистов. Хотя бы для того, что бы знать проблемные места в PHP.

Не то в в поддержку PHP, не то в его оправдание, статья PHP Sucks! But I Like It!, ответ на предыдущую статью.

Технологии

  • Writing Browser Extensions — Comparing Firefox, Chrome and Opera - анализ различий в разработке расширений для хрома, оперы и фаерфокса.
  • Thinking Async -отличная статья о том как совершать асинхронную загрузку JS-скрипта. Рассматривается  несколько способов,  в том числе и как это сделана в гугле, твитторе и фейсбуке.
  • Что может сделать  андроид-приложение, если у него нет никаких прав. Интересный эксперимент описан  в статье   ZERO-PERMISSION ANDROID APPLICATIONS. Безправное приложение смогло получить список файлов с SD-карты. В теории, даже если приложение сможет получить какую то информацию, оно не сможет передать эти данные в интернет, т.к. мы не дадим ему такого права. Но это лишь в теории, потому как приложению, в любом случае, разрешено открывать любую ссылку в браузере, а через GET можно передать много чего.
  • Программисты мельчают. Повсеместно использование различных фреймворков, готовый библиотек и модулей привело к снижению уроню программистов. Andy Firth в своей статье  The demise of the low level Programmer составил список(постоянно дополняемый) тек вещей, которые должен знать программист пишущий код на низком уровне. Много полезных ссылок.

Разное

Страница 1 из 20123451020...Последняя »