Skip to content

Graphql - wprowadzenie#60

Open
Qziem wants to merge 14 commits intomasterfrom
graphql
Open

Graphql - wprowadzenie#60
Qziem wants to merge 14 commits intomasterfrom
graphql

Conversation

@Qziem
Copy link
Copy Markdown
Owner

@Qziem Qziem commented Apr 9, 2019

Zrobiłem endpoint api graphqlowego pod adresem .../api/graphql
Jest tam narazie tylko jeden węzeł: users - służy do pobierania userów do rankingu.
Po stronie fe przerobiłem właśnie pobieranie ludzików do rankingu aby korzystać z tego węzła (zamiast z restowego: /users. Restowego serwisu nie usunąłem bo Stats z niego korzysta - oczywiście tam też będzie można przerobić aby korzystało z graphqlowego węzła - ale to może w następnych kejsach).

To jest narazie pierwszy krok - w którym tylko pobieram dane. W innych kejsach w miarę przerabiania aplikacji trzeba będzie ogarnąć głównie dwie rzeczy:

  • walidację, - czyli żeby be generował odpowiednie błędy i aby fe je odpowiednio obsługiwał
  • mutacje - czyli zapis w bazie, czyli np. update punków po wpisaniu wyniku

@@ -0,0 +1,19 @@
open Js.Promise;

module Make = (Config: ReasonApolloTypes.Config) => {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ten moduł w końcu mi się nie przydał - służy do puszczania requestów graphqlowych bez używania komponentu.
Ale może się w przyszłości okazać przydatny dlatego go narazie nie skasowałem

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"bez używania komponentu"? Co to dokładnie oznacza i jaka jest różnica pomiędzy jednym a drugim?
Mimo wszystko trzeba też się głębiej zastanowić, czy w przyszłości się z tego pliku na pewno skorzysta. Bo tak minie parę miesięcy, a ten plik nadal nie zostanie użyty :P.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reaon-apollo dostarcza komponent który na zamontowanie sam pobiera dane. Później można wymusić na nim refetch - zorobiłem wyżej za pomocą tego refetchUsersList - i w zasadzie tyle on potrafi. A czasem mogą być sytuacje że można trzeba jakoś bardziej customowo pobierać dane - np. nie na zamontowanie ale na jakąś akcję. Albo, jeśli chcielibyśmy trzymać dane w stanie komponentu, to wtedy właśnie można użyć tego. To pozwala ręcznie strzelać do be i to coś zwraca promisę. Narazie bym zostawił do momentu zakończenia przepisywania na gql, jeśli po tym będzie niepotrzebny to będzei można wywalić

@Qziem
Copy link
Copy Markdown
Owner Author

Qziem commented Apr 9, 2019

Oczywiście domergowanie tego oznacza że teraz czeka nas znowu krucjata przerabiająca cały BE - oczywiście nie muszę ja wszystkiego robić jeśli chcecie poznać graphqla. Ale jeśli nie ma zapału i chęci na graphqla (mi się pewnie samemu całości nie będzie chciało przerabiać) nie muszę tego mergować i możeby pozostać przy REST. Jak chceta !

@jazithedev
Copy link
Copy Markdown
Collaborator

Ja tam jak najbardziej mogę się wkręcić, bo potrzebuję dowiedzieć się o wiele więcej o GraphQL. Nie mniej, może to trochę potrwać :/.
BTW. "Na razie" pisze się osobno :P.

@jazithedev
Copy link
Copy Markdown
Collaborator

Restowego serwisu nie usunąłem bo Stats z niego korzysta - oczywiście tam też będzie można przerobić aby korzystało z graphqlowego węzła - ale to może w następnych kejsach

To według mnie można dodać adnotację @deprecated do tego serwisu REST.

use GraphQLElo\Resolvers\UsersResolver;
use GraphQLElo\Types\UserType;

class GraphQLCtrl {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nie stosuje się (raczej) dwóch dużych liter obok siebie w środku nazwy klasy. Zmniejsza czytelność. Może po prostu GqlCtrl?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zmieniłem na GraphqlCtrl

$rawInput = $request->getBody();
$input = json_decode($rawInput, true);
$query = $input['query'];
$variableValues = isset($input['variables']) ? $input['variables'] : null;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tutaj można zmienić tą linijkę na:

$variableValues = $input['variables'] ?? null;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zmienione

return $response->withJson($output);
}

private function getQueryFields() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uzupełnić typowanie :array

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poprawione

use Model\Entity\User;
use Model\Repository\UserRepository;

class UsersResolver {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zakładam, że resolvery służą do przetworzenia parametrów Requesta i na ich podstawie zwrócenia odpowiednich danych? Czy tutaj w jakiś sposób czasem te parametry nie powinny być przekazywane? Chodzi mi o to, że np. czy kod ['rating' => 'DESC', 'code' => 'ASC'] nie powinien czasem być jakoś przekazywany jako parametr mówiący o tym według czego ma być sortowanie?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tak, możnaby zrobić jakiś input typ który by tym sterował i wtedy możnaby tym sterować z FE, ale narazie to jest wprowadzenie graphqlea - narazie bym zostawł w przyszłości jak będzie potrzeba będzie można to oczywiście zmienić

'fields' => [
'userNid' => [
'type' => Type::nonNull(Type::int()),
'resolve' => function (User $user) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tego dowiedziałem się od nowego PhpStorma. Jak zrobić static function zamiast samego function, to będzie to bardziej optymalne :).

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zmienione

@@ -0,0 +1,6 @@
let inMemoryCache = ApolloInMemoryCache.createInMemoryCache();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Czy nie powinniśmy nazwać tego pliku jakoś inaczej? Np. GqlClient, albo ApiClient (lub podobne)? W przyszłości, jak dojdzie jakikolwiek inny "Client", to będzie problem.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zmieniłem na ApiClient

}
</div>,
<GetUsersQuery
notifyOnNetworkStatusChange=true variables=usersQuery##variables>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variables=usersQuery##variables
Cóż to za konstrukcja?

notifyOnNetworkStatusChange
Cóż to za parametr?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. variables=usersQuery##variables -
    Jeśli chodzi Ci o pytanie co to jest ## to to jest poprostu pobranie elementu z obiektu. usersQuery to obiekt Js.t i z niego pobiera się parametry właśnie w taki sposób.
    A ogólnie to jest to przekazanie parametrów do zapytania graphqlowego. To wziąłem dokładnie z dokumentacji reason-apollo: https://github.com/apollographql/reason-apollo

