Zasoby
ZasobyNajlepsze praktyki w GraphQL

Najlepsze praktyki w GraphQL

GraphQL jest wystarczająco dojrzały i obecny na rynku wystarczająco długo, by społeczność opublikowała wiele artykułów dotyczących najlepszych praktyk. Przewodniki te obejmują praktycznie wszystkie aspekty GraphQL, w tym projektowanie schema, konwencje nazewnictwa, obsługę bezpieczeństwa i dostarczanie sensownych błędów, między innymi.

Oto kilka najbardziej wartościowych przewodników na temat najlepszych praktyk w GraphQL.

Najlepsze praktyki na graphql.org

Oficjalna strona GraphQL oferuje ogólne wprowadzenie do najlepszych praktyk w GraphQL.

Te zagadnienia dotyczą głównie kwestii wysokiego poziomu, takich jak:

Gdzie warstwa GraphQL jest umieszczona w architekturze

Rekomendacje Lee Byrona

Niedługo po udostępnieniu GraphQL światu, twórca GraphQL Lee Byron opublikował artykuł Lessons From 4 Years of GraphQL, opisując, jak konceptualnie powinniśmy podchodzić do pracy z GraphQL:

  • Nazewnictwo ma znaczenie
  • Myśl w kategoriach grafów, nie endpointów
  • Opisuj dane, nie widok
  • GraphQL to lekki interfejs
  • Ukrywaj szczegóły implementacji

Szczegółowo opisuje też kilka cennych zasad i lekcji, które wyciągnął z używania GraphQL w Facebooku.

GraphQL Rules

GraphQL Rules to strona specjalnie poświęcona prezentowaniu codziennych najlepszych praktyk pracy z GraphQL, dotyczących głównie projektowania schema GraphQL.

Ten zasób jest bardzo szczegółowy. Kompiluje informacje z kilku wyjątkowych źródeł (takich jak artykuł Designing GraphQL Mutations i samouczek Shopify Designing a GraphQL API) i przedstawia je wszystkie razem w zwięzły sposób.

Opisane reguły obejmują:

  1. Reguły nazewnictwa
    • Używaj camelCase dla pól i argumentów GraphQL.
    • Używaj UpperCamelCase dla typów GraphQL.
    • Używaj CAPITALIZED_WITH_UNDERSCORES do nazewnictwa typów ENUM.
  2. Reguły typów
    • Używaj niestandardowych typów skalarnych, jeśli chcesz zadeklarować pola lub argumenty o określonej wartości semantycznej.
    • Używaj Enum dla pól zawierających określony zestaw wartości.
  3. Reguły pól (Output)
    • Używaj semantycznych nazw dla pól i unikaj ujawniania szczegółów implementacji w nazwach pól.
    • Używaj pola Non-Null, jeśli pole zawsze będzie miało daną wartość.
    • Grupuj jak najwięcej powiązanych pól w niestandardowy typ obiektowy.
  4. Reguły argumentów (Input)
    • Grupuj powiązane argumenty w nowy input-type.
    • Używaj ścisłych typów skalarnych dla argumentów, np. DateTime zamiast String.
    • Oznaczaj argumenty jako required, jeśli są wymagane do wykonania queries.
  5. Reguły list
    • Do filtrowania list używaj argumentu filter, który zawiera wszystkie dostępne filtry.
    • Używaj argumentu sort typu Enum lub [Enum!] do sortowania list.
    • Używaj limit z wartością domyślną i skip, aby ograniczyć liczbę zwracanych elementów na liście.
    • Używaj argumentów page, perPage do paginacji i zwracaj typ wyjściowy z items (tablicą elementów) i pageInfo (metadanymi).
    • Dla nieskończonych list (nieskończone przewijanie) używaj Relay Cursor Connections Specification.
  6. Reguły mutations
    • Używaj Namespace-types do grupowania mutations w ramach jednego zasobu.
    • Wychodź poza CRUD — twórz małe mutations dla różnych operacji biznesowych na zasobach.
    • Rozważ możliwość wykonywania mutations na wielu elementach (batch zmiany tego samego typu).
    • Mutations powinny jasno opisywać wszystkie obowiązkowe argumenty; nie powinno być opcji albo-albo.
    • W mutations umieszczaj wszystkie zmienne w jednym unikalnym argumencie input.
    • Każda mutation powinna mieć unikalny payload type.

Najlepsze praktyki dotyczące resolverów

Artykuł GraphQL Resolvers: Best Practices opisuje, jak najlepiej tworzyć resolvery pól. Choć jest skierowany do serwerów Node.js (infrastruktura PayPal oparta jest na Express), wiele jego lekcji można też zastosować do innych technologii, w tym PHP.

