GraphQL etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
GraphQL etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

3 Şubat 2022 Perşembe

GraphQL Subscriptions

Giriş
Açıklaması şöyle
Subscription enables the client to fetch real-time updates from the server. You can think of subscriptions as analogous to continuous polling mechanisms. It makes it possible for the server to stream data to all the clients that are listening or 'subscribed' to it. Just like queries, subscriptions allow you to read data. Unlike queries, subscriptions maintain an active connection to your GraphQL server, most commonly via WebSocket. This enables your server to push updates to the client over time. Executing a subscription creates a persistent function on the server that maps an underlying Source Stream to a returned Response Stream. You can define available subscriptions in your GraphQL schema as fields of the Subscription type.
Örnek
Şöyle yaparız
subscription {
  newAuthor {
    name
    country
  }
}
Eğer yeni bir yazar yaratılırsa sunucu bize şunu gönderir.
{
  "newAuthor": {
    "name": "Robert Jordan",
    "country": "USA"
  }
}


19 Temmuz 2021 Pazartesi

GraphQL Schema

Giriş
Açıklaması şöyle. Schema tanımlama için kullanılan dile Schema Definition Language (SDL) deniliyor.
GraphQL has its own type system. This system is used to define the schema of an API. Basically, the syntax for writing schemas is known as Schema Definition Language or SDL.
Nesneler type Foo şeklinde tanımlanıyor. Alanların sonunda ! işareti varsa bu alan mecburidir anlamına geliyor. Yani es geçilemez. Açıklaması şöyle
The ! mark signifies that these are mandatory fields.

Örnek - String
Şöyle yaparız
type Query {
  shows(titleFilter: String): [Show]
}

type Show {
  title: String
  releaseYear: Int
}
Örnek - Int
Şöyle yaparız
type Employee {
  id: String!
  name: String!
  phone: String!
  age: Int!
}
Örnek - tehlikeli kod
Şu kod tehlikeli
type Query {
  album(id: ID!): Album
}
type Album {
  photos(first: Int): [Photo]
}
type Photo {
  album: Album
}

query maliciousQuery {
  album(id: ”some-id”) {
    photos(first: 9999) {
      album {
        photos(first: 9999) {
          album {
            photos(first: 9999) {
              album {
                #... Repeat this 10000 times...
              }
            }
          }
        }
      }
    }
  }
}

14 Temmuz 2021 Çarşamba

GraphQL Mutation - CRUD İşlemleridir

Giriş
POST isteği ile gönderilir. JSON döner. Mutation ile create, update, delete işlemleri yapılır. Mutation bir sonuç dönebilir.
Metodun içine gönderilecek parametreler yazılır, döndürülecek sonuçlar ise süslü parantez içindedir.
Örnek
Şöyle yaparız. Burada name ve country değerleri gönderiliyor. Sonuç olarak yine aynı parametreler isteniyor.
mutation {
  createAuthor(name: 'Brandon Sanderson', country: "USA") {
    name
    country
  }
}
Eğer yeni bir kayıt yaratsaydık ve sonuç olarak id isteseydik şöyle yaparız
mutation {
  createAuthor(name: 'Brandon Sanderson', country: "USA") {
    id
  }
}

Örnek
Şöyle yaparız
mutation {
  project_tracker {
    createTicket(title : "New ticket", author_id : 11824) {
      id
    }
  }
}
Açıklaması şöyle
In our example, the createTicket mutation accepts two arguments for creating a ticket: title and author_id. On ticket creation, we return the $id of the newly created ticket. Just like the query, the mutation is a root object type. Mutations, for the most part, are very flexible and can return whatever you desire: scalars such as int, string, bool, and core types like the Ticket, or even custom response objects. Similar to queries, if the mutation field returns an object type, you can ask for nested fields. 
Örnek
Şöyle yaparız
type Author {
  id: ID!
  firstName: String!
  lastName: String!
}

type Query {
  findAllAuthors: [Author]!
  countAuthors: Long!
}

type Mutation {
  newAuthor(firstName: String!, lastName: String!) : Author!
}

9 Mart 2021 Salı

GraphQL Query

Giriş
Açıklaması şöyle
In REST API, we fetch data from specific endpoints. Each endpoint has a particular structure. In other words, the client needs to adhere to the API structure. Basically, the request URL determines the query parameters in a REST API.

However, GraphQL has a considerably different approach. Instead of multiple endpoints, a GraphQL server typically exposes only one endpoint. The structure of the response is not fixed. Instead, it is quite flexible. Basically, the client specifies what data is required and the server responds with the required data.
Root veya Hiyerarşik Sorgular
Nesneler başka nesneleri de içerebilir. Elimizde şöyle bir schema olsun
type Author {
  name: String!
  country: Int!
  books: [Book!]!
}

