GraphQL är det nya modeordet inom API-utveckling. Även om RESTful API: er fortfarande är det mest populära sättet att exponera data från applikationer, så rymmer de många begränsningar som GraphQL vill lösa.
GraphQL är ett sökfrågespråk som skapades av Facebook och som omvandlades till ett projekt med öppen källkod år 2015. Det erbjuder en intuitiv och flexibel syntax för att beskriva och komma åt data i ett API.
Den här guiden kommer att undersöka hur man bygger ett GraphQL node.js-projekt. Vi kommer att använda GraphQL för att bygga en Todo-applikation i webbramverket Express.js för Node.
Vad är GraphQL?
Det står i den officiella dokumentationen: ”GraphQL är ett sökfrågespråk för API: er och en körtid för att uppfylla dessa frågor med dina befintliga data. GraphQL ger en fullständig och begriplig beskrivning av data i ditt API, ger kunderna möjlighet att endast fråga efter exakt vad de behöver, gör det lättare att utveckla API: er över tiden och möjliggör kraftfulla utvecklarverktyg.”
GraphQL är en serverbaserad körtid för att utföra sökfrågor med hjälp av det typsystem som du har definierat för dina data. GraphQL är inte heller bundet till någon specifik databas eller lagringsmotor. Den stöds istället av din befintliga kod och datalagret. Du kan få en detaljerad jämförelse av dessa tekniker i guiden GraphQL vs. RESTful API.
För att skapa en GraphQL-tjänst så börjar du med att definiera schematyper och skapa fält som använder dessa typer. Därefter så tillhandahåller du en funktions-resolver som ska utföras på varje fält och typ när data begärs av klientsidan.
Terminologi för GraphQL
GraphQL-typsystemet används för att beskriva vilka data som kan frågas ut och vilka data som du kan manipulera. Det är kärnan i GraphQL. Låt oss diskutera olika sätt att beskriva och manipulera data i GraphQL.
Objekttyper
GraphQL-objekttyper är datamodeller som innehåller starkt typade fält. Det bör finnas en 1 till 1-mappning mellan dina modeller och GraphQL-typerna. Nedan finns ett exempel på en GraphQL-typ:
type User {
id: ID! # The "!" means required
firstname: String
lastname: String
email: String
username: String
todos: [Todo] # Todo is another GraphQL type
}
Sökfrågor
GraphQL Query definierar alla sökfrågor som en klient kan köra på GraphQL API. Du bör definiera en RootQuery
som inkluderar alla befintliga sökfrågor enligt konventionen.
Nedan definierar och mappar vi frågorna till motsvarande 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
}
Mutationer
Om GraphQL-förfrågningar är GET
-förfrågningar så är mutationerna POST
, PUT
, PATCH
och DELETE
-förfrågningar som manipulerar GraphQL API.
Vi kommer att placera alla mutationer i en enda RootMutation
för att demonstrera detta:
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
}
Du har noterat användningen av -input
-typer för mutationerna, t.ex. UserInput
, TodoInput
. Det är alltid bäst att alltid definiera Input-typer för att skapa och uppdatera dina resurser.
Du kan definiera inmatningstyperna på följande sätt:
input UserInput {
firstname: String!
lastname: String
email: String!
username: String!
}
Resolvers
Resolvers talar om för GraphQL vad de ska göra när varje sökfråga eller mutation begärs. Det är en grundläggande funktion som gör det hårda arbetet med att slå på databaslagret för att göra CRUD-operationer (skapa, läsa, uppdatera, ta bort), slå på en intern RESTful API-slutpunkt eller anropa en mikrotjänst för att uppfylla klientens begäran.
Du kan skapa en ny resolvers.js-fil och lägga till följande 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
}
}
Schema
GraphQL-schema är det som GraphQL exponerar för världen. Av den anledningen så kommer typer, sökfrågor och mutationer att ingå i schemat för att exponeras för världen.
Nedan beskrivs hur man exponerar typer, sökfrågor och mutationer för världen:
schema {
query: RootQuery
mutation: RootMutation
}
I ovanstående skript så har vi inkluderat RootQuery
och RootMutation
som vi skapade tidigare för att de ska exponeras för omvärlden.
Hur fungerar GraphQL med Node.js och Express.js?
GraphQL tillhandahåller en implementering för alla större programmeringsspråk, och Node.js är inte undantaget. På den officiella GraphQL-webbplatsen så finns det en sektion för JavaScript-stöd, och det finns även andra implementeringar av GraphQL för att göra det enkelt att skriva och koda.
GraphQL Apollo tillhandahåller en implementering för Node.js och Express.js och gör det enkelt att komma igång med GraphQL.
Inästa avsnitt så kommer du att lära dig hur du skapar och utvecklar din första GraphQL-applikation i Node.js och Express.js backend-ramverk med hjälp av GraphQL Apollo.
Konfigurera GraphQL med Express.js
Att bygga en GraphQL API-server med Express.js är enkelt. I det här avsnittet så kommer vi att utforska hur man bygger en GraphQL-server.
Initialisera projektet med Express
Först så måste du installera och ställa in ett nytt Express.js-projekt. Skapa en mapp för ditt projekt och installera Express.js med det här kommandot:
cd <project-name> && npm init -y
npm install express
Kommandot ovan skapar en ny package.json-fil och installerar Express.js-biblioteket i ditt projekt.
Därefter så strukturerar vi vårt projekt enligt bilden nedan. Det kommer att innehålla olika moduler för projektets funktioner som t.ex. användare, todos osv.
Initialisera GraphQL
Låt oss börja med att installera GraphQL Express.js-beroendena. Kör följande kommando för att installera:
npm install apollo-server-express graphql @graphql-tools/schema --save
Skapa scheman och typer
Därefter så ska vi skapa en index.js-fil i mappen modules och lägga till följande kodutdrag:
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;
Kodgenomgång
Vi går igenom kodutdraget och bryter ner det:
Steg 1
Först så importerade vi de nödvändiga biblioteken och skapade standardtyper för sökfrågor och mutationer. Förfrågan och mutationen anger för tillfället bara versionen av GraphQL API :et. Vi kommer dock att utöka förfrågan och mutationen för att inkludera andra scheman allteftersom vi fortsätter.
Steg 2:
Därefter så skapade vi en ny skalär typ för tid och vår första resolver för den sökfråga och mutation som skapats ovan. Vi genererade dessutom även ett schema med hjälp av funktionen makeExecutableSchema
.
Det genererade schemat inkluderar alla andra scheman som vi importerade och kommer även att innehålla fler när vi skapar och importerar dem.
Ovanstående kodutdrag visar att vi importerade olika scheman till funktionen makeExecutableSchema. Detta tillvägagångssätt hjälper oss att strukturera applikationen för komplexitet. Därefter så ska vi skapa de Todo- och User-scheman som vi importerade.
Skapa Todo-schema
Todo-schemat visar enkla CRUD-operationer som applikationens användare kan utföra. Nedan visas schemat som implementerar Todo CRUD-operationen.
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 };
Genomgång av koden
Låt oss gå igenom kodutdraget och bryta ner det:
Steg 1:
Först så skapade vi ett schema för vår Todo med hjälp av GraphQL type
, input
och extend
. Nyckelordet extend
används för att ärva och lägga till nya sökfrågor och mutationer till den befintliga rotfrågan och mutationen som vi skapade ovan.
Steg 2:
Därefter så skapade vi en resolver, som används för att hämta rätt data när en viss sökfråga eller mutation anropas.
Med resolver-funktionen på plats så kan vi skapa enskilda metoder för affärslogiken och databasmanipulationen som visas i exemplet create-todo.js.
Skapa filen create-user.js i mappen ./mutations/
och lägg till affärslogiken för att skapa en ny Todo i din databas.
const models = require('../../../models');
module.exports = async (root, { input }, context) => {
return models.todos.push({ ...input });
};
Kodutdraget ovan är ett förenklat sätt att skapa en ny Todo i vår databas med hjälp av Sequelize ORM. Du kan läsa mer om Sequelize och hur du konfigurerar det med Node.js.
Du kan följa samma steg för att skapa många scheman beroende på din applikation eller så kan du klona hela projektet från GitHub.
Därefter så ska vi konfigurera servern med Express.js och köra den nyskapade Todo-applikationen med GraphQL och Node.js.
Konfigurera och köra servern
Slutligen så ska vi konfigurera vår server med hjälp av biblioteket apollo-server-express
som vi installerade tidigare.
apollo-server-express
är en enkel wrapper av Apollo Server för Express.js, Den rekommenderas eftersom den har utvecklats för att passa i Express.js-utveckling.
Med hjälp av de exempel som vi diskuterade ovan så ska vi konfigurera Express.js-servern så att den fungerar med det nyinstallerade apollo-server-express
.
Skapa en server.js-fil i rotkatalogen och klistra in följande 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`)
);
I koden ovan så har du framgångsrikt skapat din första CRUD GraphQL-server för Todos och Users. Du kan starta din utvecklingsserver och få tillgång till denna med hjälp av http://localhost:3000/graphql. Om allt har lyckats så bör du se skärmen nedan:
Sammanfattning
GraphQL är en modern teknik som stöds av Facebook och som förenklar det tråkiga arbetet med att skapa storskaliga API: er med RESTful-arkitekturmönster.
Den här guiden har förklarat GraphQL och visat hur man utvecklar sitt första GraphQL API med Express.js.
Låt oss veta vad du bygger med hjälp av GraphQL i kommentarerna nedan.
Lämna ett svar