Budowanie interfejsów API GraphQL za pomocą Node

Opublikowany: 2022-12-20

GraphQL to nowe modne słowo w rozwoju API. Chociaż interfejsy API RESTful pozostają najpopularniejszym sposobem udostępniania danych z aplikacji, wiążą się one z wieloma ograniczeniami, które GraphQL ma na celu rozwiązać.

GraphQL to język zapytań stworzony przez Facebooka, który w 2015 roku został przekształcony w projekt typu open source. Oferuje intuicyjną i elastyczną składnię do opisywania i uzyskiwania dostępu do danych w interfejsie API.

W tym przewodniku dowiesz się, jak zbudować projekt GraphQL Node.js. Użyjemy GraphQL do zbudowania aplikacji Todo w frameworku internetowym Express.js dla Node.

Co to jest GraphQL?

Z oficjalnej dokumentacji: „GraphQL to język zapytań dla interfejsów API i środowisko wykonawcze do wypełniania tych zapytań za pomocą istniejących danych. GraphQL zapewnia pełny i zrozumiały opis danych w twoim API, daje klientom możliwość zadawania pytań dokładnie o to, czego potrzebują i nic więcej, ułatwia ewolucję API w czasie i udostępnia potężne narzędzia programistyczne.”

GraphQL to środowisko uruchomieniowe po stronie serwera do wykonywania zapytań przy użyciu systemu typów, który zdefiniowałeś dla swoich danych. Ponadto GraphQL nie jest powiązany z żadną konkretną bazą danych ani silnikiem pamięci masowej. Zamiast tego jest wspierany przez istniejący magazyn kodu i danych. Możesz uzyskać szczegółowe porównanie tych technologii z przewodnikiem GraphQL vs. RESTful API.

Aby utworzyć usługę GraphQL, zacznij od zdefiniowania typów schematów i utworzenia pól przy użyciu tych typów. Następnie udostępniasz narzędzie do rozpoznawania funkcji, które ma być wykonywane na każdym polu i wpisywać, ilekroć po stronie klienta zażądają danych.

Terminologia GraphQL

System typu GraphQL służy do opisywania, jakie dane można przeszukiwać i jakimi danymi można manipulować. Jest to rdzeń GraphQL. Omówmy różne sposoby opisywania danych i manipulowania nimi w GraphQ.

typy