type Book {
  title: String!
  publishYear: Int!
  author: Author!
}
Sadece kök nesneyi istiyorsak sorgu olarak şöyle yaparız. Burada kitapların sadece title alanını istiyoruz
{
  allBooks {
    title
  }
}
Cevap olarak şunu alırız
{
  "allBooks": [
    { "title": "Eye of the World" },
    { "title": "The Way of Kings" },
    { "title": "The Mistborn" }
  ]
}
Eğer kök nesnenin diğer alanlarını da istiyorsak sorgu olarak şöyle yaparız. Burada kitapların title  ve publishYear alanlarını istiyoruz
{
  allBooks {
    title
    publishYear
  }
}
Hiyerarşik sorgu için şöyle yaparız. Burada yazarların name alanını ve yazdıkları kitapların title alanını istiyoruz. 
{
  allAuthors {
    name
    books {
      title
    }
  }
}


Bazı Örnekler

Örnek - parametresiz
Şöyle yaparız
{
  "query":"{findAllBooks { id title } }"
}
Örnek - parametreli
name + email çekmek için şöyle yaparız.
{
  "query": "query($id: String!){ retrieveUser (id: $id) {name email} }",
  "parameters": {
    "id": 1
  }
}
Sadece email çekmek için şöyle yaparız.
{
  "query": "query($id: String!){ retrieveUser (id: $id) {email} }",
  "parameters": {
    "id": 1
  }
}
Örnek - parametreli
Şöyle yaparız
query order($id: ID!){
  order(id: $id) {
    quantity
    price
    orderDate {
      day,
      month,
      year
    }
    isConfirmed
  }
}
Örnek - parametreli
Şöyle yaparız
void getPostById(WebClient client, String id) {
  client.post("/graphql")
        .sendJson(Map.of(
"query","query post($id:String!){ postById(postId:$id){ id title content author{ name } comments{ content createdAt} createdAt}}",
"variables", Map.of("id", id)
        ))
        .onSuccess(
          data -> log.info("data of postByID: {}", data.bodyAsString())
        )
        .onFailure(e -> log.error("error: {}", e));
}
Örnek - sabit parametre
Şöyle yaparız
query {
    recentPosts(count: 10, offset: 0) {
        id
        title
        category
        author {
            id
            name
            thumbnail
        }
    }
}
Örnek - last kelimesi
Şöyle yaparız
  
{
  "data": {
    "User": {
      "name": "Fernando Doglio",
      "posts": [{
        "title": "Post #1",
        "post_date": "2021-06-28"
      }
      ...
      ],
      "followers": [
        { "name": "Follower #1" },
        { "name": "Follower #2" }
      ]
    }
  }
}
Çıktı olarak şunu alırız
{
  "data": {
    "User": {
      "name": "Fernando Doglio",
      "posts": [{
        "title": "Post #1",
        "post_date": "2021-06-28"
      }
      ...
      ],
      "followers": [
        { "name": "Follower #1" },
        { "name": "Follower #2" }
      ]
    }
  }
}
Örnek - DataLoader
Şöyle yaparız. Bir tane viewer nesnesi döner.
query CompanyData {
  viewer { # DataLoader called usersById
    company(id: "1") { # DataLoader called companiesById
      name

      transports { # DataLoader called transportsByCompanyId
        number

        carrier { # Dataloader called companiesById
          name
        }
      }
    }
  }
}
Açıklaması şöyle
Assuming, for example, that the user has access to 5 transports. Without DataLoaders, we would be looking at 8 database queries:
1 call to fetch the user (viewer)
1 call to fetch company with ID 1
1 call to fetch the 5 transports
5 calls to fetch the carriers for each of the transports

In this example, the benefit comes from the companiesById DataLoader, as it groups the 5 calls for getting the carriers of the transports into a single database query, therefore, saving us from making 4 database queries.

You can imagine scaling this example to something more plausible, such as the user having access to 500 transports, with DataLoaders, the database query count is still 4, without DataLoaders, it would now be 503.

This approach helps us solve the aforementioned N+1 problem, whilst maintaining privacy by sandboxing each request to a separate set of DataLoaders — the cached results are not shared between requests, meaning any permissions logic is never shared.

The DataLoaders also avoid errors in database queries by avoiding duplication of database queries, as well as speeding up the developer experience. More often than not, there already exists a DataLoader for the entity that the code is working with.



9 Aralık 2020 Çarşamba

GraphQL

Giriş
GraphQL'in faydalarını anlatan bir yazı burada. Aslında bu kelimeyi daha önceden bir çok defa duymuş olsam da merak etmeme sebep olan yazı da bu. 

GraphQL'in Tarihçesi Nedir?
Facebook tarafından 2012 yılında geliştirildi, 2015 yılında açık kaynak haline getirildi

GraphQL'in Faydası Nedir?
En önemli faydası getirilen verinin alanlarını özelleştirebilmek. Böylece mobil uygulamalarda tam olarak ihtiyaç duyulan veri getirilir. Açıklaması şöyle. /graphql adresine POST isteği gönderilir.
All the resources of the API are exposed in a single request — normally a POST to /graphql — and the content is a query using GraphQL specification. The query specifies the filter and the data to be returned by the API.
Json içinde 
type Foo {...} ve
type Query{...}
şeklinde kullanım vardır.

