Titik akhir GraphQL di Penyusun API Data (DAB) memungkinkan Anda mengkueri dan memodifikasi data dengan presisi.
Setiap kueri mendeklarasikan dengan tepat bidang apa yang Anda butuhkan dan mendukung argumen untuk memfilter, mengurutkan, dan membuat halaman hasil.
Secara default, DAB menghosting titik akhir GraphQL-nya di:
https://{base_url}/graphql
Entitas yang diekspos melalui konfigurasi secara otomatis disertakan dalam skema GraphQL.
Misalnya, jika Anda memiliki books entitas dan authors , keduanya muncul sebagai bidang akar dalam skema.
Nota
Untuk menjelajahi skema dan kolom pelengkapan otomatis, anda bisa menggunakan klien atau IDE GraphQL yang modern (seperti Apollo, Insomnia, atau ekstensi GraphQL untuk Visual Studio Code).
Kata kunci yang didukung di penyusun API Data
| Konsep |
GraphQL |
Kegunaan |
| Proyeksi |
items |
Pilih bidang mana yang akan dikembalikan |
| Penyaringan |
saringan |
Membatasi baris menurut kondisi |
| Pengurutan |
orderBy |
Tentukan urutan pengurutan |
| Ukuran halaman |
pertama |
Batasi jumlah item per halaman |
| Kelanjutan |
sesudah |
Lanjutkan dari halaman terakhir |
Struktur dasar
Setiap kueri GraphQL dimulai dengan bidang akar yang mewakili entitas.
Semua permintaan GraphQL menggunakan POST ke endpoint /graphql dengan tubuh JSON yang berisi kueri.
{
books {
items {
id
title
year
pages
}
}
}
Responsnya adalah objek JSON dengan bentuk yang sama dengan set pilihan Anda.
Penomoran halaman dan detail kesalahan hanya muncul saat diperlukan.
Nota
Secara default, DAB mengembalikan hingga 100 item per kueri kecuali dikonfigurasi sebaliknya (runtime.pagination.default-page-size).
POST https://localhost:5001/graphql
Content-Type: application/json
{
"query": "{ books { items { id title year pages } } }"
}
Sukses:
{
"data": {
"books": {
"items": [
{ "id": 1, "title": "Dune", "year": 1965, "pages": 412 },
{ "id": 2, "title": "Foundation", "year": 1951, "pages": 255 }
]
}
}
}
Berhasil dengan paginasi:
{
"data": {
"books": {
"items": [
{ "id": 1, "title": "Dune", "year": 1965, "pages": 412 },
{ "id": 2, "title": "Foundation", "year": 1951, "pages": 255 }
],
"hasNextPage": true,
"endCursor": "eyJpZCI6Mn0="
}
}
}
Kesalahan:
{
"errors": [
{
"message": "Could not find item with the given key.",
"locations": [{ "line": 1, "column": 3 }],
"path": ["book_by_pk"]
}
]
}
curl -X POST "https://localhost:5001/graphql" \
-H "Content-Type: application/json" \
-d '{"query": "{ books { items { id title year pages } } }"}'
Kelas model berikut mendeserialisasi respons DAB GraphQL:
using System.Text.Json.Serialization;
public class GraphQLRequest
{
[JsonPropertyName("query")]
public string Query { get; set; } = string.Empty;
[JsonPropertyName("variables")]
public object? Variables { get; set; }
}
public class GraphQLResponse<T>
{
[JsonPropertyName("data")]
public T? Data { get; set; }
[JsonPropertyName("errors")]
public List<GraphQLError>? Errors { get; set; }
[JsonIgnore]
public bool IsSuccess => Errors is null || Errors.Count == 0;
}
public class GraphQLError
{
[JsonPropertyName("message")]
public string Message { get; set; } = string.Empty;
[JsonPropertyName("path")]
public List<string>? Path { get; set; }
}
public class BooksResponse
{
[JsonPropertyName("books")]
public BooksResult? Books { get; set; }
}
public class BooksResult
{
[JsonPropertyName("items")]
public List<Book>? Items { get; set; }
[JsonPropertyName("hasNextPage")]
public bool HasNextPage { get; set; }
[JsonPropertyName("endCursor")]
public string? EndCursor { get; set; }
}
public class Book
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("title")]
public string Title { get; set; } = string.Empty;
[JsonPropertyName("year")]
public int? Year { get; set; }
[JsonPropertyName("pages")]
public int? Pages { get; set; }
}
Panggil API dan deserialisasi respons:
public async Task<List<Book>> GetBooksAsync()
{
var request = new GraphQLRequest
{
Query = "{ books { items { id title year pages } } }"
};
var response = await httpClient.PostAsJsonAsync("graphql", request);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<GraphQLResponse<BooksResponse>>();
if (result?.Errors?.Count > 0)
{
throw new Exception(result.Errors[0].Message);
}
return result?.Data?.Books?.Items ?? [];
}
Kelas data berikut memodelkan respons DAB GraphQL:
from dataclasses import dataclass, field
import requests
@dataclass
class Book:
id: int
title: str
year: int | None = None
pages: int | None = None
@dataclass
class GraphQLError:
message: str
path: list[str] | None = None
@dataclass
class BooksResult:
items: list[Book] = field(default_factory=list)
has_next_page: bool = False
end_cursor: str | None = None
@dataclass
class GraphQLResponse:
data: dict | None = None
errors: list[GraphQLError] | None = None
@property
def is_success(self) -> bool:
return self.errors is None or len(self.errors) == 0
Panggil API dan uraikan respons:
def get_books(base_url: str) -> list[Book]:
query = "{ books { items { id title year pages } } }"
response = requests.post(
f"{base_url}/graphql",
json={"query": query}
)
response.raise_for_status()
data = response.json()
if "errors" in data and data["errors"]:
raise Exception(data["errors"][0]["message"])
items = data.get("data", {}).get("books", {}).get("items", [])
return [Book(**item) for item in items]
Fungsi berikut memanggil API GraphQL:
async function getBooks(baseUrl) {
const query = "{ books { items { id title year pages } } }";
const response = await fetch(`${baseUrl}/graphql`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query }),
});
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const result = await response.json();
if (result.errors?.length > 0) {
throw new Error(result.errors[0].message);
}
return result.data?.books?.items ?? [];
}
Contoh penggunaan:
const books = await getBooks("https://localhost:5001");
console.log(`Fetched ${books.length} books from the API.`);
Jenis kueri
Setiap entitas mendukung dua kueri akar standar:
| Pertanyaan |
Deskripsi |
entity_by_pk |
Mengembalikan satu rekaman dengan kunci utamanya |
entities |
Mengembalikan daftar rekaman yang cocok dengan filter |
Contoh mengembalikan satu rekaman:
{
book_by_pk(id: 1010) {
title
year
}
}
Contoh mengembalikan banyak:
{
books {
items {
id
title
}
}
}
Memfilter hasil
filter Gunakan argumen untuk membatasi rekaman mana yang dikembalikan.
{
books(filter: { title: { contains: "Foundation" } }) {
items { id title }
}
}
Kueri ini mengembalikan semua buku yang judulnya berisi "Foundation."
Filter dapat menggabungkan perbandingan dengan operator logis:
{
authors(filter: {
or: [
{ first_name: { eq: "Isaac" } }
{ last_name: { eq: "Asimov" } }
]
}) {
items { first_name last_name }
}
}
Lihat referensi argumen filter untuk operator yang didukung seperti eq, neq, lt, lte, dan isNull.
Mengurutkan hasil
Argumen orderBy menentukan bagaimana rekaman diurutkan.
{
books(orderBy: { year: DESC, title: ASC }) {
items { id title year }
}
}
Ini mengembalikan buku yang diurutkan berdasarkan year menurun, lalu berdasarkan title.
Untuk informasi selengkapnya, lihat referensi argumen orderBy.
Membatasi hasil
Argumen first membatasi berapa banyak rekaman yang dikembalikan dalam satu permintaan.
{
books(first: 5) {
items { id title }
}
}
Ini mengembalikan lima buku pertama, diurutkan berdasarkan kunci primer secara default.
Anda juga dapat menggunakan first: -1 untuk meminta ukuran halaman maksimum yang dikonfigurasi.
Pelajari selengkapnya dalam referensi argumen pertama.
Melanjutkan hasil
Untuk mengambil halaman berikutnya, gunakan argumen after bersama kursor dari kueri sebelumnya.
{
books(first: 5, after: "eyJpZCI6NX0=") {
items { id title }
}
}
Token after menandai tempat halaman sebelumnya berakhir.
Untuk informasi selengkapnya, lihat referensi argumen setelah.
Pemilihan bidang (proyeksi)
Di GraphQL, Anda memilih dengan tepat bidang mana yang muncul dalam respons.
Tidak ada wildcard seperti SELECT *. Minta hanya apa yang Anda butuhkan.
{
books {
items { id title price }
}
}
Anda juga dapat menggunakan alias untuk mengganti nama bidang dalam respons:
{
books {
items {
bookTitle: title
cost: price
}
}
}
Lihat referensi proyeksi bidang untuk detailnya.
Memodifikasi data
Mutasi GraphQL memungkinkan Anda membuat, memperbarui, dan menghapus rekaman tergantung pada izin entitas.
| Mutasi |
Action |
createEntity |
Membuat item baru |
updateEntity |
Memperbarui item yang sudah ada |
deleteEntity |
Menghapus item |
Nota
Akhiran _by_pk hanya berlaku untuk kueri (misalnya, book_by_pk). Nama mutasi tidak menyertakan akhiran ini—gunakan updateBook dan deleteBook, bukan updateBook_by_pk atau deleteBook_by_pk.
Penting
Mutasi GraphQL memerlukan kumpulan koneksi database aktif. Jika string koneksi Anda mengatur Pooling=False atau MultipleActiveResultSets=False, mutasi gagal dengan kesalahan Implicit distributed transactions have not been enabled. Atur Pooling=True dan MultipleActiveResultSets=True (SQL Server) atau yang setara untuk penyedia database Anda.
Petunjuk / Saran
Untuk prosedur tersimpan yang diekspos melalui GraphQL, DAB mengawali nama entitas dengan execute. Misalnya, entitas prosedur tersimpan bernama GetBookById menjadi executeGetBookById dalam skema. Untuk informasi selengkapnya, lihat prosedur tersimpan.
Membuat rekaman baru
create Gunakan mutasi untuk menambahkan item baru.
POST https://localhost:5001/graphql
Content-Type: application/json
{
"query": "mutation { createBook(item: { id: 2000, title: \"Leviathan Wakes\", year: 2011, pages: 577 }) { id title year pages } }"
}
curl -X POST "https://localhost:5001/graphql" \
-H "Content-Type: application/json" \
-d '{"query": "mutation { createBook(item: { id: 2000, title: \"Leviathan Wakes\", year: 2011, pages: 577 }) { id title year pages } }"}'
var request = new GraphQLRequest
{
Query = @"
mutation CreateBook($item: CreateBookInput!) {
createBook(item: $item) { id title year pages }
}",
Variables = new
{
item = new { id = 2000, title = "Leviathan Wakes", year = 2011, pages = 577 }
}
};
var response = await httpClient.PostAsJsonAsync("graphql", request);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<GraphQLResponse<CreateBookResponse>>();
if (result?.Errors?.Count > 0)
{
throw new Exception(result.Errors[0].Message);
}
query = """
mutation CreateBook($item: CreateBookInput!) {
createBook(item: $item) { id title year pages }
}
"""
variables = {
"item": {"id": 2000, "title": "Leviathan Wakes", "year": 2011, "pages": 577}
}
response = requests.post(
f"{base_url}/graphql",
json={"query": query, "variables": variables}
)
response.raise_for_status()
data = response.json()
if "errors" in data and data["errors"]:
raise Exception(data["errors"][0]["message"])
const query = `
mutation CreateBook($item: CreateBookInput!) {
createBook(item: $item) { id title year pages }
}
`;
const variables = {
item: { id: 2000, title: "Leviathan Wakes", year: 2011, pages: 577 },
};
const response = await fetch(`${baseUrl}/graphql`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query, variables }),
});
const result = await response.json();
if (result.errors?.length > 0) {
throw new Error(result.errors[0].message);
}
Perbarui data yang ada
update Gunakan mutasi untuk mengubah bidang tertentu pada item yang sudah ada.
POST https://localhost:5001/graphql
Content-Type: application/json
{
"query": "mutation { updateBook(id: 2000, item: { title: \"Leviathan Wakes\", year: 2011, pages: 577 }) { id title year pages } }"
}
curl -X POST "https://localhost:5001/graphql" \
-H "Content-Type: application/json" \
-d '{"query": "mutation { updateBook(id: 2000, item: { title: \"Leviathan Wakes\", year: 2011, pages: 577 }) { id title year pages } }"}'
var request = new GraphQLRequest
{
Query = @"
mutation UpdateBook($id: Int!, $item: UpdateBookInput!) {
updateBook(id: $id, item: $item) { id title year pages }
}",
Variables = new
{
id = 2000,
item = new { title = "Leviathan Wakes", year = 2011, pages = 577 }
}
};
var response = await httpClient.PostAsJsonAsync("graphql", request);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<GraphQLResponse<UpdateBookResponse>>();
if (result?.Errors?.Count > 0)
{
throw new Exception(result.Errors[0].Message);
}
query = """
mutation UpdateBook($id: Int!, $item: UpdateBookInput!) {
updateBook(id: $id, item: $item) { id title year pages }
}
"""
variables = {
"id": 2000,
"item": {"title": "Leviathan Wakes", "year": 2011, "pages": 577}
}
response = requests.post(
f"{base_url}/graphql",
json={"query": query, "variables": variables}
)
response.raise_for_status()
data = response.json()
if "errors" in data and data["errors"]:
raise Exception(data["errors"][0]["message"])
const query = `
mutation UpdateBook($id: Int!, $item: UpdateBookInput!) {
updateBook(id: $id, item: $item) { id title year pages }
}
`;
const variables = {
id: 2000,
item: { title: "Leviathan Wakes", year: 2011, pages: 577 },
};
const response = await fetch(`${baseUrl}/graphql`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query, variables }),
});
const result = await response.json();
if (result.errors?.length > 0) {
throw new Error(result.errors[0].message);
}
Hapus sebuah catatan
delete Gunakan mutasi untuk menghapus item menurut kunci primer.
POST https://localhost:5001/graphql
Content-Type: application/json
{
"query": "mutation { deleteBook(id: 2000) { id title } }"
}
curl -X POST "https://localhost:5001/graphql" \
-H "Content-Type: application/json" \
-d '{"query": "mutation { deleteBook(id: 2000) { id title } }"}'
var request = new GraphQLRequest
{
Query = @"
mutation DeleteBook($id: Int!) {
deleteBook(id: $id) { id title }
}",
Variables = new { id = 2000 }
};
var response = await httpClient.PostAsJsonAsync("graphql", request);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<GraphQLResponse<DeleteBookResponse>>();
if (result?.Errors?.Count > 0)
{
throw new Exception(result.Errors[0].Message);
}
query = """
mutation DeleteBook($id: Int!) {
deleteBook(id: $id) { id title }
}
"""
variables = {"id": 2000}
response = requests.post(
f"{base_url}/graphql",
json={"query": query, "variables": variables}
)
response.raise_for_status()
data = response.json()
if "errors" in data and data["errors"]:
raise Exception(data["errors"][0]["message"])
const query = `
mutation DeleteBook($id: Int!) {
deleteBook(id: $id) { id title }
}
`;
const variables = { id: 2000 };
const response = await fetch(`${baseUrl}/graphql`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query, variables }),
});
const result = await response.json();
if (result.errors?.length > 0) {
throw new Error(result.errors[0].message);
}