Strapi-Content mit GraphQL einbinden

Salina Körner, 31. Juli 2023
Lesezeit: 10 Minuten

Team-Mitglieder können nun mithilfe des GraphQL-Plugins ganz einfach in unserem Content-Management-System Strapi hinzugefügt werden.

Strapi bietet sowohl REST-Schnittstellen als auch eine GraphQL-Schnittstelle an. Mit REST werden unsere Blogbeiträge (so wie dieser hier) aus dem CMS abgerufen. Die Teambilder wurden bisher manuell im Angular Code gepflegt. Dadurch ist das Einpflegen von Änderungen im Gegensatz zu einer Verwaltung über die CMS-Oberfläche erschwert. Daher kam die Idee auf die Team-Seite alleine über die Strapi Oberfläche zu verwalten. Denn mit GraphQL und Strapi können wir bequem über die GUI neue Mitarbeiter hinzufügen oder entfernen. Zusätzlich können wir nun Entwürfe erstellen, was besonders bei dem regelmäßigen Wechsel an Praktikanten von Vorteil ist.

Was ist GraphQL?

GraphQL ist eine Datenabfragesprache, welche darauf abzielt genau die Daten bereitzustellen, die gebraucht werden. Sie wurde 2012 von Facebook entwickelt und wurde 2015 Open-Source.

In GraphQL wird mit Feldern von Objekten gearbeitet. Diese einzelnen Felder können durch Querys abgefragt oder durch Mutations geändert werden. Dabei werden nur die Felder angefragt, die benötigt werden. In einer Query kann neben einzelnen Feldern, aber auch nach verschachtelten Objekten verlangt werden.

Um zu wissen welche Felder von einem GraphQL-Service angefragt werden können, gibt es das Schema, das alle möglichen Felder und ihre Typen definiert. Dieses wird später mit eingehenden Abfragen abgeglichen, damit auch nur gültige Abfragen ausgeführt werden können.
Da GraphQL unabhängig von der Programmiersprache benutzbar ist, gibt es die GraphQL-Schema-Language, die die Felder und ihre Datentypen beschreibt.

Vorteile von GraphQL

GraphQL hat den Vorteil, dass Overfetching vermieden wird. Overfetching bedeutet, dass mehr Daten nach einer Abfrage zurück kommen, als eigentlich benötigt werden. Dies führt zu einem höheren Verbrauch an Bandbreite als nötig.

So kann man durch GraphQL mit einfachen Querys gezielt die benötigten Daten abfragen. Nicht mehr und nicht weniger. In unserem Fall betrifft das den Namen, die Rolle, die E-Mail und das Bild eines jeweiligen Mitarbeiters.

Außerdem wird die Anzahl an Endpunkten deutlich verringert, da es möglich ist durch einen einzigen Endpunkt auf eine Vielzahl an Daten zuzugreifen.

Umsetzung

Backend – Strapi

Dank der Möglichkeit Plugins im Strapi hinzuzufügen, erfolgt die Integration von GraphQL in das CMS recht unkompliziert. Nach der Installation des GraphQL-Plugins steht bereits ein Playground zur Verfügung, der es ermöglicht Abfragen zu testen.

Im nächsten Schritt geht es darum eine TeamMember-Collection zu erstellen, die die einzelnen Attribute eines Mitarbeiters enthält.

Copy
{
  "kind": "collectionType",
  "collectionName": "team_members",
  "info": {
    "singularName": "team-member",
    "pluralName": "team-members",
    "displayName": "TeamMember",
    "description": ""
  },
  "options": {
    "draftAndPublish": true
  },
  "pluginOptions": {},
  "attributes": {
    "firstName": {
      "type": "string"
    },
    "lastName": {
      "type": "string"
    },
    "email": {
      "type": "email"
    },
    "role": {
      "type": "string"
    },
    "photo": {
      "type": "media",
      "multiple": false,
      "required": false,
      "allowedTypes": [
        "images"
      ]
    }
  }
}

Anhand dieser Collection wird automatisch eine schema.json-Datei erstellt, welche den Collection-Type Mitarbeiter mit entsprechenden Properties und Datentypen widerspiegelt. Das Schema legt fest, welche Daten von der API abgefragt werden können. Einkommende Abfragen werden gegen dieses Schema geprüft, sodass nur valide Abfragen ausgeführt werden.

Frontend

Nachdem das Backend für GraphQL Abfragen vorbereitet wurde, kann nun das Frontend auf die GraphQL API von Strapi angepasst werden. Auch im Angular Umfeld bieten externe Libraries Abhilfe zur Integration von GraphQl.

Durch die Verwendung von Apollo Client und GraphQl-Codegen wird das Anpassen der Team-Komponent auf eine GraphQL Schnittstelle problemlos möglich.

GraphQL – Codegen

Die GraphQL-Codegen ist ein CLI (command-line interface) durch das man basierend auf den Operationen (Querys, Mutations) Code generieren lassen kann. Dabei entsteht ein vollständiger Service mit Datentypen. Das ist besonders praktisch, da durch die automatische Generierung Fehler vermieden werden, die sich in handgeschriebenem Code schnell einschleichen können.