Type Alan Tipleri
Boolean
Date
Float
ID
Int
String

olabilir. Tipin yanında ! (ünlem) işareti varsa, mecburi olduğunu belirtir

Geliştirme Yöntemi
Açıklaması şöyle. Yani schema elle yazılabilir veya üretilebilir.
There are two different approaches to GraphQL development; schema-first and code-first development. 
With schema-first development, you manually define your API’s schema using the GraphQL Schema Language. The code in your service only implements this schema.

With code-first development, you don’t have a schema file. Instead, the schema gets generated at runtime based on definitions in code.

Kavramlar
Schemas
Type'ları ve işlemleri (Query + Mutations) belirtir. GraphQL Schema yazısına taşıdım

Query
Sorgu için kullanılan metod imzaları. GraphQL Query yazısına taşıdım

Mutations
Create, update, delete işlemleri için metod imzaları. GraphQL Mutation yazısına taşıdım

Resolvers
GraphQL'e veriyi nereden alacağını belirtir Yani Query'leri çalıştıran kodlar

Subscriptions
GraphQL sunucusuna abone olunur ve değişikliklerden haberdar olunur. GraphQL Subscriptions yazısına taşıdım

GraphQL ile Neo4J İlişkisi Nedir?
Neo4J bir Graph veri tabanı . GraphQL ile ilişkisi yoktur. Sadece isimlerindeki Graph kelimeleri aynı

Kütüphaneler
Java + GraphQL kullanabilmek için bir sürü kütüphane var. Bazılar şöyle

1. graphql-spring-boot-starter Kullanımı
Maven
Örnek
Şu satırı dahil ederiz
<dependency>
  <groupId>com.graphql-java</groupId>
  <artifactId>graphql-spring-boot-starter</artifactId>
  <version>5.0.2</version>
</dependency>
<dependency>
  <groupId>com.graphql-java</groupId>
  <artifactId>graphql-java-tools</artifactId>
  <version>5.2.4</version>
</dependency>
Bu satırlar ile bir tane GraphQL için servlet projeye dahil edilir. Açıklaması şöyle
By default, this will expose the GraphQL Service on the /graphql endpoint of our application and will accept POST requests containing the GraphQL Payload. This endpoint can be customised in our application.properties file if necessary.
GraphQL SPQR Kullanımı
GraphQL SPQR kullanımında sadece anotasyonlar var. .graphqls" uzantılı dosyalarla uğraşmıyoruz. Bence bu kullanım Spring'in ruhuna daha uygun.

Örnek
Kullanımı daha kolay olan GraphQL SPQR projesi de tercih edilebilir. Şöyle yaparız
<dependency>
  <groupId>io.leangen.graphql</groupId>
  <artifactId>graphql-spqr-spring-boot-starter</artifactId>
  <version>0.0.4</version>
</dependency>

graphql-java Kullanımı
Açıklaması şöyle
graphql-java is most popular for implementing schema-first GraphQL APIs in Java, but is designed to be a low level library. The graphql-java-kickstart starter is a set of libraries for implementing GraphQL services, and provides graphql-java-tools and graphql-java-servlet on top of graphql-java.
graphql-java-tools Kullanımı
Bazı notlarım şöyle
- Schema .graphqls uzantlı dosyalara yazılır. GraphQL Java Tools bu dosyaları parse edebilir.

- Gerekli entity için GraphQLResolver'dan kalıtan bir resolver yazılır. Bu resolver aynı zamanda bir bean'dir. Bu resolver'da kendi repository sınıflarımız çağrılır.

- Gerekli entity için GraphQLMutationResolver 'dan kalıtan bir resolver yazılır. Bu resolver aynı zamanda bir bean'dir. Bu resolver'da kendi repository sınıflarımız çağrılır.

- Mutation ve Query bean'leri de yaratılır

- http://localhost:8080/graphql/schema.json adresinde schema görülebilir

.graphqls Dosyaları
Açıklaması şöyle
The GraphQL Tools library works by processing GraphQL Schema files to build the correct structure and then wires special beans to this structure. The Spring Boot GraphQL starter automatically finds these schema files.

These files need to be saved with the extension “.graphqls” and can be present anywhere on the classpath. We can also have as many of these files as desired, so we can split the scheme up into modules as desired.

The one requirement is that there must be exactly one root query, and up to one root mutation. This can not be split across files, unlike the rest of the scheme. This is a limitation of the GraphQL Schema definition itself, and not of the Java implementation.
GraphQLQueryResolver 
Örnek
Elimizde şöyle bir query olsun
# The Root Query for the application
type Query {
    recentPosts(count: Int, offset: Int): [Post]!
}
Şöyle yaparız. Not : Metod imzasının izlemesi gereken bazı kurallar var. 
public class Query implements GraphQLQueryResolver {
  private PostDao postDao;
  public List<Post> getRecentPosts(int count, int offset) {
    return postsDao.getRecentPosts(count, offset);
  }
}