GraphQL е език за заявки за вашия API, който е разработен и с отворен код от Facebook през 2015 г. Повече за „Какво е GraphQL“:



Основният градивен елемент на GraphQL схема е „типовата система“. Типовата система дефинира типовете данни, които могат да бъдат заявени, и полетата, които могат да бъдат заявени за всеки тип. Типовата система GraphQL включва вградени скаларни типове (напр. Int, String, Boolean), както и потребителски типове, които могат да бъдат дефинирани от разработчика.

Системата от типове се състои от три основни типа: скалари, обекти и енуми.

Скаларите са най-основният тип в GraphQL и включват вградени типове като Int, Float, String, Boolean и ID. Тези типове представляват най-основните части от данни, които могат да бъдат заявени или манипулирани в GraphQL API.

Типовете обекти се използват за представяне на сложни структури от данни и са съставени от полета, които са скалари или други типове обекти. Например тип обект Book може да има полета за заглавие, автор и рецензии.

Енумерациите се използват за представяне на фиксиран набор от възможни стойности, като например BookStatus изброяване със стойности на „AVAILABLE“, „CHECKED_OUT“ и „ON_HOLD“.

В допълнение към тези типове, GraphQL има и няколко модификатора на типове, които могат да се използват за допълнително описание на данните:

  • Non-Null: гарантира, че полето не може да бъде нула.
  • List: позволява полето да съдържа списък с елементи, като например масив от книги.
  • Input: използва се за дефиниране на типове вход за мутации.

GraphQL също така позволява създаването на потребителски скаларни типове за представяне на специфични типове данни, които не са обхванати от вградените скалари.

Типовата система GraphQL също се използва за дефиниране на връзки между различни типове данни. Това може да се постигне чрез използване на интерфейси, съюзи и полета.

Интерфейсите дефинират общ набор от полета, които множество типове трябва да изпълняват. Например интерфейс Node може да има поле id, което всички типове, които го прилагат, също трябва да имат.

Обединенията позволяват множество типове да бъдат върнати от едно поле. Например поле search, което връща тип Book или Author.

И накрая, полетата в GraphQL могат също да се използват за описание на връзки между типове. Например полето author в типа Book ще се използва за описание на връзката между Book и неговото Author.

Схеми

Схемата на GraphQL е план за вашия API. Той дефинира типовете данни, които могат да бъдат заявени, полетата, които могат да бъдат заявени за всеки тип, и връзките между типовете. Схемата на GraphQL се дефинира с помощта на езика за схема на GraphQL, който е прост език за описание на структурата на GraphQL API.

Ето пример за проста схема на GraphQL, която дефинира тип `Book` с полета `title` и `author`:

type Book {
  title: String
  author: String
}

Тази схема дефинира един тип, „Книга“, с две полета, „заглавие“ и „автор“, като и двете са от тип „Низ“.

Вградени скаларни типове

GraphQL има няколко вградени скаларни типа: Int, Float, String, Boolean и ID. Тези типове се използват за дефиниране на полетата на вашите типове и могат да се използват в аргументите на вашите заявки и мутации.

Ето пример за заявка, която изисква полетата „заглавие“ и „автор“ от тип „Книга“:

query {
  book(id: 1) {
    title
    author
  }
}

В този пример полето „book“ е от тип „Book“ и приема аргумент „id“, който е от тип „ID“. И двете полета „заглавие“ и „автор“ са от тип „Низ“.

Типови дефиниции

В GraphQL можете да дефинирате свои собствени типове, като използвате ключовата дума „type“. Дефиницията на тип дефинира нов тип и неговите полета.

Ето пример за дефиниция на тип за тип „Човек“ с полета „име“ и „възраст“:

type Person {
  name: String
  age: Int
}

Типови модификатори

GraphQL ви позволява да промените типа на поле със следните модификатори:

  • ! обозначава ненулево поле. Това означава, че полето винаги трябва да връща стойност.
  • [] обозначава списък от типа. Това означава, че полето ще върне масив от посочения тип.

Ето пример за дефиниция на тип, която включва модификатори на тип:

