В тази статия ще обсъдим как можем да използваме GraphQL, докато изграждаме просто приложение MERN stack. Ще изградим много основно приложение, за да си играем с потребителски данни, и ще използваме GraphQL за заявки на данните от страната на сървъра към страната на клиента. За да поддържаме нещата прости и подредени, ще предприемем следните мерки –

  • Няма да се фокусираме върху частта UI на приложението. Това ще ни помогне да поддържаме кода кратък и прост. Това ще помогне на начинаещите да се съсредоточат само върху най-важното, вместо върху частта от потребителския интерфейс.
  • Ще разделим тази статия на 2 части, така че концепциите от страна на сървъра да могат да бъдат обхванати в една част, а изпълнението от страна на клиента да може да бъде обхванато във втората част.
  • Няма да обсъждаме пълните основи на GraphQL в тази статия, защото вече го разгледахме в предишната. Ако по някакъв начин сте го пропуснали, можете да го прочетете тук. Би било чудесна идея да прегледате тази статия веднъж, ако току-що започвате своето пътуване с GraphQL.
  • Ако искате да проверите крайния продукт, можете да го опитате тук. Това ще ви даде ясна представа какво възнамеряваме да изградим.

Сега, след като всички основни неща сме готови, нека започнем да създаваме приложението.

Приложение за потребители

Първо, ще изградим нашия server.js файл, в който ще поставим нашите основни неща от страната на сървъра.

const express = require("express");
const mongoose = require("mongoose");
const graphqlHTTP = require("express-graphql");
const schema = require("./schema/schema");
const cors = require("cors");
const app = express();
const PORT = 4000;
app.use(cors());

mongoose.connect("YOUR_MONGODB_URI",
{ useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false }, (error) => {
if (!error) {
console.log("MongoDB has been connected!");
} else {
console.log("Error while connecting to MongoDB : ", error);
}
});

app.use("/graphql", graphqlHTTP({
schema: schema,
graphiql: true,
})
);
app.listen(PORT, () => {
console.log(`Server is running at PORT : ${PORT}`);
});

Тук сме -

  • Инициализиране на PORT на 4000.
  • Свързване към MongoDB. Моля, не забравяйте да добавите свой собствен MongoDB uri адрес на мястото на YOUR_MONGODB_URI. Можете да използвате MongoDB Atlas, за да управлявате данните си от тук.
  • Използване на CORS, така че да нямаме проблеми с между платформите, докато правим заявки от страна на клиента.
  • Използване на пакет, наречен express-graphql (Използва се за създаване на GraphQL HTTP сървър с всяка HTTP уеб рамка, която поддържа свързващ стил на междинен софтуер, например Express.js в нашия случай)
  • Настройване на схемата (Тук ще пишем всички наши заявки).
  • Настройването на graphql като true, което ни позволява да използваме GraphQL IDE.

Сега, след като поставихме нашия server.js файл, нека изградим потребителски модел.

const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
userId: String,
name: String,
email: String,
age: Number,
occupation: String,
});
module.exports = mongoose.model("users", userSchema);

Тук изграждаме много основен потребителски модел файл, в който на полетата относно потребителската информация са присвоени подходящи типове данни (например String, Number и т.н.).

Сега ще започнем да работим върху файла schema.js. Това е мястото, където ще пишем всички наши заявки и мутации.

const users = require("../models/model");
const {
GraphQLNonNull,
GraphQLID,
GraphQLInt,
GraphQLString,
GraphQLList,
GraphQLSchema,
GraphQLObjectType,
} = require("graphql");

Тук сме :

  1. Импортиране на потребителския модел, който току-що създадохме.
  2. Импортиране на типовете обекти, които ще използваме за потребителските данни. Например GraphQLID за userId, GraphQLInt за възраст и т.н.

Сега, след като импортирахме типовете обект, нека напишем типа потребител

const userType = new GraphQLObjectType({
name: "Users",
fields: () => ({
userId: { type: GraphQLID },
name: { type: GraphQLString },
email: { type: GraphQLString },
occupation: { type: GraphQLString },
age: { type: GraphQLInt },
}),
});

Тук присвояваме подходящия тип обект на всички свързани с потребителя полета, които ще използваме в това приложение.

Тъй като приключихме с потребителския тип, сега ще напишем RootQuery. Той действа като база за всички останали заявки, които ще се използват.

const RootQuery = new GraphQLObjectType({
name: "Root",
fields: {},
});

В полетата ще пишем заявките.

Запитвания

1. За да извлечете всички потребителски данни

const RootQuery = new GraphQLObjectType({
name: "Root",
fields: {
allUsers: {
type: new GraphQLList(userType),
resolve() {
return users.find({});
},
}
},
});

Тук пишем нашата първа заявка с име allUsers. Пишем тази заявка, за да получим всички потребители и свързаните с тях данни. Тъй като тази заявка ще върне списък от потребители, следователно използваме GraphQLList като тип обект. userType вече е дефиниран от нас по-рано (този, в който задаваме типове обекти за всички свързани с потребителя полета).

2. За да извлечете потребител по ID

const RootQuery = new GraphQLObjectType({
name: "Root",
fields: {
allUsers: {
type: new GraphQLList(userType),
resolve() {
return users.find({});
},
},
findUser: {
type: userType,
args: {
userId: { type: new GraphQLNonNull(GraphQLID) },
},
resolve(parentValue, args) {
return users.findById(args.userId);
},
},
},
});

За да намерим потребител по ID, ние написахме заявка findUser, където userId е направен задължителен (GraphQLNonNull е използван, за да се гарантира че userId не е нула). ID, предоставен от страна на клиента, може да бъде извлечен чрез args, посочени във функцията resolve. Следователно ние търсим и връщаме потребителя въз основа на userId, извлечен от args. Тъй като тази заявка ще върне само данни за един потребител, следователно GraphQLList не е използван в този случай.

Мутации

Сега, след като написахме основните си заявки, ще запишем заявки за мутиране (промяна) на данните. Мутациите основно се наричат ​​манипулиране на данните от страната на сървъра. Нека се потопим и запишем няколко мутации.

1. За да добавите нов потребител

const mutation = new GraphQLObjectType({
name: "mutation",
fields: {
addUser: {
type: userType,
args: {
userId: { type: GraphQLID },
name: { type: new GraphQLNonNull(GraphQLString) },
email: { type: new GraphQLNonNull(GraphQLString) },
occupation: { type: new GraphQLNonNull(GraphQLString) },
age: { type: new GraphQLNonNull(GraphQLInt) },
},
resolve(parentValue, args) {
const user = new users({
name: args.name,
email: args.email,
occupation: args.occupation,
age: args.age,
});
user.userId = user._id;
return new Promise((resolve, reject) => {
user.save((err) => {
if (err) reject(err);
else resolve(user);
});
});
},
},
},
});

Тук написахме нашата първа мутация, наречена addUser. Вътре в args задаваме подходящите типове обекти за всички свързани с потребителя полета и ги задаваме като задължителни, като използваме GraphQLNonNull (Ние не използваме GraphQLNonNull за userId, защото е автоматично генериран от MongoDB). Вътре във функцията за разрешаване ние използваме обещание, така че потребителските данни да се съхраняват, след като идентификаторът, генериран от mongoDB, бъде зададен в полето userId. Съхраняването на идентификатора, зададен от mongodb, в друга променлива като userId ще ни помогне при извършването на други полезни операции, а също така ще опрости нещата за внедряване от страна на клиента.

3. За редактиране на потребителски данни

const mutation = new GraphQLObjectType({
name: "mutation",
fields: {
editUser: {
type: userType,
args: {
userId: { type: new GraphQLNonNull(GraphQLID) },
name: { type: new GraphQLNonNull(GraphQLString) },
email: { type: new GraphQLNonNull(GraphQLString) },
occupation: { type: new GraphQLNonNull(GraphQLString) },
age: { type: new GraphQLNonNull(GraphQLInt) },
},
resolve(parentValue, args) {
return users.findByIdAndUpdate(
args.userId,
{
name: args.name,
email: args.email,
occupation: args.occupation,
age: args.age,
},
{ new: true }
);
},
},
},
});

Тук сме използвали мутация editUser за актуализиране на потребителските данни. Както направихме при предишната мутация (addUser), ние зададохме типове обекти за свързани с потребителя данни в args. Вътре във функцията resolve можем да намерим потребител с помощта на userId от args и да актуализираме данните с помощта на findByIdAndUpdate() на mongoose. (Ако имате нужда от урок относно някаква концепция на mongodb или конкретна заявка, моля, запишете в секцията за коментари).

3. Да изтриете потребител

const mutation = new GraphQLObjectType({
name: "mutation",
fields: {
deleteUser: {
type: userType,
args: {
userId: { type: new GraphQLNonNull(GraphQLID) },
},
resolve(parentValue, args) {
return users.findByIdAndDelete(args.userId);
},
},
},
});