Główne wnioski to:

  • Pobieranie i przekazywanie danych od rodzica do dziecka powinno być stosowane oszczędnie.
  • Używaj bibliotek takich jak dataloader do deduplikacji żądań downstream.
  • Bądź świadomy obciążenia, jakie nakładasz na swoje źródła danych.
  • Nie mutuj "context". Zapewnia to spójny, mniej podatny na błędy kod.
  • Pisz resolvery czytelne, łatwe w utrzymaniu i testowalnych. Nie za sprytne.
  • Spraw, aby twoje resolvery były jak najcieńsze. Wyodrębnij logikę pobierania danych do wielokrotnie używanych funkcji async.

OWASP - GraphQL Cheat Sheet

OWASP (Open Web Application Security Project) to fundacja non-profit pracująca na rzecz poprawy bezpieczeństwa oprogramowania. Prowadzi badania nad podatnościami różnych technologii na exploity i szczegółowo opisuje rozwiązania problemów bezpieczeństwa, ułatwiając deweloperom zapobieganie atakom.

OWASP opublikowało GraphQL Cheat Sheet, wyjaśniając, jakie są najczęstsze ataki i największe problemy bezpieczeństwa w GraphQL oraz jak je rozwiązać.

Częste ataki na GraphQL to:

  1. Injection - zazwyczaj obejmuje, ale nie ogranicza się do:
    • Injection SQL i NoSQL
    • Injection poleceń systemu operacyjnego
    • Injection SSRF i CRLF / Request Smuggling
  2. DoS (Denial of Service)
  3. Nadużycie złamanej autoryzacji: niewłaściwy lub nadmierny dostęp, w tym IDOR
  4. Batching Attacks, specyficzna dla GraphQL metoda ataku brute force
  5. Nadużycie niebezpiecznych domyślnych konfiguracji

OWASP następnie dostarcza rekomendacji, jak unikać każdego z tych przypadków.

Najlepsze praktyki z queries GraphQL

Zespół Apollo opublikował GraphQL query best practices, oferując praktyczne wskazówki dotyczące konkretnych sposobów komponowania queries GraphQL.

Na przykład te dwa queries osiągają ten sam cel, ale ponieważ pierwsze ma nazwę operacji, jest bardziej zrozumiałe i pomocne podczas debugowania:

# Zalecane ✅
query GetBooks {
  books {
    title
  }
}
 
# Niezalecane ❌
query {
  books {
    title
  }
}

Ich sugestie obejmują:

  • Nadawaj nazwy wszystkim operacjom
  • Używaj zmiennych do dostarczania argumentów GraphQL
  • Pobieraj tylko potrzebne dane, tam gdzie ich potrzebujesz
  • Używaj fragments do enkapsulacji powiązanych zestawów pól
  • Pobieraj dane globalne i dane specyficzne dla użytkownika osobno

Wykorzystanie one graph

Również od zespołu Apollo pochodzi strona Principled GraphQL, która wyjaśnia, że GraphQL to nie tylko specyfikacja, ale — być może co ważniejsze — interfejs do interakcji z "grafem" danych naszej firmy.

Poprzez listę 10 zasad strona ta opisuje, jak w pełni wykorzystać pojedynczy graf:

  1. One Graph: twoja firma powinna mieć jeden ujednolicony graf, zamiast wielu grafów tworzonych przez każdy zespół.
  2. Federated Implementation: choć istnieje tylko jeden graf, implementacja tego grafu powinna być sfederowana między wieloma zespołami.
  3. Track the Schema in a Registry: powinno istnieć jedno źródło prawdy do rejestrowania i śledzenia grafu.
  4. Abstract, Demand-Oriented Schema: schema powinno działać jako warstwa abstrakcji zapewniająca elastyczność konsumentom, ukrywając jednocześnie szczegóły implementacji usług.
  5. Use an Agile Approach to Schema Development: schema powinno być budowane przyrostowo na podstawie rzeczywistych wymagań i ewoluować płynnie w czasie.
  6. Iteratively Improve Performance: zarządzanie wydajnością powinno być ciągłym, opartym na danych procesem, płynnie dostosowującym się do zmieniających się obciążeń queries i implementacji usług.
  7. Use Graph Metadata to Empower Developers: deweloperzy powinni być wyposażeni w bogatą świadomość grafu przez cały proces deweloperski.
  8. Access and Demand Control: przyznawaj dostęp do grafu na podstawie klienta i zarządzaj tym, co i jak klienci mogą uzyskać do niego dostęp.
  9. Structured Logging: rejestruj strukturalne logi wszystkich operacji grafu i wykorzystuj je jako główne narzędzie do rozumienia użycia grafu.
  10. Separate the GraphQL Layer from the Service Layer: przyjmij architekturę warstwową z funkcjonalnością grafu podzieloną na osobną warstwę, a nie wbudowaną w każdą usługę.