  2. notifyOnNetworkStatusChange to już jest mniej oczywiste. Generalnie ten komponent zwraca dane i domyślnie obsługuje tylko pokazanie loading gdy pobiera dane za pierwszym razem. Dzięki temu parametrowi, przy obieraniu danych mamy parametr networkStatus z którego można wyciągnąć czy dane pobierane są ponownie - żeby pokazać loading.

ResponseDecoder.MakeWithWarningsOrContent(GameResponseContentDecoder);

let onSuccess = (containterSend, send, json) => {
let onSuccess = (refreshUsers, send, json) => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nazwa dla tego na pewno lepsza, ale jakoś "refresh" mi tu też nie pasuje :D. Ja bym przerobił na "reloadUsersList".

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W sumie spoko, zmieniłem

...{
({result, refetch, networkStatus}) => {
let refreshUsers = refreshUsersWithRefetch(refetch);
let isRefeching = networkStatus == Some(4);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trzeba by wyjaśnić nieco co oznacza Some(4).

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To się właśnie wiąże troche z powyższym pytaniem. Akurat Some(4) oznacza że dane pobierają się ponownie - tak mają w dokumentacji react-apollo. Wyniosłem to do stałej
Niewiem czy to co pisałem wyżej i tutaj jest zrozumiałe jak coś mogę potłumaczyć na żywo.


let onSuccess = (send, json) =>
json |> DecodeUsers.users |> (users => send(SetUsersToState(users)));
let refreshUsersWithRefetch = (refetch, ()) => refetch(None)->ignore;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wyjaśnisz mi, proszę, co oznacza refetch(None)->ignore ?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refetch to funkcja dostarczona przez reason-apollo która ponownie wysyła request o pobranie danych.
Ona właśnie powoduje że wysyła się request i wtedy ten komponent wygenerowany z reason-apollo (GetUsersQuery) sam się odświży - i to chce osiągnąć. Ale ta funkcja dodaktowo zwraca promise, jeśli ktoś chciałby potem coś jeszcze robić. Ja nie chce i po to jest ten ignore - bo funkcja refreshUsersWithRefetch powinna zwrócić unita, a bez użycia ignore by zwróciła promise. Czyli w skrócie ignore to funkcja która bierze coś tam i zwraca unita.

use GraphQLElo\Resolvers\UsersResolver;
use GraphQLElo\Types\UserType;

class GraphQLCtrl {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zmieniłem na GraphqlCtrl

$rawInput = $request->getBody();
$input = json_decode($rawInput, true);
$query = $input['query'];
$variableValues = isset($input['variables']) ? $input['variables'] : null;
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zmienione

return $response->withJson($output);
}

private function getQueryFields() {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poprawione

use Model\Entity\User;
use Model\Repository\UserRepository;

class UsersResolver {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tak, możnaby zrobić jakiś input typ który by tym sterował i wtedy możnaby tym sterować z FE, ale narazie to jest wprowadzenie graphqlea - narazie bym zostawł w przyszłości jak będzie potrzeba będzie można to oczywiście zmienić

'fields' => [
'userNid' => [
'type' => Type::nonNull(Type::int()),
'resolve' => function (User $user) {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zmienione

let component = ReasonReact.statelessComponent("RankAndStats");

let component = ReasonReact.reducerComponent("RankAndStats");
module GetUsers = [%graphql
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nawiązując do pytania o ppx - to właśnie tutaj to jest użyte - dzięki tamtemu w bsconfig można tutaj zrobić takie zapytanie graphqlowe o takiej składni

}
</div>,
<GetUsersQuery
notifyOnNetworkStatusChange=true variables=usersQuery##variables>
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. variables=usersQuery##variables -
    Jeśli chodzi Ci o pytanie co to jest ## to to jest poprostu pobranie elementu z obiektu. usersQuery to obiekt Js.t i z niego pobiera się parametry właśnie w taki sposób.
    A ogólnie to jest to przekazanie parametrów do zapytania graphqlowego. To wziąłem dokładnie z dokumentacji reason-apollo: https://github.com/apollographql/reason-apollo

  2. notifyOnNetworkStatusChange to już jest mniej oczywiste. Generalnie ten komponent zwraca dane i domyślnie obsługuje tylko pokazanie loading gdy pobiera dane za pierwszym razem. Dzięki temu parametrowi, przy obieraniu danych mamy parametr networkStatus z którego można wyciągnąć czy dane pobierane są ponownie - żeby pokazać loading.

...{
({result, refetch, networkStatus}) => {
let refreshUsers = refreshUsersWithRefetch(refetch);
let isRefeching = networkStatus == Some(4);
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To się właśnie wiąże troche z powyższym pytaniem. Akurat Some(4) oznacza że dane pobierają się ponownie - tak mają w dokumentacji react-apollo. Wyniosłem to do stałej
Niewiem czy to co pisałem wyżej i tutaj jest zrozumiałe jak coś mogę potłumaczyć na żywo.

@@ -0,0 +1,6 @@
let inMemoryCache = ApolloInMemoryCache.createInMemoryCache();
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zmieniłem na ApiClient

@@ -0,0 +1,19 @@
open Js.Promise;

module Make = (Config: ReasonApolloTypes.Config) => {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reaon-apollo dostarcza komponent który na zamontowanie sam pobiera dane. Później można wymusić na nim refetch - zorobiłem wyżej za pomocą tego refetchUsersList - i w zasadzie tyle on potrafi. A czasem mogą być sytuacje że można trzeba jakoś bardziej customowo pobierać dane - np. nie na zamontowanie ale na jakąś akcję. Albo, jeśli chcielibyśmy trzymać dane w stanie komponentu, to wtedy właśnie można użyć tego. To pozwala ręcznie strzelać do be i to coś zwraca promisę. Narazie bym zostawił do momentu zakończenia przepisywania na gql, jeśli po tym będzie niepotrzebny to będzei można wywalić

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants