Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Eine einzelne Veranstaltung per Identifier abfragen

Eine einzelne Veranstaltung per Identifier abfragen

~7 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026

Für eine Detailseite reicht die Listen-Query aus den Kapiteln 12-14 nicht - sie bräuchte einen künstlichen Filter auf genau einen Datensatz und würde trotzdem die komplette Events-Wrapper-Struktur mit page_info zurückgeben. Sauberer ist eine eigene, dedizierte Einzel-Query, die direkt einen Event liefert.

Die Query im Schema

app/code/Mironsoft/Event/etc/schema.graphqls
type Query {
    event(
        identifier: String!
    ): Event
        @resolver(class: "Mironsoft\\Event\\Model\\Resolver\\Event")
        @doc(description: "Returns a single event by its unique identifier")
}

identifier: String! ist bewusst als Pflichtargument deklariert (Kapitel 7) - eine Einzelabfrage ohne Identifier ergibt fachlich keinen Sinn. Der Rückgabetyp Event selbst bleibt dagegen nullable: existiert keine passende Veranstaltung, liefert die Query null statt eines Fehlers - dazu gleich mehr.

Den Resolver implementieren

app/code/Mironsoft/Event/Model/Resolver/Event.php
<?php

declare(strict_types=1);

namespace Mironsoft\Event\Model\Resolver;

use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Mironsoft\Event\Api\EventRepositoryInterface;

/**
 * Resolves the event query field.
 */
class Event implements ResolverInterface
{
    /**
     * @param EventRepositoryInterface $eventRepository Service contract for event access
     */
    public function __construct(
        private readonly EventRepositoryInterface $eventRepository,
    ) {
    }

    /**
     * Loads a single event by its identifier argument.
     *
     * @param Field $field Resolved GraphQL field configuration
     * @param mixed $context Resolver context
     * @param ResolveInfo $info GraphQL resolve tree info
     * @param array|null $value Parent resolver's value, unused for a top-level field
     * @param array|null $args Arguments passed to the event field
     * @return array<string, mixed>
     * @throws GraphQlNoSuchEntityException
     */
    public function resolve(
        Field $field,
        $context,
        ResolveInfo $info,
        ?array $value = null,
        ?array $args = null
    ): array {
        $identifier = (string) ($args['identifier'] ?? '');

        try {
            $event = $this->eventRepository->getByIdentifier($identifier);
        } catch (NoSuchEntityException $exception) {
            throw new GraphQlNoSuchEntityException(
                __('No event found with identifier "%1".', $identifier),
                $exception
            );
        }

        return [
            'event_id' => $event->getEventId(),
            'identifier' => $event->getIdentifier(),
            'title' => $event->getTitle(),
            'description' => $event->getDescription(),
            'location' => $event->getLocation(),
            'start_at' => $event->getStartAt(),
            'end_at' => $event->getEndAt(),
            'capacity' => $event->getCapacity(),
            'model' => $event,
        ];
    }
}

GraphQlNoSuchEntityException - Kapitel 19 vertieft die komplette Familie der GraphQL-Exceptions - übersetzt die interne NoSuchEntityException des Repositories in eine für GraphQL-Clients sinnvolle Fehlerantwort mit einer eigenen category, statt eines nackten, technischen PHP-Fehlers.

Warum hier keine eigene DataProvider-Klasse?

Anders als bei Events (Kapitel 13) bleibt die Logik hier bewusst direkt im Resolver - ein einzelner Repository-Aufruf plus Array-Mapping ist schlicht zu wenig eigenständige Logik, um eine separate Klasse zu rechtfertigen. Die DataProvider-Konvention ist kein Selbstzweck: Sie lohnt sich, sobald mehrere Argumente in SearchCriteria übersetzt werden müssen (wie in Kapitel 13-14), nicht bei jedem noch so kleinen Resolver.

query {
  event(identifier: "magento-graphql-meetup-berlin") {
    title
    location
    start_at
    end_at
  }
}

Tipp: Ein Identifier statt einer numerischen ID als öffentliches Argument zu verwenden (wie hier, analog zu url_key bei Produkten/Kategorien) verhindert, dass Clients auf interne, fortlaufende Datenbank-IDs angewiesen sind - IDs bleiben ein internes Implementierungsdetail, der Identifier ist die stabile, öffentliche Adresse einer Veranstaltung.

Achtung: Eine leere Zeichenkette als identifier-Argument wird von GraphQL selbst nicht abgefangen - String! verlangt nur, dass überhaupt ein String übergeben wird, nicht, dass er nicht leer ist. Der Resolver muss diesen fachlichen Randfall selbst behandeln, hier implizit über getByIdentifier(''), das ebenfalls in NoSuchEntityException und damit in eine saubere GraphQL-Fehlerantwort mündet.

Mit Liste, Filter/Sortierung und Einzelabfrage ist Block 4 abgeschlossen - die Veranstaltungen-API kann vollständig gelesen werden. Block 5 ergänzt Schreibzugriff: Mutations und Authentifizierung.