type Query {
  books: [Book!]!
  person(id: ID!): Person!
}

В този пример полето „книги“ е ненулев списък с ненулеви типове „Книга“, а полето „лице“ е ненулев тип „Човек“, който приема ненулев аргумент „id“ от въведете „ID“.

Входни аргументи

В GraphQL можете да предавате аргументи към вашите полета, за да посочите допълнителна информация за данните, които изисквате. Те се наричат ​​входни аргументи. Входните аргументи се дефинират с помощта на ключовата дума „вход“.

Ето пример за заявка, която използва входен аргумент за филтриране на списък с книги по техния автор:

query {
  books(filter: { author: "George Orwell" }) {
    title
  }
}

В този пример полето „книги“ приема входен аргумент, наречен „филтър“ от тип „BookFilterInput“. Типът „BookFilterInput“ се дефинира като:

input BookFilterInput {
  author: String
}

Типове входове

Входните типове са подобни на обикновените типове, но се използват специално за входни аргументи. Те се дефинират с помощта на ключовата дума „вход“.

Ето пример за тип вход за мутация „CreateBook“:

input CreateBookInput {
  title: String!
  author: String!
}

В този пример типът „CreateBookInput“ има две полета, „title“ и „author“, като и двете са ненулеви низове.

Персонализирани скалари

В допълнение към вградените скаларни типове, GraphQL ви позволява да дефинирате свои собствени персонализирани скаларни типове. Персонализираните скаларни типове могат да се използват за представяне на по-конкретни типове данни, като дата или URL.

Ето пример за потребителски скаларен тип, наречен „Дата“:

scalar Date

За да използвате този потребителски скаларен тип, трябва да посочите персонализиран скаларен резолвер. Скаларните резолвери са функции, които определят как да анализирате и сериализирате персонализирани скалари.

Интерфейси

Интерфейсите в GraphQL ви позволяват да дефинирате набор от полета, които множество типове могат да реализират. Това ви позволява да укажете, че определени типове имат определен набор от полета, без да се налага да повтаряте полетата за всеки тип.

Ето пример за интерфейс, наречен „Node“, който дефинира поле „id“:

interface Node {
  id: ID!
}

След това можете да имате няколко типа, които внедряват този интерфейс:

type Book implements Node {
  id: ID!
  title: String
  author: String
}

type Person implements Node {
  id: ID!
  name: String
  age: Int
}

В този пример и двата вида „Книга“ и „Човек“ имплементират интерфейса „Възел“ и имат ненулево поле „id“ от тип „ID“.

Синдикати

Обединенията в GraphQL ви позволяват да представяте множество типове като един тип. Това ви позволява да върнете няколко типа в едно и също поле.

Ето пример за тип обединение, наречен „SearchResult“, който може да представлява или „Книга“, или „Човек“:

union SearchResult = Book | Person

След това можете да използвате този тип обединение в заявка:

query {
  search(query: "George Orwell") {
    ... on Book {
      title
    }
    ... on Person {
      name
    }
  }
}

В този пример полето „търсене“ връща тип обединение „Резултат от търсенето“, който може да бъде тип „Книга“ или „Човек“. За достъп до полетата от конкретния тип, заявката използва синтаксиса „…“, за да посочи типа.

Енуми

Енумите в GraphQL ви позволяват да дефинирате набор от предварително дефинирани стойности за поле. Това ви позволява да укажете, че едно поле може да има само определени стойности.

Ето пример за тип enum, наречен „BookGenre“:

enum BookGenre {
  SCI_FI
  FANTASY
  ROMANCE
  MYSTERY
}

След това можете да използвате този тип enum в дефиниция на тип:

type Book {
  title: String
  author: String
  genre: BookGenre
}

В този пример полето „жанр“ от типа „Книга“ може да има само предварително зададените стойности на „SCI_FI“, „ФЕНТАЗИЯ“, „РОМАНС“ и „МИСТЕРИЯ“.

Запитвания

