Koncové body GraphQL v Tvůrci rozhraní DATA API (DAB) umožňují dotazovat a upravovat data s přesností.
Každý dotaz deklaruje přesně ta pole, která potřebujete, a podporuje argumenty pro filtrování, řazení a stránkování výsledků.
Ve výchozím nastavení DAB hostuje koncový bod GraphQL na adrese:
https://{base_url}/graphql
Entity vystavené prostřednictvím konfigurace se automaticky zahrnou do schématu GraphQL.
Například pokud máte entity books a authors, obě se ve schématu zobrazují jako kořenová pole.
Poznámka:
Pokud chcete prozkoumat schéma a pole automatického dokončování, použijte libovolného moderního GraphQL klienta nebo IDE (například Apollo, Insomnia nebo GraphQL rozšíření pro Visual Studio Code).
Klíčová slova podporovaná v Tvůrci rozhraní Data API
| Koncepce |
GraphQL |
Purpose |
| Projekce |
items |
Vyberte pole, která se mají vrátit |
| Filtrování |
filter |
Omezení řádků podle podmínky |
| Řazení |
orderBy |
Definování pořadí řazení |
| Velikost stránky |
first |
Omezení položek na stránku |
| Pokračování |
po |
Pokračovat z poslední stránky |
Základní struktura
Každý dotaz GraphQL začíná kořenovým polem, které představuje entitu.
Všechny požadavky GraphQL směřují na koncový bod /graphql s tělem ve formátu JSON, který obsahuje dotaz.
{
books {
items {
id
title
year
pages
}
}
}
Odpověď je objekt JSON se stejným tvarem jako sada výběrů.
Stránkování a podrobnosti o chybách se zobrazí pouze v případě, že je to možné.
Poznámka:
Ve výchozím nastavení daB vrátí až 100 položek na dotaz, pokud není nakonfigurovaný jinak (runtime.pagination.default-page-size).
POST https://localhost:5001/graphql
Content-Type: application/json
{
"query": "{ books { items { id title year pages } } }"
}
Úspěch:
{
"data": {
"books": {
"items": [
{ "id": 1, "title": "Dune", "year": 1965, "pages": 412 },
{ "id": 2, "title": "Foundation", "year": 1951, "pages": 255 }
]
}
}
}
Úspěch se stránkováním:
{
"data": {
"books": {
"items": [
{ "id": 1, "title": "Dune", "year": 1965, "pages": 412 },
{ "id": 2, "title": "Foundation", "year": 1951, "pages": 255 }
],
"hasNextPage": true,
"endCursor": "eyJpZCI6Mn0="
}
}
}
Chyba:
{
"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 } } }"}'
Následující třídy modelu deserializují odpovědi 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; }
}
Volání rozhraní API a deserializace odpovědi:
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 ?? [];
}
Následující datové třídy modelují odpovědi 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
Volání rozhraní API a analýza odpovědi:
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]
Následující funkce volá rozhraní GraphQL API:
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 ?? [];
}
Příklad použití:
const books = await getBooks("https://localhost:5001");
console.log(`Fetched ${books.length} books from the API.`);
Typy dotazů
Každá entita podporuje dva standardní kořenové dotazy:
| Dotaz |
Description |
entity_by_pk |
Vrátí jeden záznam podle primárního klíče. |
entities |
Vrátí seznam záznamů, které odpovídají filtrům. |
Příklad vrácení jednoho záznamu:
{
book_by_pk(id: 1010) {
title
year
}
}
Příklad vracející mnoho dat:
{
books {
items {
id
title
}
}
}
Filtrování výsledků
Pomocí argumentu filter omezte, které záznamy se vrátí.
{
books(filter: { title: { contains: "Foundation" } }) {
items { id title }
}
}
Tento dotaz vrátí všechny knihy, jejichž název obsahuje "Nadace".
Filtry můžou kombinovat porovnání s logickými operátory:
{
authors(filter: {
or: [
{ first_name: { eq: "Isaac" } }
{ last_name: { eq: "Asimov" } }
]
}) {
items { first_name last_name }
}
}
Podívejte se na referenční informace o argumentech filtru pro podporované operátory, jako jsou eq, neq, lt, lte, a isNull.
Řazení výsledků
Argument orderBy definuje způsob řazení záznamů.
{
books(orderBy: { year: DESC, title: ASC }) {
items { id title year }
}
}
Vrátí knihy seřazené podle year sestupně, pak podle title.
Další informace naleznete v odkazu argumentu orderBy.
Omezení výsledků
Argument first omezuje počet vrácených záznamů v jednom požadavku.
{
books(first: 5) {
items { id title }
}
}
Tím se vrátí prvních pět knih seřazených podle primárního klíče ve výchozím nastavení.
Můžete také použít first: -1 k vyžádání nakonfigurované maximální velikosti stránky.
Další informace najdete v prvním odkazu na argument.
Pokračování výsledků
Pokud chcete načíst další stránku, použijte after argument s kurzorem z předchozího dotazu.
{
books(first: 5, after: "eyJpZCI6NX0=") {
items { id title }
}
}
Token after označuje, kde byla předchozí stránka ukončena.
Další informace najdete v referenci následujícího argumentu.
Výběr pole (projekce)
V GraphQL zvolíte přesně ta pole, která se zobrazí v odpovědi.
Není zástupný znak jako SELECT *. Požádejte jenom o to, co potřebujete.
{
books {
items { id title price }
}
}
K přejmenování polí v odpovědi můžete také použít aliasy:
{
books {
items {
bookTitle: title
cost: price
}
}
}
Podrobnosti najdete v referenčních informacích k projekci polí .
Úprava dat
Mutace GraphQL vám umožňují vytvářet, aktualizovat a odstraňovat záznamy v závislosti na oprávněních entit.
| Mutace |
Action |
createEntity |
Vytvoření nové položky |
updateEntity |
Aktualizace existující položky |
deleteEntity |
Odebrání položky |
Poznámka:
Přípona _by_pk se vztahuje pouze na dotazy (například book_by_pk). Názvy mutací nezahrnují tuto příponu – použijte updateBook a deleteBook, ne updateBook_by_pk nebo deleteBook_by_pk.
Důležité
Mutace GraphQL vyžadují aktivní připojení k databázi. Pokud se váš připojovací řetězec nastaví Pooling=False nebo MultipleActiveResultSets=False, mutace selžou s chybou Implicit distributed transactions have not been enabled. Nastavte Pooling=True a MultipleActiveResultSets=True (SQL Server) nebo ekvivalent vašeho poskytovatele databáze.
Návod
Pro uložené procedury zpřístupněné prostřednictvím GraphQL předpony DAB název entity pomocí execute. Například entita nazvaná uložená procedura GetBookById se ve schématu stává executeGetBookById. Další informace najdete v tématu Uložené procedury.
Vytvoření nového záznamu
create K přidání nové položky použijte mutaci.
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);
}
Aktualizovat existující záznam
update Pomocí změtování můžete upravit konkrétní pole u existující položky.
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);
}
Odstranění záznamu
delete Pomocí mutaci odeberte položku podle primárního klíče.
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);
}