Тук използвахме и наименувахме мутация deleteUser за изтриване на потребителски запис. За разлика от предишната мутация, ние просто дефинираме обектен тип за userId вътре в аргументите, защото не се нуждаем от други данни освен userId. Сега, използвайки findByIdAndDelete(), можем да изтрием потребителя, свързан с предоставения userId.

просто? нали Сега, след като написахме всички заявки, можем да ги тестваме изцяло с помощта на GraphQL IDE. Първо отидете на терминала и натиснете node server.js. Това ще задейства нашия сървър. За достъп до IDE посетете http://localhost:4000/graphql. Вашият GraphQL IDE трябва да изглежда нещо подобно –

Лявата страна е мястото, където ще правим заявките, а дясната страна ще показва отговора. Сега нека започнем да тестваме нашите заявки една по една и да видим дали ще получим желаните резултати.

1. Добавяне на нов потребител

За да започнем да пишем мутация, започваме с ключова дума mutation, последвана от името на заявката, която трябва да използваме. Спомняте ли си, че го нарекохме като addUser? Сега ще поставим нашите данни като параметри, където въвеждаме свързаните с потребителя данни. След това трябва да уточним какви данни трябва да получим като резултат. Тук просто посочваме потребителско име, име и професия. След като приключим с това, трябва да натиснем бутона възпроизвеждане (дясната страна на текста на GraphQL в горния ляв ъгъл).

След като го ударим, получаваме отговора от дясната страна на GraphQL IDE. Тук получаваме данните, които сме посочили в нашата заявка, тоест потребителско име, име и професия. Това е, което отличава GraphQL от REST подхода. Получавате само това, което поискате. Сега можем да отидем и да проверим и данните в нашата колекция mongodb. Ще видим нашите данни така –

Супер лесно, нали? Нека продължим и тестваме заявката за редактиране на потребителски данни. За целта нека копираме userId на току-що създадения обект.

2. Редактиране на потребителски данни

Тук използваме editUser за актуализиране на потребителските данни. Поставете userId в полето userId, което копирахме от отговора на addUser. Сега преименувахме John Doe на John Cena в полето за име. Останалите полета са запазени. Сега натиснете бутона пускане и проверете отговора. Виждаме, че името е актуализирано за userId. Същото може да се провери и в mongodb.

3. Изтриване на потребителски данни

Сега можем да използваме deleteUser за изтриване на потребителските данни. Както можете да видите на снимката, ние просто трябва да посочим userId (надявам се, че все още имате потребителския идентификатор, копиран за потребителя, който създадохме по-рано) и да посочим какви всички данни са ви необходими. Натиснете бутона play и проверете mongodb, сега не можем да видим John Cena! 😉

4. Извлечете всички потребители

Преди да изпълним тази заявка, моля, не забравяйте първо да добавите няколко потребители към базата данни. Използвайки addUser, създайте 2–3 различни потребители, за да можем да тестваме тази заявка.

За разлика от мутациите, не е нужно да пишем нищо преди името на заявката. Можем просто да започнем със скоби и да уточним какви данни са ни необходими. Искаме userId, име и професия на всички потребители в тази заявка. В отговора можете да видите, че получаваме желаните потребителски полета за всички потребители в базата данни. Сега да продължим и да напишем последното си запитване.

5. Извличане на потребител по ID

За да използвате тази заявка, моля, копирайте userId на който и да е потребител от предишния резултат от заявката или можете да копирате и от базата данни.

Тук използваме заявката findUser, за да извлечем потребител по id. Просто трябва да предоставим userId и да посочим какви всички данни трябва да извлечем, свързани с този userId. В отговора можем да видим, че получаваме всички данни, които сме посочили в заявката.

С това завършихме внедряването на сървърната страна на нашето приложение. Тъй като тази статия вече придоби голяма дължина, би било по-разумно да продължите внедряването от страна на клиента в Част 2 на тази статия. В случай, че имате някакви съмнения, въпроси, предложения, моля, не се колебайте да оставите коментар. За да получите пълния изходен код на кода, можете да проверите моето repo в github. Ако харесвате работата ми и смятате, че трябва да продължа да създавам такива опростени уроци, любезно обмислете да ме подкрепите, като дарите на paypal.me/topcoded. Дори малък ваш принос би бил много насърчителен за студенти като мен, които възнамеряват да направят нещата по-прости за другите стипендианти. Ако искате да покрия друга концепция или ако имате обратна връзка, любезно ми напишете коментар в секцията за коментари по-долу. Отново, големи благодарности на всички постоянни читатели и сътрудници, които ме вдъхновяват да продължа да работя. Ще се видим в следващата статия! Дотогава се пазете!