Typy obiektów GraphQL to modele danych zawierające silnie wpisane pola. Powinno istnieć mapowanie 1 do 1 między Twoimi modelami a typami GraphQL. Poniżej znajduje się przykład typu GraphQL:

 type User { id: ID! # The "!" means required firstname: String lastname: String email: String username: String todos: [Todo] # Todo is another GraphQL type }

Zapytania

GraphQL Query definiuje wszystkie zapytania, które klient może uruchomić w GraphQL API. Powinieneś zdefiniować RootQuery , który będzie zawierał wszystkie istniejące zapytania zgodnie z konwencją.

Poniżej definiujemy i mapujemy zapytania do odpowiedniego RESTful API:

 type RootQuery { user(id: ID): User # Corresponds to GET /api/users/:id users: [User] # Corresponds to GET /api/users todo(id: ID!): Todo # Corresponds to GET /api/todos/:id todos: [Todo] # Corresponds to GET /api/todos }

Mutacje

Jeśli zapytania GraphQL są żądaniami GET , mutacje to żądania POST , PUT , PATCH i DELETE , które manipulują interfejsem API GraphQL.

Umieścimy wszystkie mutacje w jednym RootMutation , aby zademonstrować:

 type RootMutation { createUser(input: UserInput!): User # Corresponds to POST /api/users updateUser(id: ID!, input: UserInput!): User # Corresponds to PATCH /api/users removeUser(id: ID!): User # Corresponds to DELETE /api/users createTodo(input: TodoInput!): Todo updateTodo(id: ID!, input: TodoInput!): Todo removeTodo(id: ID!): Todo }

Zauważyłeś użycie typów -input dla mutacji, takich jak UserInput , TodoInput . Najlepszą praktyką jest zawsze definiowanie typów danych wejściowych do tworzenia i aktualizowania zasobów.

Możesz zdefiniować typy I nput, takie jak ten poniżej:

 input UserInput { firstname: String! lastname: String email: String! username: String! }

resolwery

Resolwery mówią GraphQL, co ma zrobić, gdy wymagane jest każde zapytanie lub mutacja. Jest to podstawowa funkcja, która wykonuje ciężką pracę polegającą na uderzeniu w warstwę bazy danych w celu wykonania operacji CRUD (tworzenie, odczytywanie, aktualizowanie, usuwanie), uderzaniu w wewnętrzny punkt końcowy interfejsu API RESTful lub wywoływaniu mikrousługi w celu spełnienia żądania klienta.

Możesz utworzyć nowy plik resolvers.js i dodać następujący kod:

 import sequelize from '../models'; export default function resolvers () { const models = sequelize.models; return { // Resolvers for Queries RootQuery: { user (root, { id }, context) { return models.User.findById(id, context); }, users (root, args, context) { return models.User.findAll({}, context); } }, User: { todos (user) { return user.getTodos(); } }, } // Resolvers for Mutations RootMutation: { createUser (root, { input }, context) { return models.User.create(input, context); }, updateUser (root, { id, input }, context) { return models.User.update(input, { ...context, where: { id } }); }, removeUser (root, { id }, context) { return models.User.destroy(input, { ...context, where: { id } }); }, // ... Resolvers for Todos go here } }; }

Schemat

Schemat GraphQL jest tym, co GraphQL ujawnia światu. W związku z tym typy, zapytania i mutacje zostaną uwzględnione w schemacie, który zostanie udostępniony światu.

Poniżej pokazano, jak ujawnić światu typy, zapytania i mutacje:

 schema { query: RootQuery mutation: RootMutation }

W powyższym skrypcie uwzględniliśmy RootQuery i RootMutation , które stworzyliśmy wcześniej, aby były widoczne dla świata.

Jak GraphQL współpracuje z Nodejs i Expressjs

GraphQL zapewnia implementację dla wszystkich głównych języków programowania, a Node.js nie jest zwolniony. Na oficjalnej stronie GraphQL znajduje się sekcja poświęcona obsłudze JavaScript, a także inne implementacje GraphQL ułatwiające pisanie i kodowanie w GraphQL.

GraphQL Apollo zapewnia implementację Node.js i Express.js i ułatwia rozpoczęcie pracy z GraphQL.

W następnej sekcji dowiesz się, jak stworzyć i rozwinąć swoją pierwszą aplikację GraphQL w frameworku zaplecza Nodes.js i Express.js przy użyciu GraphQL Apollo.

Konfiguracja GraphQL z Express.js

Tworzenie serwera API GraphQL za pomocą Express.js jest łatwe do rozpoczęcia. W tej sekcji zbadamy, jak zbudować serwer GraphQL.

Zainicjuj projekt za pomocą Express

Najpierw musisz zainstalować i skonfigurować nowy projekt Express.js.

Utwórz folder dla swojego projektu i zainstaluj Express.js za pomocą tego polecenia:

 cd <project-name> && npm init -y npm install express

Powyższe polecenie tworzy nowy plik package.json i instaluje bibliotekę Express.js w twoim projekcie.

Następnie zorganizujemy nasz projekt, jak pokazano na poniższym obrazku. Będzie zawierał różne moduły dla funkcji projektu, takich jak użytkownicy, todos itp.

Lista plików w graphql-todo.
Pliki dla graphql-todo .

Zainicjuj GraphQL

Zacznijmy od zainstalowania zależności GraphQL Express.js. Uruchom następujące polecenie, aby zainstalować:

 npm install apollo-server-express graphql @graphql-tools/schema --save

Tworzenie schematów i typów

Następnie utworzymy plik index.js w folderze modułów i dodamy następujący fragment kodu:

 const { gql } = require('apollo-server-express'); const users = require('./users'); const todos = require('./todos'); const { GraphQLScalarType } = require('graphql'); const { makeExecutableSchema } = require('@graphql-tools/schema'); const typeDefs = gql` scalar Time type Query { getVersion: String! } type Mutation { version: String! } `; const timeScalar = new GraphQLScalarType({ name: 'Time', description: 'Time custom scalar type', serialize: (value) => value, }); const resolvers = { Time: timeScalar, Query: { getVersion: () => `v1`, }, }; const schema = makeExecutableSchema({ typeDefs: [typeDefs, users.typeDefs, todos.typeDefs], resolvers: [resolvers, users.resolvers, todos.resolvers], }); module.exports = schema;

Przewodnik po kodzie

Przeanalizujmy fragment kodu i podzielmy go:

Krok 1

Najpierw zaimportowaliśmy wymagane biblioteki i utworzyliśmy domyślne typy zapytań i mutacji. Zapytanie i mutacja ustawiają na razie tylko wersję API GraphQL. Jednak w miarę postępów będziemy rozszerzać kwerendę i mutację, aby obejmowały inne schematy.

Interfejs wiersza poleceń pokazujący kod „const” do importowania GraphQL i innych rozszerzeń.
Importowanie GraphQL i rozszerzeń.
Krok 2:

Następnie stworzyliśmy nowy typ skalarny dla czasu i nasz pierwszy tłumacz dla utworzonego powyżej zapytania i mutacji. Ponadto wygenerowaliśmy również schemat za pomocą funkcji makeExecutableEchema .

Wygenerowany schemat zawiera wszystkie inne zaimportowane przez nas schematy i będzie zawierał więcej, gdy je utworzymy i zaimportujemy.

Zmagasz się z przestojami i problemami z WordPressem? Kinsta to rozwiązanie hostingowe zaprojektowane, aby zaoszczędzić Twój czas! Sprawdź nasze funkcje
Interfejs wiersza poleceń pokazujący kod „const” do tworzenia naszego typu skalarnego i naszego pierwszego programu tłumaczącego.
Tworzenie typu skalarnego dla czasu oraz naszego pierwszego resolvera.

Powyższy fragment kodu pokazuje, że zaimportowaliśmy różne schematy do funkcji makeExecutableEchema. Takie podejście pomaga nam w konstruowaniu aplikacji pod kątem złożoności. Następnie utworzymy zaimportowane schematy Todo i User.

Tworzenie schematu zadań

Schemat Todo przedstawia proste operacje CRUD, które mogą wykonywać użytkownicy aplikacji. Poniżej znajduje się schemat implementujący operację Todo CRUD.

 const { gql } = require('apollo-server-express'); const createTodo = require('./mutations/create-todo'); const updateTodo = require('./mutations/update-todo'); const removeTodo = require('./mutations/delete-todo'); const todo = require('./queries/todo'); const todos = require('./queries/todos'); const typeDefs = gql` type Todo { id: ID! title: String description: String user: User } input CreateTodoInput { title: String! description: String isCompleted: Boolean } input UpdateTodoInput { title: String description: String isCompleted: Boolean } extend type Query { todo(id: ID): Todo! todos: [Todo!] } extend type Mutation { createTodo(input: CreateTodoInput!): Todo updateTodo(id: ID!, input: UpdateTodoInput!): Todo removeTodo(id: ID!): Todo } `; // Provide resolver functions for your schema fields const resolvers = { // Resolvers for Queries Query: { todo, todos, }, // Resolvers for Mutations Mutation: { createTodo, updateTodo, removeTodo, }, }; module.exports = { typeDefs, resolvers };

Przewodnik po kodzie

Przeanalizujmy fragment kodu i podzielmy go:

Krok 1:

Najpierw stworzyliśmy schemat dla naszego Todo, używając GraphQL type , input i extend . Słowo kluczowe extend służy do dziedziczenia i dodawania nowych zapytań i mutacji do istniejącego zapytania głównego i mutacji, które utworzyliśmy powyżej.

Interfejs wiersza poleceń przedstawiający schemat naszego skryptu Todo, w tym nowe dane wejściowe.
Tworzenie schematu dla naszego Todo.
Krok 2:

Następnie stworzyliśmy resolver, który służy do pobierania poprawnych danych, gdy wywoływane jest określone zapytanie lub mutacja.

Interfejs wiersza poleceń pokazujący kod do utworzenia narzędzia rozpoznawania nazw dla naszego Todo.
Tworzenie resolwera.

Mając uruchomioną funkcję resolvera, możemy tworzyć indywidualne metody dla logiki biznesowej i manipulacji bazą danych, jak pokazano w przykładzie create-todo.js .

Utwórz plik create-user.js w folderze <code>./mutations</code> i dodaj logikę biznesową, aby utworzyć nowe Todo w swojej bazie danych.

 const models = require('../../../models'); module.exports = async (root, { input }, context) => { return models.todos.push({ ...input }); };

Powyższy fragment kodu to uproszczony sposób tworzenia nowego Todo w naszej bazie danych przy użyciu Sequelize ORM. Możesz dowiedzieć się więcej o Sequelize i jak to skonfigurować za pomocą Node.js.

Możesz wykonać ten sam krok, aby utworzyć wiele schematów w zależności od aplikacji lub sklonować cały projekt z GitHub.

Następnie skonfigurujemy serwer z Express.js i uruchomimy nowo utworzoną aplikację Todo z GraphQL i Node.js

Konfiguracja i uruchamianie serwera

Na koniec skonfigurujemy nasz serwer przy użyciu biblioteki apollo-server-express , którą wcześniej zainstalowaliśmy i skonfigurujemy.

Apollo -server-express to proste opakowanie serwera Apollo dla Express.js. Jest zalecane, ponieważ zostało opracowane tak, aby pasowało do rozwoju Express.js.

Korzystając z przykładów, które omówiliśmy powyżej, skonfigurujmy serwer Express.js do pracy z nowo zainstalowanym apollo-server-express .

Utwórz plik server.js w katalogu głównym i wklej następujący kod:

 const express = require('express'); const { ApolloServer } = require('apollo-server-express'); const schema = require('./modules'); const app = express(); async function startServer() { const server = new ApolloServer({ schema }); await server.start(); server.applyMiddleware({ app }); } startServer(); app.listen({ port: 3000 }, () => console.log(`Server ready at http://localhost:3000`) );

W powyższym kodzie pomyślnie utworzyłeś swój pierwszy serwer CRUD GraphQL dla Todos i Users. Możesz uruchomić swój serwer programistyczny i uzyskać dostęp do placu zabaw za pomocą http://localhost:3000/graphql. Jeśli wszystko się powiedzie, powinieneś zobaczyć poniższy ekran:

Interfejs deweloperski przedstawiający proste zapytanie w odpowiedzi.
Ekran weryfikacji.

Streszczenie

GraphQL to nowoczesna technologia wspierana przez Facebooka, która upraszcza żmudną pracę związaną z tworzeniem wielkoskalowych interfejsów API z wykorzystaniem wzorców architektonicznych RESTful.

Ten przewodnik wyjaśnił GraphQL i pokazał, jak opracować swój pierwszy interfejs API GraphQL za pomocą Express.js.

Daj nam znać, co budujesz za pomocą GraphQL.