Заявките се използват за извличане на данни от GraphQL сървър. Те са подобни на GET заявките в REST API. Заявката се състои от набор от полета, които искате да извлечете, заедно с всякакви аргументи и вложени полета.

Ето пример за заявка, която извлича заглавието и автора на книга:

query {
  book(id: 1) {
    title
    author
  }
}

Тази заявка изисква полето „book“ с аргумент „id“ 1 и след това изисква полетата „title“ и „author“ на върнатия обект „book“.

Силата на GraphQL се крие в способността му да извлича множество ресурси в една заявка. Например, можете да извлечете информация за книга и нейния автор в една заявка:

query {
  book(id: 1) {
    title
    author {
      name
      bio
    }
  }
}

Тази заявка извлича заглавието на книгата, заедно с името и биографията на автора на книгата. Това е мощна функция, която може да намали броя на заявките, необходими за извличане на данните, необходими за конкретен случай на употреба.

Мутации

Мутациите се използват за създаване, актуализиране или изтриване на данни на GraphQL сървър. Те са подобни на заявките POST, PUT и DELETE в REST API. Мутацията се състои от набор от полета, които искате да модифицирате, заедно с всякакви аргументи и вложени полета.

Ето пример за мутация, която създава нова книга:

mutation {
  createBook(input: {
    title: "The Hobbit"
    author: "J.R.R. Tolkien"
    genre: FANTASY
  }) {
    title
    author
    genre
  }
}

Тази мутация извиква полето “createBook” с аргумент “input”, който съдържа полетата за новата книга. След това мутацията връща заглавието, автора и жанра на новосъздадената книга.

Абонаменти

Абонаментите се използват за получаване на актуализации в реално време от GraphQL сървър. Те са подобни на WebSocket връзките в REST API. Абонаментът се състои от набор от полета, за които искате да се абонирате, заедно с всякакви аргументи и вложени полета.

Ето пример за абонамент, който следи за актуализации на книга:

subscription {
  bookUpdates(id: 1) {
    title
    author
    genre
  }
}

Този абонамент извиква полето „bookUpdates“ с аргумент „id“ 1 и след това изисква полетата за заглавие, автор и жанр на върнатия обект книга. След това сървърът ще изпрати всички актуализации на книгата с посочения идентификатор на клиента.

Кратко сравнение с REST API

REST API се основават на HTTP протокола и използват различни крайни точки за различни ресурси. Клиентът трябва да изпрати множество заявки до различни крайни точки, за да извлече всички данни, необходими за конкретен случай на употреба. Това може да доведе до свръхизвличане или недостатъчно извличане на данни и може да направи клиентския код по-сложен.

От друга страна, GraphQL ви позволява да извличате множество ресурси в една заявка, с възможността да посочите точно какви данни са необходими. Това може да намали броя на заявките, необходими за извличане на данните, необходими за конкретен случай на употреба, което води до по-ефективни и удобни за потребителя приложения, управлявани от данни.

В REST API, например, ако искате да извлечете подробности за книга, нейния автор и нейните рецензии, ще трябва да направите множество заявки до различни крайни точки като:

GET /books/1
GET /authors/2
GET /reviews?bookId=1

За разлика от това, в GraphQL можете да извлечете цялата информация в една заявка:

query {
  book(id: 1) {
    title
    author {
      name
      bio
    }
    reviews {
      text
      rating
    }
  }
}

Това не само намалява броя на необходимите заявки, но също така прави клиентския код по-прост, тъй като всички необходими данни са налични в един отговор.

Друго предимство на GraphQL пред REST е, че позволява повече гъвкавост във формата на върнатите данни. В REST формата на върнатите данни се определя от крайната точка, която се извиква, докато в GraphQL формата на върнатите данни се определя от заявката на клиента. Това позволява на клиента да извлича само данните, от които се нуждае, и не трябва да филтрира ненужните данни.

В обобщение, GraphQL предоставя по-ефективен и гъвкав начин за извличане на данни, което позволява по-удобни за потребителя приложения, управлявани от данни. Позволява на клиента да посочи точно какви данни са необходими, като намалява броя на необходимите заявки и прави кода на клиента по-прост.