GraphQL — је упитни језик за API и извршно окружење за извођење ових упита, развијен од стране Facebook-а 2012. године и објављен као отворени код 2015. За разлику од REST-а, где сервер одређује структуру одговора, GraphQL омогућава клијенту да тачно наведе који подаци су му потребни, потпуно елиминишући проблеме overfetching-а и underfetching-а. Према State of JavaScript Survey (2025), GraphQL користи 35% анкетираних програмера, а међу великим компанијама увеле су га GitHub, Shopify, Airbnb и The New York Times. GraphQL подржава три типа операција: query (читање), mutation (упис) и subscription (ажурирања у реалном времену преко WebSocket-а).
Главне тачке
GraphQL — је спецификација и извршно окружење за API које клијенту пружа потпуну контролу над примљеним подацима. Развијена од стране инжењера Facebook-а за решавање проблема мобилне апликације News Feed, спецификација је објављена као отворени стандард 2015. године. Од 2018. године GraphQL је под управом GraphQL Фондације уз подршку Linux Фондације и компанија као што су Apollo, AWS, GitHub, SAP и друге.
За разлику од REST-а, где сваки endpoint враћа фиксну структуру података, GraphQL користи јединствени endpoint који прима низ упита. Клијент у упиту описује која му поља требају, а сервер враћа управо њих. На пример, упит { user(id: „1”) { name email } } вратиће само name и email корисника, без додатних поља попут address, phone или createdAt која би се морала добијати у REST-у.
GraphQL није везан ни за једну одређену базу података или језик. Спецификација дефинише само формат упита и одговора. Постоје имплементације сервера у Node.js (graphql-js, Apollo Server), Kotlin (graphql-kotlin, Netflix DGS Framework), Python (Graphene, Strawberry), Ruby (graphql-ruby) и другим језицима. Клијентске библиотеке доступне су за све главне платформе, укључујући Apollo Client за iOS, Android и веб.
Архитектура GraphQL-а се састоји од три кључне компоненте: шема (Schema), резолвери (Resolvers) и извршни мотор (GraphQL Engine). Шема одређује који типови података су доступни, који упити се могу извршавати и које аргументе прихватају. Резолвери су функције на серверу које враћају податке за свако поље шеме. Извршни мотор прима долазни упит, валидира га према шеми, позива одговарајуће резолвере и саставља одговор.
Процес обраде упита изгледа овако:
Кључна предност архитектуре GraphQL-а је решавање на нивоу поља. У REST-у програмер или добија сва поља ресурса (могуће са вишком), или прибегава проширењима попут ?fields=name,email. У GraphQL-у таква филтрација је уграђена у језик: сваки упит експлицитно наводи која поља су потребна, а сервер враћа управо њих. Ово је посебно важно за мобилне апликације, где количина пренесених података директно утиче на брзину учитавања и потрошњу саобраћаја.
GraphQL дефинише три типа операција, од којих свака одговара одређеном сценарију интеракције. Query — за читање података, аналогно GET-у у REST-у. Mutation — за измену података (креирање, ажурирање, брисање), аналогно POST/PUT/DELETE. Subscription — за ажурирања у реалном времену преко WebSocket-а, што нема директну аналогију у класичном REST-у (захтева додатна решења попут WebSocket-а или Server-Sent Events).
Основна синтакса упита је интуитивна:
// Једноставан упит са аргументом
query {
user(id: "42") {
name
email
avatarUrl
}
}
// Mutation са враћањем измењених података
mutation {
updateProfile(name: "Иван") {
id
name
updatedAt
}
}
// Subscription — ослушкује ажурирања у реалном времену
subscription {
newMessage(chatId: "chat_1") {
id
text
sender { name }
}
}
Query се извршава паралелно — сва поља на истом нивоу се учитавају истовремено. Ово омогућава учитавање повезаних података (корисника и његових постова) једним упитом без вишеструких round-trip-ова. Mutation се извршава секвенцијално — мутације у једном упиту се извршавају једна за другом по редоследу декларације. Subscription успоставља сталну везу преко WebSocket-а, путем које сервер шаље податке када дође до догађаја.
Операције могу прихватати променљиве за одвајање података од упита, директиве (@include, @skip) за условно укључивање поља и фрагменте за поновну употребу скупова поља. Ове могућности чине GraphQL упите флексибилним и вишеструко употребљивим, што је посебно важно у великим пројектима са више екрана и компоненти.
У основи GraphQL-а лежи систем типова, који описује све могуће податке и операције API-ја. Шема (Schema) је опис типова које сервер може да врати и упита које прихвата. Шема се пише на језику Schema Definition Language (SDL) и служи као уговор између клијента и сервера. Клијент може добити шему путем интроспекције — специјалног упита __schema који враћа потпуни опис API-ја.
Пример шеме за блог:
// SDL — Schema Definition Language
type User {
id: ID!
name: String!
email: String
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String
author: User!
}
type Query {
user(id: ID!): User
posts(page: Int): [Post!]!
}
Знак узвика (!) означава non-null поље — гарантовано ће бити присутно у одговору. Квадратне заграде [ ] означавају листу. GraphQL подржава скаларне типове (Int, Float, String, Boolean, ID), објектне типове, enum, union, interface и input-типове (за аргументе мутација). Строга типизација само-документује API и омогућава клијентским алатима да генеришу код: TypeScript типове, Kotlin дата-класе, Swift структуре.
Интроспекција — јединствена могућност GraphQL-а, која не постоји у REST-у. Клијент може послати упит шеми и добити потпуни опис свих типова, поља, аргумената и директива. Ово лежи у основи алата попут GraphiQL-а и Apollo Studio-а, који аутоматски генеришу документацију и аутоматско довршавање за програмере. Интроспекција такође омогућава писање аутоматских тестова који проверавају усклађеност шеме са очекиваном структуром.
Избор између GraphQL-а и REST-а је једно од кључних архитектонских питања при дизајнирању API-ја. Оба приступа имају своје предности и недостатке, а избор зависи од специфичних захтева пројекта. REST побеђује у једноставности и универзалности, GraphQL — у флексибилности и ефикасности упита. Погледајмо упоредну табелу.
| Критеријум | REST | GraphQL |
|---|---|---|
| Структура одговора | Фиксна, серверска | Флексибилна, клијентска |
| Overfetching | Често — сервер враћа сва поља | Не — клијент тражи само потребна |
| Број захтева | Вишеструки round-trip-ови | Један захтев за све податке |
| Кеширање | Изворно HTTP кеширање | Захтева ручно подешавање |
| Типизација | Није уграђена (зависи од формата) | Строга, преко SDL шеме |
| Алати | curl, Postman, Swagger | GraphiQL, Apollo Studio, Introspection |
| Отпремање датотека | Изворно преко multipart-а | Захтева додатне протоколе |
| Перформансе | Предвидиве, лакше за оптимизацију | Зависе од сложености угнежђених упита |
Главни недостатак GraphQL-а је сложеност кеширања. У REST-у HTTP кеширање ради на нивоу URL-а: један захтев ка /api/users/42 увек враћа исту структуру, а одговор се може кеширати по URL-у. У GraphQL-у сви захтеви иду на један endpoint, структура одговора зависи од тела захтева. За решавање овог проблема Apollo Client користи нормализовани кеш на страни клијента који раздваја одговоре на појединачне ентитете по id-у и аутоматски их ажурира при добијању нових података.
Још један важан аспект је N+1 проблем. При захтеву угнежђених података (на пример, постови корисника и коментари за сваки пост) GraphQL може извршити одвојени SQL упит за сваки елемент листе. Решава се помоћу DataLoader-а — алата за груписање и кеширање упита ка базама података који спаја појединачне упите у један групни. У REST-у је овај проблем мање изражен, јер програмер контролише структуру одговора на серверу.
Размотримо практичне примере коришћења GraphQL-а у мобилној апликацији на Kotlin-у са Apollo Client-ом. Примери демонстрирају типичне сценарије: учитавање података за екран профила (query), креирање новог поста (mutation) и претплату на нове коментаре (subscription). Сваки пример укључује и GraphQL упит и код на клијентској страни.
Један GraphQL упит учитава корисника, његове последње постове и укупан број пратилаца. У REST-у би било потребно најмање 2-3 захтева: /users/42, /users/42/posts, /users/42/stats. GraphQL их спаја у један round-trip, скраћујући време учитавања екрана на спорим везама.
// GraphQL упит (у .graphql датотеци)
query ProfileScreen($userId: ID!) {
user(id: $userId) {
name
bio
avatarUrl
posts(limit: 10) {
id
title
createdAt
}
followersCount
followingCount
}
}
// Позив на клијенту (Apollo Client + Kotlin)
val response = apolloClient
.query(ProfileScreenQuery(userId = "42"))
.execute()
binding.nameText.text = response.data?.user?.name
Мутација не само да креира ресурс, већ и враћа његове актуелне податке за ажурирање UI-ја. Поље __typename користи Apollo Client за нормализацију кеша — клијент аутоматски ажурира запис Post у кешу при успешном одговору мутације.
// GraphQL мутација
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
createdAt
author {
id
name
}
}
}
// Позив мутације са input типом
val input = CreatePostInput(
title = "Нови пост о GraphQL-у",
content = "GraphQL поједностављује рад са API-јем..."
)
val result = apolloClient
.mutation(CreatePostMutation(input))
.execute()
Важна предност GraphQL-а у односу на REST у контексту мобилног развоја је аутоматско генерисање кода. Apollo Client за Kotlin (Apollo GraphQL) генерише типно-безбедне класе из .graphql датотека у фази изградње. Ако сервер промени шему, пројекат се неће изградити док се упити не ажурирају. Ово спречава runtime грешке, карактеристичне за REST, где промена структуре одговора може остати непримећена током развоја.
Екосистем GraphQL-а укључује неколико кључних библиотека и алата који поједностављују развој и експлоатацију. Apollo Client — најпопуларнија клијентска библиотека, која подржава React, iOS, Android и Kotlin Multiplatform. Relay од Facebook-а — алтернатива за React апликације са јединственим приступом управљању подацима и кеширању. Избор између Apollo-а и Relay-а зависи од платформе и захтева за перформансама.
На серверској страни воде Apollo Server (Node.js), Netflix DGS Framework (Kotlin/Java) и graphql-ruby. За развој шеме и тестирање упита користи се GraphiQL — интерактивно IDE уграђено у прегледач. Apollo Studio пружа метрике перформанси, праћење упита и управљање шемом за производно окружење. Одвојено треба поменути GraphQL Code Generator — алат који генерише TypeScript, Kotlin, Swift и Dart типове из SDL шеме.
За мобилни развој посебан интерес представља Apollo Kotlin (Apollo GraphQL) — библиотека у потпуности написана у Kotlin-у са подршком за корутине, Flow и Multiplatform. Омогућава коришћење истих GraphQL упита за Android и iOS у Kotlin Multiplatform пројектима. Apollo Kotlin нормализује кеш, подржава грешке на нивоу поља (partial errors) и аутоматски генерише моделе података из .graphql датотека. Ово чини GraphQL пожељним избором за велике мобилне пројекте где су брзина развоја и типна безбедност важни.
Често постављана питања
GraphQL не замењује REST, већ нуди алтернативни приступ. REST је бољи за једноставне CRUD API-је, кеширање преко HTTP-а и јавне API-је са предвидивим оптерећењем. GraphQL је оптималан за сложене интерфејсе са више повезаних података.
Миграција је могућа постепено: GraphQL може радити као међуслој (gateway) испред постојећих REST сервиса. Многе компаније додају GraphQL поред REST-а, не искључујући стари API. Потпуна замена захтева преписивање резолвера.
N+1 настаје када се за сваки елемент листе извршава одвојени упит бази података. Решава се помоћу DataLoader-а — библиотеке која групише појединачне упите у један и кешира резултате у оквиру једног HTTP захтева.
Спецификација GraphQL-а не дефинише директно отпремање датотека. У пракси се користе: base64 кодирање (једноставно, али неефикасно за велике датотеке), multipart захтеви по протоколу graphql-multipart-request-spec или одвојени REST endpoint за датотеке.
Безбедност GraphQL-а захтева додатне мере: ограничавање дубине угнежђења, лимит сложености упита, rate limiting на нивоу операција. Јавна интроспекција шеме може открити структуру података — у производном окружењу препоручује се њено искључивање.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође