Чуть больше недели назад я писал про чтение данных о контактах Google через Google API. Сегодня я расскажу о том как вносить изменения в сведения о контакте. В данной части работы с API от нас требуется не только обеспечить добавление или внесение изменений в какие-либо сведения о контакте, но, также и обеспечить целостность данных.
Для того, чтобы внести изменения в информацию о каком-либо контакте в GMail нам необходимо, как минимум:
1. Знать ETag изменяемой записи и правильно его расположить в запросе
2. Знать адрес ссылки (узел Link) на который необходимо отправить PUT-запрос
3. Обеспечить наличие в XML-документе необходимых узлов.
Кстати, эти же пункты необходимо соблюдать и при добавлении нового контакта. Рассмотрим всё по порядку.
1. Работа с ETag.
Вообще, работа с Google API мне напоминает некое подобие конструктора лего — есть куча деталей, которые можно расположить в определенном порядке, чтобы получить в результате игрушку. Только в нашем случае, мы должны получить запись в адресной книге. Как и деталь в конструкторе ETag может располагаться в разных частях запроса:
1. Непосредственно в XML-документе. При этом Etag включается в документа как атрибут gd:etag корневого узла entry.
2. В заголовках запроса PUT к серверу. В этом случае Etag должен быть расположен в заголовке If-Match.
При расположении ETag в атрибутах XML необходимо учесть следующее обстоятельство: ETag содержит символы ««» и в документе они должны выглядеть также, т.е. не должны заменяться на &qout и т.д. Поэтому, на мой взгляд, более безопасно и просто читать и записывать ETag следующим образом: при чтении данных искать атрибут gd:etag и сохранять его значение в переменной, а при отправке данных — включать ETag в заголовки. Так нам не придётся лишний раз следить за тем, чтобы ETag отправился правильно.
2. Ссылка для редактирования контакта
Про узлы link я уже писал не раз, поэтому подробно останавливаться на данно вопросе не будем. Скажу только , что для изменения текстовой информации нам необходимо найти узел с атрибутом rel=»edit».
3. Формируем запрос, содержащий минимальный набор данных.
Я немного поэкспериментировал со своей адресной книгой GMail и определил тот минимум данных, который необходимо записать в XML-документ, чтобы сервер не вернул ошибку. Итак, наш документ должен содержать:
1. Все пространства имен (в атрибутах узла entry), а именно:
xmlns=»http://www.w3.org/2005/Atom»
xmlns:gd=»http://schemas.google.com/g/2005″
xmlns:gContact=»http://schemas.google.com/contact/2008″
2. Узел ID со значением, определенным при чтении данных о контакте
3. Узлы link со следующими атрибутами rel: edit,http://schemas.google.com/contacts/2008/rel#photo, self
4. Как минимум один узел gContact:groupMembershipInfo с атрибутом rel содержащим ссылку на системных группу «Все контакты»
Ну и хотя бы какой-то узел, содержащий видимую информацию контакта, например адрес e-mail или блога.
Вот тот минимум, который сервер Google принимает безоговорочно.
Для примера приведу небольшой листинг процедуры отправки данных в Google. Пример основан на работе с классом, который я рассматривал здесь.
procedure TContact.UpdateInfo; var Doc: TNativeXml; I: Integer; url:string; begin Doc:=TNativeXml.Create; //создаем новый документ Doc.EncodingString:='utf-8'; Doc.CreateName('entry');//добавляем корневой узел {добавляем пространства имен} for i := 0 to High(clNameSpaces) do Doc.Root.WriteAttributeString(contactNameSpaces[i, 0], contactNameSpaces[i, 1]); Doc.Root.NodeNew('id').ValueAsString:=Fid;//добавляем id for I := 0 to Self.FLinks.Count - 1 do //добавляем все ссылки begin if LowerCase(Self.FLinks[i].Rel)='edit' then url:=Self.FLinks[i].Href; Self.FLinks[i].AddToXML(Doc.Root); end; for I := 0 to Self.FEmails.Count - 1 do //добавляем адреса почты Self.FEmails[i].AddToXML(Doc.Root); for I := 0 to GroupMemberships.Count - 1 do //добавляем членство в группах GroupMemberships[i].AddToXML(Doc.Root); with THTTPSend.Create do //отправка данных begin Headers.Add('GData-Version: 3.0.'); Headers.Add('Authorization: GoogleLogin auth=' + Self.FOwner.FAuth); MimeType := 'application/atom+xml'; Headers.Add('If-Match: '+Self.Etag); Doc.SaveToStream(Document); if HTTPMethod('PUT',url) then begin //сохраняем ответный - внем может содержаться описание ошибки Document.SaveToFile('response.xml'); end else ShowMessage(IntToStr(ResultCode)) end; end;
Здесь в процедуре я использовал NativeXML для формирования документа и Synapse для отправки данных на сервер.
И напоследок несколько замечаний по работе с контактами:
1. Для того, чтобы обеспечивать сохранность данных о контакте gmail Вы обязаны включать в отправляемый XML-документ все данные, которые были ранее получены. Ислючением могут быть узлы update (дата обновления контакта) и category (категория элемента entry). Все остальные данные — постовые адреса, телефоны, почта и т.д. и т.п. должны включаться в запрос иначе при обновлении все не объявленные данные будут удалены.
2. Иногда брэндмауэр может блокировать PUT-запрос. Если вдруг вы столкнулись с такой проблемой, то достаточно включить в заголовки запись X-HTTP-Method-Override: PUT и отправлять данные POST-запросом.