Попов Дмитрий
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)
print "
";

$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 под статью. На тестовой странице сниппет такой:

print "
";

$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 '
'
; print_r($result);

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

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

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

// [[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 '
'
; 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 (Гиннесс)", ] ];
Николай, привет! С выдачей таки разобрался и уперся в "тактические" вопросы. Подскажи, пожалуйста, куда копать. Код выдачи:


//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 выводишь только одно. Смотри свой вывод.
Точно!! Спасибо огромное) А то вывих мозга уже намечался)))

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