Mit GraphQL-Endpunkten im Daten-API-Generator (DAB) können Sie Daten präzise abfragen und ändern.
Jede Abfrage definiert genau, welche Felder Sie benötigen, und unterstützt Argumente zum Filtern, Sortieren und zur Paginierung der Ergebnisse.
Standardmäßig hosten DAB ihren GraphQL-Endpunkt unter:
https://{base_url}/graphql
Entitäten, die über die Konfiguration verfügbar gemacht werden, werden automatisch im GraphQL-Schema enthalten.
Wenn Sie beispielsweise über books und authors Entitäten verfügen, werden beide als Stammfelder im Schema angezeigt.
Hinweis
Um die Schema- und Autovervollständigen-Felder zu erkunden, verwenden Sie einen beliebigen modernen GraphQL-Client oder eine IDE (wie Apollo, Insomnia oder die Visual Studio Code GraphQL-Erweiterung).
Im Daten-API-Generator unterstützte Schlüsselwörter
| Konzept |
GraphQL |
Purpose |
| Projektion |
Elemente |
Auswählen der zurückzugebenden Felder |
| Filterung |
Filter |
Einschränken von Zeilen nach Bedingung |
| Sortieren |
orderBy |
Definieren der Sortierreihenfolge |
| Seitengröße |
erste |
Einschränken der Elemente pro Seite |
| Fortsetzung |
nach |
Weiter von der letzten Seite |
Grundstruktur
Jede GraphQL-Abfrage beginnt mit einem Stammfeld, das eine Entität darstellt.
Alle GraphQL-Anfragen werden an den POST-Endpunkt gesendet, wobei ein JSON-Textkörper verwendet wird, der die Abfrage enthält/graphql.
{
books {
items {
id
title
year
pages
}
}
}
Die Antwort ist ein JSON-Objekt mit derselben Form wie der Auswahlsatz.
Paginierungs- und Fehlerdetails werden nur angezeigt, wenn zutreffend.
Hinweis
Standardmäßig gibt DAB bis zu 100 Elemente pro Abfrage zurück, sofern nicht anders konfiguriert (runtime.pagination.default-page-size).
POST https://localhost:5001/graphql
Content-Type: application/json
{
"query": "{ books { items { id title year pages } } }"
}
Erfolg:
{
"data": {
"books": {
"items": [
{ "id": 1, "title": "Dune", "year": 1965, "pages": 412 },
{ "id": 2, "title": "Foundation", "year": 1951, "pages": 255 }
]
}
}
}
Erfolg mit Paginierung:
{
"data": {
"books": {
"items": [
{ "id": 1, "title": "Dune", "year": 1965, "pages": 412 },
{ "id": 2, "title": "Foundation", "year": 1951, "pages": 255 }
],
"hasNextPage": true,
"endCursor": "eyJpZCI6Mn0="
}
}
}
Fehler:
{
"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 } } }"}'
Die folgenden Modellklassen deserialisieren die DAB GraphQL-Antworten:
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; }
}
Rufen Sie die API auf, und deserialisieren Sie die Antwort:
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 ?? [];
}
Die folgenden Datenklassen modellieren DAB-GraphQL-Antworten.
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
Rufen Sie die API auf, und analysieren Sie die Antwort:
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]
Die folgende Funktion ruft die GraphQL-API auf:
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 ?? [];
}
Beispielverwendung:
const books = await getBooks("https://localhost:5001");
console.log(`Fetched ${books.length} books from the API.`);
Abfragetypen
Jede Entität unterstützt zwei Standardstammabfragen:
| Abfrage |
Beschreibung |
entity_by_pk |
Gibt einen Datensatz anhand des Primärschlüssels zurück. |
entities |
Gibt eine Liste von Datensätzen zurück, die Mit Filtern übereinstimmen |
Beispiel für die Rückgabe eines Datensatzes:
{
book_by_pk(id: 1010) {
title
year
}
}
Beispiel, in dem viele zurückgegeben werden:
{
books {
items {
id
title
}
}
}
Filterergebnisse
Verwenden Sie das filter Argument, um einzuschränken, welche Datensätze zurückgegeben werden.
{
books(filter: { title: { contains: "Foundation" } }) {
items { id title }
}
}
Diese Abfrage gibt alle Bücher zurück, deren Titel "Foundation" enthält.
Filter können Vergleiche mit logischen Operatoren kombinieren:
{
authors(filter: {
or: [
{ first_name: { eq: "Isaac" } }
{ last_name: { eq: "Asimov" } }
]
}) {
items { first_name last_name }
}
}
Weitere Informationen finden Sie in der Filterargumentreferenz für unterstützte Operatoren wie eq, neq, lt, lte, und isNull.
Sortieren von Ergebnissen
Das orderBy Argument definiert, wie Datensätze sortiert werden.
{
books(orderBy: { year: DESC, title: ASC }) {
items { id title year }
}
}
Dies gibt Bücher zurück, die nach year absteigend sortiert sind, dann nach title.
Weitere Informationen finden Sie in der OrderBy-Argumentreferenz.
Einschränken der Ergebnisse
Das first Argument begrenzt, wie viele Datensätze in einer einzelnen Anforderung zurückgegeben werden.
{
books(first: 5) {
items { id title }
}
}
Dadurch werden die ersten fünf Bücher zurückgegeben, die standardmäßig nach Primärschlüssel sortiert sind.
Sie können auch first: -1 verwenden, um die konfigurierte maximale Seitengröße anzufordern.
Weitere Informationen finden Sie in der ersten Argumentreferenz.
Fortlaufende Ergebnisse
Verwenden Sie zum Abrufen der nächsten Seite das after Argument mit dem Cursor aus der vorherigen Abfrage.
{
books(first: 5, after: "eyJpZCI6NX0=") {
items { id title }
}
}
Das after Token kennzeichnet, wo die vorherige Seite beendet wurde.
Weitere Informationen finden Sie in der Nachargumentreferenz.
Feldauswahl (Projektion)
In GraphQL wählen Sie genau aus, welche Felder in der Antwort angezeigt werden.
Es gibt keine Wildcard wie SELECT *. Fordern Sie nur das an, was Sie benötigen.
{
books {
items { id title price }
}
}
Sie können auch Aliase verwenden, um Felder in der Antwort umzubenennen:
{
books {
items {
bookTitle: title
cost: price
}
}
}
Ausführliche Informationen finden Sie in der Feldprojektionsreferenz.
Ändern von Daten
Mit GraphQL-Mutationen können Sie Datensätze je nach Entitätsberechtigungen erstellen, aktualisieren und löschen.
| Mutation |
Action |
createEntity |
Erstellen eines neuen Elements |
updateEntity |
Aktualisieren eines vorhandenen Elements |
deleteEntity |
Entfernen eines Elements |
Hinweis
Das _by_pk Suffix gilt nur für Abfragen (z. B book_by_pk. ). Mutationsnamen enthalten dieses Suffix nicht – verwenden updateBook und deleteBooknicht updateBook_by_pk oder deleteBook_by_pk.
Von Bedeutung
GraphQL-Mutationen erfordern einen aktiven Datenbankverbindungspool. Wenn Ihre Verbindungszeichenfolge Pooling=False oder MultipleActiveResultSets=False festlegt, schlagen Änderungen mit dem Fehler Implicit distributed transactions have not been enabled fehl. Legen Sie Pooling=True und MultipleActiveResultSets=True (SQL Server) oder die Entsprechung für Ihren Datenbankanbieter fest.
Tipp
Für gespeicherte Prozeduren, die über GraphQL verfügbar gemacht werden, präfixt DAB den Entitätsnamen mit execute. Eine gespeicherte Prozedur-Entität mit dem Namen GetBookById wird im Schema zu executeGetBookById. Weitere Informationen finden Sie unter gespeicherten Prozeduren.
Neuen Datensatz erstellen
Verwenden Sie eine create Mutation, um ein neues Element hinzuzufügen.
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);
}
Vorhandenen Datensatz aktualisieren
Verwenden Sie eine update Mutation, um bestimmte Felder für ein vorhandenes Element zu ändern.
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);
}
Löschen eines Datensatzes
Verwenden Sie eine delete Mutation, um ein Element nach Primärschlüssel zu entfernen.
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);
}