Im Code-Ausschnitt sieht man wie eine Query aufgebaut ist. Sie hat den Namen “teamMembers” und gibt uns alle teamMembers aufsteigend sortiert mit ihren Attributen zurück. Durch die Struktur der Query, kann man genau erkennen welche Felder die Schnittstelle zurückliefert.

Copy
query teamMembers {
  teamMembers(sort: "lastName:asc", pagination: {limit: 25}) {
    data {
      attributes {
        firstName
        lastName
        email
        role
        photo {
          data {
            attributes {
              url
            }
          }
        }
      }
    }
  }
}

Damit wie gewohnt mit Models und Datentypen in Angular gearbeitet werden kann, muss ein Skript erstellt werden, welches mit Hilfe des GraphQL-Code-Generators Datentypen generiert.

In der CodegenConfig-Datei konfigurieren wir in welchem Verzeichnis (hier “src/__generated__ /graphql.ts) unsere Typescript-Typen abgelegt werden sollen, die durch die angegebenen Typescript-Plugin generiert werden. Das wird zu den anderen Skripts der package.json-Datei hinzugefügt. Sobald Änderungen an einer Query erfolgen oder eine neue hinzugefügt wird, ist es nötig dieses Skript auszuführen, sodass die Typen ebenfalls aktualisiert werden. Außerdem enthält die graphql.ts die URL zum Endpunkt der API auf der das Schema liegt.

Copy
const config: CodegenConfig = {
    schema: `${environment.baseUrl}/graphql`,
    documents: ['src/app/graphql/teamMember.graphql'],
    generates: {
        './src/__generated__/graphql.ts': {
            plugins: ['typescript', 'typescript-operations', 'typescript-apollo-angular'],
            presetConfig: {
                gqlTagName: 'gql',
            }
        }
    },
    overwrite: true,
    ignoreNoDocuments: true,
};

Aus der Query von oben wird dieser Type generiert.

Copy
export type TeamMembersQuery = {
    __typename?: 'Query',
    teamMembers?: {
        __typename?: 'TeamMemberEntityResponseCollection',
        data: Array<{
            __typename?: 'TeamMemberEntity',
            attributes?: {
                __typename?: 'TeamMember',
                firstName?: string | null,
                lastName?: string | null,
                email?: string | null,
                role?: string | null,
                photo?: {
                    __typename?: 'UploadFileEntityResponse',
                    data?: {
                        __typename?: 'UploadFileEntity',
                        attributes?: { __typename?: 'UploadFile', url: string } | null
                    } | null
                } | null
            } | null
        }>
    } | null
};

Apollo Client

Apollo Client ist eine Library, die dazu dient Daten mit GraphQL zu verwalten. Sie verfügt über intelligentes Caching, sodass Daten, die schon einmal abgefragt wurden, aus dem Cache und nicht von der API abgerufen werden. Des Weiteren verwaltet Apollo die HTTP-Requests und ihren Lifecycle.

Durch Apollo werden die GraphQL-Operationen per HTTP an die API gesendet. Diese Methode wird im Strapi-Service aufgerufen.

this.teamMembersGQL.fetch();

TeamMembersGQL ist eine Instanz der TeamMembersGQL Klasse, anhand welcher die Query und die dazugehörigen Variablen an die API geschickt werden können.

Copy
@Injectable({
    providedIn: 'root'
})
export class TeamMembersGQL extends Apollo.Query<TeamMembersQuery, TeamMembersQueryVariables> {
    override document = TeamMembersDocument;

    constructor(apollo: Apollo.Apollo) {
        super(apollo);
    }
}

An dieser Stelle können Parameter für die Query festgelegt werden. In unserem Fall werden keine benötigt, da die Query immer alle Teammeber zurückgeben soll. Falls jedoch ein Query für den Abruf einzelner Teammember benötigt wird, könnte hier die Id als Parameter festgelegt werden.

export type TeamMembersQueryVariables = Exact<{ [key: string]: never; }>;

Das ist die Query, die an die API geschickt wird.

Copy
export const TeamMembersDocument = gql`
    query teamMembers {
  teamMembers(sort: "lastName:asc", pagination: {limit: 25}) {
    data {
      attributes {
        firstName
        lastName
        email
        role
        photo {
          data {
            attributes {
              url
            }
          }
        }
      }
    }
  }
}
    `;

Fazit

Die Integration von GraphQL in unsere Website hat uns gezeigt, wie praktisch die Abfragesprache sein kann.
Dadurch dass REST und GraphQL sich nicht gegenseitig ausschließen, konnte die Integration in die bestehende Applikation reibungsfrei ablaufen, sodass keine Änderungen an der restlichen Struktur der Website erforderlich waren.

Durch das Einpflegen der Teammitglieder im Strapi müssen diese nun nicht mehr ausschließlich von Entwicklern verwaltet werden.

author image
Salina Körner
Studentin Informatik, 5. Semester
Durch die Umstellung auf GraphQL konnte ich mich selbständig in die Website einarbeiten und neue Technologien wie Strapi und GraphQl kennenlernen. Außerdem konnte ich hier die gelernten Inhalte aus meinem Praktikum einsetzen.