Попов Дмитрий
28 мар. 2019 г., 10:45

API запросы к pivkarta.ru

Николай, привет! Не подскажешь, как правильно обращаться к пивкарте, да и вообще к сайтам на prisma-cms, по API с другого сайта? Если правильно понимаю, то стучаться надо сюда https://pivkarta.ru/api/ , но что обязательно нужно в параметрах указать?
Думаю, что тема будет интересна не только мне:)
Дима, привет!
Здесь все как и с чистым GraphQL. Можно гуглить, к примеру, по запросу "graphql request example". Или вот прямая ссылка на оффдоку: https://graphql.org/learn/serving-over-http/
По сути это стандартный ajax-запрос (в примеру, через fetch) с передачей GraphQL-запроса в теле ajax-запроса с получением ответа в формате json.
Спасибо! Я тогда как разберусь - сюда закину что получится)
Проблема в следующем: тестово обращаюсь https://pivkarta.ru/api/?query={beers{name}}, но если вбить в адресную, то показывает http://joxi.ru/8An0bwVczjjabm
То есть в строке не прописывается api/. Не сталкивался?

И соответственно в modx пытаюсь постучать - выдает ошибку

$client = $modx->getService('rest.modRestCurlClient'); $result = $client->request('https://pivkarta.ru/api/?query={beers{name}}', '/', 'GET', $params); $result = json_decode($result, true); print_r($result);

Дима, как я говорил, надо именно POST-запросы слать. GET-это возвращает HTML самого API-интерфейса. Более того, слать надо с заголовками json. Вот рабочий пример (выполняется через MODX-console)
<?php print "<pre>"; $query = ' query users ( $first: Int = 3 $orderBy: UserOrderByInput = createdAt_DESC $where: UserWhereInput $withPlaces: Boolean = false ){ users( first: $first orderBy: $orderBy where: $where ){ ...user Places( first: 3 ) @include(if: $withPlaces) { id name } } } fragment user on User{ id user_id username fullname email } '; $params = [ "query" => $query, "variables" => [ "first" => 1, "orderBy" => "fullname_ASC", "withPlaces" => true, "where" => [ "Places_some" => [] ], ], ]; $client = $modx->getService('rest.modRestCurlClient'); $result = $client->request('https://pivkarta.ru', '/api/', 'POST', $params, [ "contentType" => "json", ]); // print_r($result); $result = json_decode($result, true); print_r($result);
Обрати внимание, я в запрос прописал параметры $first и $orderBy со значениями по умолчанию. Теперь эти параметры можно передавать в запросе (см. variables).
Я еще улучшил по ходовой запрос, добавив для примера конструкцию @include(if: $withPlaces). Если передать параметр withPlaces = true, то будут получены еще и данные заведений пользователя. Если нет, то соответственно нет. А where в моем примере запрашивает только тех пользователей, которые создали хоть одно заведение.
Супер! Спасибо) Закину запросы и даю ссыль на то, что получится)
Разбираюсь с запросами, но общее направление ясно:) Сейчас сделал вывод данных о заведении и ассортименту пива https://goldpivo.ru/testovaya.html Сколько-то страница повисит, в чуть позже уже нормальный пример будет. На эту страницу планирую вывести все заведения, в которых есть разливной Guinness под статью. На тестовой странице сниппет такой:

<?php print "<pre>"; $query = ' query { places ( where : {name: "Grace O’Malley"} ) { name address place_id url_name image beers { id Beer { name image } } } } '; $params = [ "query" => $query, ]; $client = $modx->getService('rest.modRestCurlClient'); $result = $client->request('https://pivkarta.ru', '/api/', 'POST', $params, [ "contentType" => "json", ]); // print_r($result); $result = json_decode($result, true); $name = $result['data']['places'][0]['name']; $address = $result['data']['places'][0]['address']; $place_img = $result['data']['place'][0]['place_id'].$result['data']['places'][0]['image']; foreach($result['data']['places'][0]['beers'] as $res) { $beers .= ' <div class="col-12"> <img class="mx-auto d-block" src="https://pivkarta.ru/images/resized/thumb/'.$res['Beer']['image'].'" /> <h3>'.$res['Beer']['name'].'</h3> </div> '; } $output=' <div class="row"> <div class="col-4"> <img class="mx-auto d-block" src="https://pivkarta.ru/images/resized/thumb/'.$place_img.'" /> </div> <div class="col-8"> <h2>'.$name.'</h2> <p>'.$address.'</p> </div> <hr/> '.$beers.' </div> '; return $output; echo '<hr/>'; print_r($result);

Сейчас ты не спрашиваешь, а хвастаешься? :)
Не, нечем: сайт завалил:)))
Восстанавливаю.

А выложил - для информации.
Стало понятно, что поля заведения "Город" не хватает: как думаешь, имеет смысл добавить простое текстовое в карточку или не стоит?
Нет, не стоит. Потому что там завязка с геоданными. Это надо будет по-другому обыгрывать. Я потом придумаю как лучше это сделать.
На замену "потерянной" страницы с примером: ссылка

Код сниппета:

<?php // [[places_beer? &beername=`Guinness Draught (Гиннесс)`]] $query = ' query { beers ( where : {name: "'.$beername.'"} ) { places ( orderBy: price_ASC first: 12 ) { price Place{ name address place_id url_name image } } } } '; $params = [ "query" => $query, ]; $client = $modx->getService('rest.modRestCurlClient'); $result = $client->request('https://pivkarta.ru', '/api/', 'POST', $params, [ "contentType" => "json", ]); $result = json_decode($result, true); foreach($result['data']['beers'][0]['places'] as $res) { $beers .= ' <a href="https://pivkarta.ru/place/'.$res['Place']['place_id'].'/'.$res['Place']['url_name'].'" class="col-6 col-sm-4 col-md-3 col-lg-2 text-center" target="_blank" style="line-height:1;"> <img class="mx-auto d-block" src="https://pivkarta.ru/images/resized/thumb/'.$res['Place']['image'].'"/> <b>'.$res['Place']['name'].'</b><br/> '.$res['Place']['address'].'<br/> Цена: <big>'.$res['price'].' руб</big> </a> '; } $output=' <div class="row"> <div class="col-12"> <h3>В каких заведениях есть пиво '.$beername.'</h3> </div> '.$beers.' </div> '; return $output; echo '<hr/>'; print_r($result);

Дима, здесь все хорошо, только переделай where : {name: "'.$beername.'"} на ($where: BeerWhereInput) where: $where. А то ты ограничен в поиске только по имени. А так сможешь передавать "where" => ["name" => "someName"] и не только.

... А не, не все хорошо. Что-то я и не сразу заметил, что ты вставил name: "'.$beername.'" текстовой переменной. Так совсем не надо делать. Посмотри мой пример выше. Должно быть просто name: $beername, а $beername объявлена выше в перечислении параметров запроса как $beername: String, то есть твой запрос должен выглядеть так:
query beers($beername: String) { beers(where: { name: $beername }) { places( orderBy: price_ASC, first: 12 ) { price Place { name address place_id url_name image } } } }
А с правильным определением $where вот так:
query beers($where: BeerWhereInput) { beers(where: $where) { places( orderBy: price_ASC, first: 12 ) { price Place { name address place_id url_name image } } } }
И несмотря на развернутое объяснение... понимания нет( Код выдает результат, но от "от балды", без привязки к конкретному пиву.
И сразу возник еще вопрос, как отсечь заведения, в которых пиво есть, а цены - нет? Так не прокатит: "where" => ["name" => "Guinness Draught (Гиннесс)", "price:!=" => null ] ?


$query = ' query beers($where: BeerWhereInput) { beers(where: $where) { places( orderBy: price_ASC, first: 12 ) { price Place { name address place_id url_name image } } } } '; $params = [ "query" => $query, "where" => [ "name" => "Guinness Draught (Гиннесс)", ] ];
Николай, привет! С выдачей таки разобрался и уперся в "тактические" вопросы. Подскажи, пожалуйста, куда копать. Код выдачи:


<?php //print "<pre>"; $query = ' query beers($where: BeerWhereInput) { beers(where: $where) { places( orderBy: price_ASC, first: 24 ) { price Place { name address place_id url_name image } } } } '; $params = [ "query" => $query, "variables" => [ "where" => [ "name" => $beername ] ], ];
В выдаче есть заведения с ценами и без (price = null), и вот выбрать только те, у которых нет цены получается, а обратного не выходит (вывести только те заведения, у которых есть цена на нужное пиво). У меня такое ощущение, что решение какое-то настолько тривиальное, что о нем и не пишет никто ничего...
И встал вопрос передачи массива параметра в запрос, например передать несколько названий пива?
Дима, привет!

1. Не придумывай параметры запроса сам. Заходи в API и смотри документацию. Нет запроса типа price:!= (как в модексе), но есть price_not, price_gt и price_gte. http://joxi.ru/Vm6a53Mt43k1kr

2. Твой запрос будет примерно так выглядеть:
query beers { beers( where: { name_in: [ "Spaten", "Paulaner Hefe-weissbier", ], places_some:{ price_gt: 0 } } ) { id name places( orderBy: price_ASC, first: 24 where: { price_gt: 0 } ) { price Place { name address place_id url_name image } } } }
Но смотри, тут сразу два условия прописано, потому что выборка идет пива, но цены указаны в связке пиво-заведение, поэтому по первому условию мы находим пиво, у которых цена имеется хоть в одном заведении, но могут быть записи, где цены нет (в одном цена указана, а в другом, это же пиво, нет). Вторым условием мы получаем только те заведения, в которых указана цена для этого пива.
Если указать не places_some, а places_every, то он найдет пиво, у которого во всех заведениях указана цена, и можешь часть выборки потерять.
Николай, спасибо огромное! Вообще не туда смотрел!
Николай, приветствую! Прошу волшебного пинка в нужную сторону:


$params = [ "query" => $query, "variables" => [ "where" => [ "name_in" => array("Lager Hell Ayinger (Айингер Лагер Хелль) бутылка","Lager Hell Ayinger (Айингер Лагер Хелль) разливное") ] ], ]; print_r($params); $client = $modx->getService('rest.modRestCurlClient'); $result = $client->request('https://pivkarta.ru', '/api/', 'POST', $params, [ "contentType" => "json", ]);
Не могу найти правильное решение, как 2 пива запихать в запрос.
Дима, я что-то не очень понимаю твой вопрос "Не могу найти правильное решение, как 2 пива запихать в запрос.". Что ты имеешь ввиду? По виду у тебя правильный запрос на получение двух видов пива. Где что не так?
Возвращает только по одному: по последнему


По первому пиву точно есть 3 заведения и они не пересекаются, то есть теоретически должно выдать 5 позиций.


Сам запрос:

$query = ' query beers($where: BeerWhereInput) { beers(where: $where) { places( orderBy: price_ASC, first: 24 where: { price_gt: 0 } ) { price Place { name address place_id url_name image lng lat } } } } ';

Нет, он тебе возвращает два. http://joxi.ru/l2ZLnYdHzNaKjr
Это ты уже на уровне php выводишь только одно. Смотри свой вывод.
Точно!! Спасибо огромное) А то вывих мозга уже намечался)))

Добавить комментарий