More Kitsu GraphQL API cleanup, resolves #33
All checks were successful
timw4mail/HummingBirdAnimeClient/pipeline/pr-master This commit looks good

This commit is contained in:
Timothy Warren 2020-10-21 17:59:43 -04:00
parent 155f44a424
commit d2a3b8ad37
11 changed files with 96 additions and 515 deletions

View File

@ -33,6 +33,12 @@ use Psr\Log\LoggerAwareTrait;
abstract class APIRequestBuilder { abstract class APIRequestBuilder {
use LoggerAwareTrait; use LoggerAwareTrait;
/**
* Where to look for GraphQL request files
* @var string
*/
protected string $filePath = __DIR__;
/** /**
* Url prefix for making url requests * Url prefix for making url requests
* @var string * @var string
@ -294,6 +300,74 @@ abstract class APIRequestBuilder {
return $this; return $this;
} }
/**
* Create a GraphQL query and return the Request object
*
* @param string $name
* @param array $variables
* @return Request
*/
public function queryRequest(string $name, array $variables = []): Request
{
$file = "{$this->filePath}/Queries/{$name}.graphql";
if ( ! file_exists($file))
{
throw new LogicException('GraphQL query file does not exist.');
}
$query = file_get_contents($file);
$body = [
'query' => $query
];
if ( ! empty($variables))
{
$body['variables'] = [];
foreach($variables as $key => $val)
{
$body['variables'][$key] = $val;
}
}
return $this->setUpRequest('POST', $this->baseUrl, [
'body' => $body,
]);
}
/**
* Create a GraphQL mutation request, and return the Request object
*
* @param string $name
* @param array $variables
* @return Request
* @throws Throwable
*/
public function mutateRequest (string $name, array $variables = []): Request
{
$file = "{$this->filePath}/Mutations/{$name}.graphql";
if ( ! file_exists($file))
{
throw new LogicException('GraphQL mutation file does not exist.');
}
$query = file_get_contents($file);
$body = [
'query' => $query
];
if (!empty($variables)) {
$body['variables'] = [];
foreach ($variables as $key => $val)
{
$body['variables'][$key] = $val;
}
}
return $this->setUpRequest('POST', $this->baseUrl, [
'body' => $body,
]);
}
/** /**
* Create the full request url * Create the full request url
* *

View File

@ -1,159 +0,0 @@
query ($id: Int) {
Media(type: ANIME, idMal:$id) {
id
idMal
isAdult
season
title {
romaji
english
native
userPreferred
}
description(asHtml: true)
duration
format
status
chapters
volumes
genres
synonyms
countryOfOrigin
source
startDate {
year
month
day
}
endDate {
year
month
day
}
trailer {
id
site
}
coverImage {
large
medium
}
bannerImage
tags {
id
name
description
category
isGeneralSpoiler
isMediaSpoiler
isAdult
}
characters {
edges {
role
voiceActors {
id
name {
first
last
native
}
language
image {
large
medium
}
description(asHtml: true)
siteUrl
}
node {
id
name {
first
last
native
}
image {
large
medium
}
description
siteUrl
}
}
pageInfo {
total
perPage
currentPage
lastPage
hasNextPage
}
}
staff {
edges {
role
node {
id
name {
first
last
native
}
language
image {
large
medium
}
description(asHtml: true)
siteUrl
}
}
pageInfo {
total
perPage
currentPage
lastPage
hasNextPage
}
}
studios {
edges {
isMain
node {
name
siteUrl
}
}
pageInfo {
total
perPage
currentPage
lastPage
hasNextPage
}
}
externalLinks {
id
url
site
}
mediaListEntry {
id
userId
status
score
progress
progressVolumes
repeat
private
notes
}
streamingEpisodes {
title
thumbnail
url
site
}
siteUrl
}
}

View File

@ -1,9 +0,0 @@
query ($id: Int, $type: MediaType) {
Media (idMal: $id, type: $type) {
mediaListEntry {
id
userId
mediaId
}
}
}

View File

@ -1,101 +0,0 @@
query ($id: Int){
Media(type: MANGA, id: $id) {
id
idMal
isAdult
season
title {
romaji
english
native
userPreferred
}
description(asHtml:true)
duration
format
status
chapters
volumes
genres
synonyms
countryOfOrigin
source
startDate {
year
month
day
}
endDate {
year
month
day
}
trailer {
id
site
}
coverImage {
large
medium
}
bannerImage
tags {
id
name
description
category
isGeneralSpoiler
isMediaSpoiler
isAdult
}
characters {
edges {
id
}
nodes {
id
name {
first
last
native
}
image {
large
medium
}
description
siteUrl
}
pageInfo {
total
perPage
currentPage
lastPage
hasNextPage
}
}
externalLinks {
id
url
site
}
mediaListEntry {
id
userId
status
score
progress
progressVolumes
repeat
private
notes
}
streamingEpisodes {
title
thumbnail
url
site
}
siteUrl
}
}

View File

@ -1,5 +0,0 @@
query ($id: Int) {
Media (type: ANIME, malId: $id) {
id
}
}

View File

@ -1,56 +0,0 @@
query ($name: String) {
MediaListCollection(userName: $name, type: ANIME) {
lists {
entries {
id
mediaId
score
progress
repeat
private
notes
status
media {
id
idMal
title {
romaji
english
native
userPreferred
}
type
format
status
episodes
season
genres
synonyms
countryOfOrigin
source
trailer {
id
}
coverImage {
large
medium
}
bannerImage
tags {
id
}
externalLinks {
id
}
mediaListEntry {
id
}
}
user {
id
}
}
}
}
}

View File

@ -1,56 +0,0 @@
query ($name: String) {
MediaListCollection(userName: $name, type: MANGA) {
lists {
entries {
id
mediaId
score
progress
progressVolumes
repeat
private
notes
status
media {
id
idMal
title {
romaji
english
native
userPreferred
}
type
format
status
chapters
volumes
genres
synonyms
countryOfOrigin
source
trailer {
id
}
coverImage {
large
medium
}
bannerImage
tags {
id
}
externalLinks {
id
}
mediaListEntry {
id
}
}
user {
id
}
}
}
}
}

View File

@ -30,6 +30,8 @@ use const Aviat\AnimeClient\USER_AGENT;
use Aviat\AnimeClient\API\APIRequestBuilder; use Aviat\AnimeClient\API\APIRequestBuilder;
use LogicException;
final class RequestBuilder extends APIRequestBuilder { final class RequestBuilder extends APIRequestBuilder {
use ContainerAware; use ContainerAware;

View File

@ -172,10 +172,9 @@ final class Model {
/** /**
* Get the userid for a username from Kitsu * Get the userid for a username from Kitsu
* *
* @param string $username * @param string|null $username
* @return string * @return string
* @throws InvalidArgumentException * @throws \Psr\SimpleCache\InvalidArgumentException
* @throws Throwable
*/ */
public function getUserIdByUsername(string $username = NULL): string public function getUserIdByUsername(string $username = NULL): string
{ {
@ -185,15 +184,11 @@ final class Model {
} }
return $this->getCached(K::AUTH_USER_ID_KEY, function(string $username) { return $this->getCached(K::AUTH_USER_ID_KEY, function(string $username) {
$data = $this->requestBuilder->getRequest('users', [ $data = $this->requestBuilder->runQuery('GetUserId', [
'query' => [ 'slug' => $username
'filter' => [
'name' => $username
]
]
]); ]);
return $data['data'][0]['id'] ?? NULL; return $data['data']['findProfileBySlug']['id'] ?? NULL;
}, [$username]); }, [$username]);
} }

View File

@ -0,0 +1,6 @@
query ($slug: String!) {
findProfileBySlug(slug: $slug) {
id
slug
}
}

View File

@ -43,7 +43,13 @@ final class RequestBuilder extends APIRequestBuilder {
* The base url for api requests * The base url for api requests
* @var string $base_url * @var string $base_url
*/ */
protected string $baseUrl = K::JSON_API_ENDPOINT; protected string $baseUrl = K::GRAPHQL_ENDPOINT;
/**
* Where to look for GraphQL request files
* @var string
*/
protected string $filePath = __DIR__;
/** /**
* HTTP headers to send with every request * HTTP headers to send with every request
@ -123,92 +129,6 @@ final class RequestBuilder extends APIRequestBuilder {
return $request->getFullRequest(); return $request->getFullRequest();
} }
/**
* Remove some boilerplate for get requests
*
* @param mixed ...$args
* @throws Throwable
* @return array
*/
public function getRequest(...$args): array
{
return $this->request('GET', ...$args);
}
/**
* Remove some boilerplate for patch requests
*
* @param mixed ...$args
* @throws Throwable
* @return array
*/
public function patchRequest(...$args): array
{
return $this->request('PATCH', ...$args);
}
/**
* Remove some boilerplate for post requests
*
* @param mixed ...$args
* @throws Throwable
* @return array
*/
public function postRequest(...$args): array
{
$logger = $this->container->getLogger('kitsu-request');
$response = $this->getResponse('POST', ...$args);
$validResponseCodes = [200, 201];
if ( ! in_array($response->getStatus(), $validResponseCodes, TRUE))
{
$logger->warning('Non 2xx response for POST api call', $response->getBody());
}
return JSON::decode(wait($response->getBody()->buffer()), TRUE);
}
/**
* Remove some boilerplate for delete requests
*
* @param mixed ...$args
* @throws Throwable
* @return bool
*/
public function deleteRequest(...$args): bool
{
$response = $this->getResponse('DELETE', ...$args);
return ($response->getStatus() === 204);
}
public function queryRequest(string $name, array $variables = []): Request
{
$file = __DIR__ . "/Queries/{$name}.graphql";
if ( ! file_exists($file))
{
throw new LogicException('GraphQL query file does not exist.');
}
$query = file_get_contents($file);
$body = [
'query' => $query
];
if ( ! empty($variables))
{
$body['variables'] = [];
foreach($variables as $key => $val)
{
$body['variables'][$key] = $val;
}
}
return $this->setUpRequest('POST', K::GRAPHQL_ENDPOINT, [
'body' => $body,
]);
}
/** /**
* Run a GraphQL API query * Run a GraphQL API query
* *
@ -232,38 +152,8 @@ final class RequestBuilder extends APIRequestBuilder {
} }
/** /**
* @param string $name * Run a GraphQL mutation
* @param array $variables *
* @return Request
* @throws Throwable
*/
public function mutateRequest (string $name, array $variables = []): Request
{
$file = __DIR__ . "/Mutations/{$name}.graphql";
if ( ! file_exists($file))
{
throw new LogicException('GraphQL mutation file does not exist.');
}
$query = file_get_contents($file);
$body = [
'query' => $query
];
if (!empty($variables)) {
$body['variables'] = [];
foreach ($variables as $key => $val)
{
$body['variables'][$key] = $val;
}
}
return $this->setUpRequest('POST', K::GRAPHQL_ENDPOINT, [
'body' => $body,
]);
}
/**
* @param string $name * @param string $name
* @param array $variables * @param array $variables
* @return array * @return array