安全なNode.jsGraphQLAPIを作成する方法
公開: 2022-03-11この記事では、安全なNode.jsGraphQLAPIを作成する方法に関するクイックガイドを紹介することを目的としています。
頭に浮かぶかもしれないいくつかの質問は次のとおりです。
- GraphQL APIを使用する目的は何ですか?
- GraphQL APIとは何ですか?
- GraphQLクエリとは何ですか?
- GraphQLの利点は何ですか?
- GraphQLはRESTよりも優れていますか?
- なぜNode.jsを使用するのですか?
これらはすべて有効な質問ですが、答える前に、Web開発の現在の状態の概要を簡単に説明する必要があります。
- 今日見られるほとんどすべてのソリューションは、ある種のアプリケーションプログラミングインターフェイス(API)を使用しています。
- FacebookやInstagramなどのソーシャルネットワークを使用している場合でも、APIを使用するフロントエンドに接続されています。
- 興味がある場合は、Netflix、Spotify、YouTubeなどのサービスを含め、ほとんどすべてのオンラインエンターテインメントサービスが異なる種類のAPIを使用していることに気付くでしょう。
事実上すべてのシナリオで、詳細に知る必要のないAPIが見つかります。たとえば、APIがどのように構築されたかを知る必要はなく、以前と同じテクノロジーを使用する必要もありません。それをあなた自身のシステムに統合することができます。 提供されるAPIを使用すると、特定のテクノロジースタックに依存することなく、サービスとクライアントの両方が通信できる共通の標準でサービス間で通信する方法を提供できます。
適切に構造化されたAPIを使用すると、複数の種類のクライアントとフロントエンドアプリケーションにサービスを提供できる、堅牢で保守可能でスケーラブルなAPIを使用できます。
そうは言っても、GraphQL APIとは何ですか?
GraphQLはAPIのクエリ言語であり、Facebookで内部使用するために開発され、2015年に公開されました。読み取り、書き込み、およびリアルタイムの更新をサポートします。 また、オープンソースであり、一般的にRESTや他のアーキテクチャと比較されます。 一言で言えば、これは以下に基づいています。
- GraphQLクエリ-これにより、クライアントはデータの受信方法を読み取って操作できます。
- GraphQL Mutations-これは、サーバーにデータを書き込む方法です。 これは、システムにデータを書き込む方法に関するGraphQLの規則です。
この記事は、GraphQL APIを構築して使用する方法について、シンプルでありながら実際のシナリオを示すことを目的としていますが、GraphQLの詳細な紹介は提供しません。 GraphQLチームが包括的なドキュメントを提供し、GraphQLの概要にいくつかのベストプラクティスをリストしているため、理由は単純です。
GraphQLクエリとは何ですか?
前に説明したように、クエリは、クライアントがAPIからデータを読み取って操作できる方法です。 オブジェクトのタイプを渡し、受け取るフィールドの種類を選択できます。 簡単なクエリは次のようになります。
query{ users{ firstName, lastName } }
このクエリでは、ユーザーのスキーマからすべてのユーザーにリーチしようとしていますが、 firstName
とlastName
のみを受け取ります。 このクエリの結果は、次のようになります。
{ "data": { "users": [ { "firstName": "Marcos", "lastName": "Silva" }, { "firstName": "Paulo", "lastName": "Silva" } ] } }
クライアントでの使用は非常に簡単です。
GraphQL APIを使用する目的は何ですか?
APIを作成する目的は、他の外部サービスと統合できるサービスとしてソフトウェアを使用できるようにすることです。 アプリケーションが単一のフロントエンドによって消費されている場合でも、このフロントエンドを外部サービスと見なすことができます。そのため、2つの間の通信がAPIを介して提供されると、さまざまなプロジェクトで作業できるようになります。
大規模なチームで作業する場合は、分割してフロントエンドチームとバックエンドチームを作成し、両方が同じテクノロジーを使用して作業を容易にすることができます。 APIを設計するときは、プロジェクトにより適したものと、目的のソリューションに近づくものを選択することが重要です。
この記事では、GraphQLを使用するAPIを構築するためのスケルトンに焦点を当てます。
GraphQLはRESTよりも優れていますか?
それはちょっとした取り締まりかもしれませんが、私はそれを助けることはできません:それは依存します。
GraphQLは、いくつかのシナリオに非常によく適合するアプローチです。 RESTは、いくつかのシナリオでも実証されているアーキテクチャアプローチです。 今日では、なぜ一方が他方より優れているのか、またはGraphQLの代わりにRESTのみを使用する必要があるのかを説明する記事がたくさんあります。 また、GraphQLを内部で使用し、APIのエンドポイントをRESTベースのアーキテクチャとして維持できる多くの方法もあります。
最善のガイダンスは、各アプローチの利点を理解し、作成しているソリューションを分析し、チームがソリューションをどの程度快適に使用しているかを評価し、チームが学習して理解できるように指導できるかどうかを評価することです。アプローチを選択する前に速くスピードを上げてください。
この記事は、GraphQLとRESTの主観的な比較というよりも、実用的なガイドです。 2つの詳細な比較を読みたい場合は、別の記事の1つであるGraphQLとREST-GraphQLチュートリアルを確認することをお勧めします。
今日の記事では、Node.jsを使用したGraphQLAPIの作成に焦点を当てます。
なぜNode.jsを使用するのですか?
GraphQLには、使用できるいくつかの異なるライブラリがあります。 この記事の目的のために、Node.jsでJavaScriptを使用するというアイデアを採用することにしました。これは、JavaScriptが広く使用されており、Node.jsを使用すると、開発者がサーバー側の開発に使い慣れたフロントエンド構文を使用できるためです。
また、RESTベースのAPIを使用したアプローチと比較することも役立ちます。これは、別のToptalEngineeringブログの記事「Node.jsでの安全なRESTAPIの作成」で示されているものと似ています。 この記事では、Node.jsをExpressで使用して、これら2つのアプローチの違いを比較できるスケルトンRESTAPIを開発する方法も紹介します。 Node.jsは、スケーラブルなネットワークアプリケーション、グローバルコミュニティ、およびnpmWebサイトにあるいくつかのオープンソースライブラリを使用して設計されました。
今回は、GraphQL、Node.js、Expressを使用してスケルトンAPIを構築する方法を紹介します。
GraphQLチュートリアルの実践
前に概説したように、GraphQL APIのスケルトンのアイデアを構築します。先に進む前に、Node.jsとExpressの基本を理解する必要があります。 このGraphQLの例のために作成されたプロジェクトのソースコードは、こちらから入手できます。
2種類のリソースを処理します。
- 基本的なCRUDを処理するユーザー。
- GraphQLのパワーをさらに示すために、少し詳しく説明する製品。
ユーザーには、次の構造が含まれます。
- id
- ファーストネーム
- 苗字
- Eメール
- パスワード
- パーミッションレベル
製品には次の構造が含まれます。
- id
- 名前
- 説明
- 価格
コーディング標準については、このプロジェクトではTypeScriptを使用します。 ソースファイルでは、TypeScriptでコーディングを開始するためにすべてを構成できます。
コーディングしましょう!
まず、最新のNode.jsバージョンがインストールされていることを確認してください。 公開時点では、Nodejs.orgによると、現在のバージョンは10.15.3です。
プロジェクトの初期化
node-graphql
という名前の新しいフォルダーから始めましょう。 そこで、ターミナルまたはGit CLIコンソールを開き、次のコマンドを使用してマジックを開始できます: npm init
。
依存関係とTypeScriptの構成
プロセスを高速化するには、Gitリポジトリでpackage.json
を次のものに置き換えると、必要なすべての依存関係が含まれている必要があります。
{ "name": "node-graphql", "version": "1.0.0", "description": "", "main": "dist/index.js", "scripts": { "tsc": "tsc", "start": "npm run tsc && node ./build/app.js" }, "author": "", "license": "ISC", "dependencies": { "@types/express": "^4.16.1", "@types/express-graphql": "^0.6.2", "@types/graphql": "^14.0.7", "express": "^4.16.4", "express-graphql": "^0.7.1", "graphql": "^14.1.1", "graphql-tools": "^4.0.4" }, "devDependencies": { "tslint": "^5.14.0", "typescript": "^3.3.4000" } }
更新されたpackage.json
を使用して、ターミナルをもう一度押して、 npm install
を使用します。 Node.jsおよびExpress内でこのGraphQLAPIを実行するために必要なすべての依存関係をインストールします。
次の部分は、TypeScriptモードを構成することです。 ルートフォルダに次のtsconfig.json
というファイルが必要です。
{ "compilerOptions": { "target": "ES2016", "module": "commonjs", "outDir": "./build", "strict": true, "esModuleInterop": true } }
この構成のコードのロジックは、appフォルダーにあります。 そこでapp.ts
ファイルを作成し、基本的なテストのために次のコードをそこに追加します。
console.log('Hello Graphql Node API tutorial');
これで、 npm start
を実行してビルドを待機し、すべてが正しく機能していることをテストできるようになりました。 ターミナルコンソールに、「Hello GraphQLNodeAPIチュートリアル」が表示されます。 バックシーンでは、構成は基本的にTypeScriptコードを純粋なJavaScriptにコンパイルしてから、 build
フォルダーでビルドを実行します。
それでは、GraphQLAPIの基本的なスケルトンを構成しましょう。 プロジェクトを開始するために、3つの基本的なインポートを追加します。
- 特急
- Express-graphql
- Graphql-ツール
それをすべてまとめ始めましょう:
import express from 'express'; import graphqlHTTP from 'express-graphql'; import {makeExecutableSchema} from 'graphql-tools';
これで、少しコーディングを開始できるはずです。 次のステップは、Expressでアプリを処理し、次のような基本的なGraphQL構成を処理することです。
import express from 'express'; import graphqlHTTP from 'express-graphql'; import {makeExecutableSchema} from 'graphql-tools'; const app: express.Application = express(); const port = 3000; let typeDefs: any = [` type Query { hello: String } type Mutation { hello(message: String) : String } `]; let helloMessage: String = 'World!'; let resolvers = { Query: { hello: () => helloMessage }, Mutation: { hello: (_: any, helloData: any) => { helloMessage = helloData.message; return helloMessage; } } }; app.use( '/graphql', graphqlHTTP({ schema: makeExecutableSchema({typeDefs, resolvers}), graphiql: true }) ); app.listen(port, () => console.log(`Node Graphql API listening on port ${port}!`));
私たちがしていることは:

- Expressサーバーアプリのポート3000を有効にします。
- 簡単な例として使用するクエリとミューテーションを定義します。
- クエリとミューテーションがどのように機能するかを定義します。
OK、しかしtypeDefとリゾルバー、そしてクエリとミューテーションとの関係はどうなっているのでしょうか?
- typeDefs-クエリとミューテーションから期待できるもののスキーマの定義。
- リゾルバー-フィールドや必須パラメーターの期待値の代わりに、ここでは、クエリとミューテーションがどのように機能するかについての関数と動作を定義します。
- クエリ-サーバーから読み取りたい「gets」。
- ミューテーション-自分のサーバーにあるデータに影響を与えるリクエスト。
それでは、 npm startをもう一度実行して、そこに何があるかを確認しましょう。 アプリは次のメッセージで実行されると予想されます。ポート3000でリッスンしているNodeGraphqlAPI!
これで、http:// localhost:3000/graphqlを介して独自のサーバーでGraphQLAPIのクエリとテストを試みることができます。
これで、「hello」として定義された最初の独自のクエリを作成できます。
typeDefs
で定義した方法で、このページはクエリの作成に役立つことに注意してください。
それは素晴らしいことですが、どうすれば値を変更できますか? 突然変異!
ここで、メモリ内の値を変更して変更するとどうなるかを見てみましょう。
これで、GraphQLNode.jsAPIを使用して基本的なCRUD操作を実行できます。 それでは、コードを進めましょう。
製品
製品については、productsというモジュールを使用します。 この記事を簡略化するために、デモンストレーションのためだけにインメモリデータベースを使用します。 製品を管理するためのモデルとサービスを定義します。
私たちのモデルは次のように基づいています:
export class Product { private id: Number = 0; private name: String = ''; private description: String = ''; private price: Number = 0; constructor(productId: Number, productName: String, productDescription: String, price: Number) { this.id = productId; this.name = productName; this.description = productDescription; this.price = price; } }
GraphQLと通信するサービスは、次のように定義されます。
export class ProductsService { public products: any = []; configTypeDefs() { let typeDefs = ` type Product { name: String, description: String, id: Int, price: Int } `; typeDefs += ` extend type Query { products: [Product] } `; typeDefs += ` extend type Mutation { product(name:String, id:Int, description: String, price: Int): Product! }`; return typeDefs; } configResolvers(resolvers: any) { resolvers.Query.products = () => { return this.products; }; resolvers.Mutation.product = (_: any, product: any) => { this.products.push(product); return product; }; } }
ユーザー
ユーザーの場合、製品モジュールと同じ構造に従います。 ユーザー向けのモデルとサービスを用意します。 モデルは次のように定義されます。
export class User { private id: Number = 0; private firstName: String = ''; private lastName: String = ''; private email: String = ''; private password: String = ''; private permissionLevel: Number = 1; constructor(id: Number, firstName: String, lastName: String, email: String, password: String, permissionLevel: Number) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.email = email; this.password = password; this.permissionLevel = permissionLevel; } }
その間、私たちのサービスは次のようになります:
const crypto = require('crypto'); export class UsersService { public users: any = []; configTypeDefs() { let typeDefs = ` type User { firstName: String, lastName: String, id: Int, password: String, permissionLevel: Int, email: String } `; typeDefs += ` extend type Query { users: [User] } `; typeDefs += ` extend type Mutation { user(firstName:String, lastName: String, password: String, permissionLevel: Int, email: String, id:Int): User! }`; return typeDefs; } configResolvers(resolvers: any) { resolvers.Query.users = () => { return this.users; }; resolvers.Mutation.user = (_: any, user: any) => { let salt = crypto.randomBytes(16).toString('base64'); let hash = crypto.createHmac('sha512', salt).update(user.password).digest("base64"); user.password = hash; this.users.push(user); return user; }; } }
念のため、このリンクからソースコードを使用できます。
これで、コードを再生してテストできます。 npm start
を実行してみましょう。 サーバーはポート3000で実行されます。これで、http:// localhost:3000/graphqlでテスト用のGraphQLにアクセスできます。
ミューテーションを試して、商品リストにアイテムを追加してみましょう。
それが機能したかどうかをテストするために、製品のクエリを使用しますが、 id
、 name
、 price
のみを受け取ります。
query{ products{ id, name, price } } The response will be: { "data": { "products": [ { "id": 100, "name": "My amazing product", "price": 400 } ] } }
以上です; 製品は期待どおりに機能しています。 これで、必要に応じてフィールドを再生したり切り替えたりできます。 説明を追加してみてください。
query{ products{ id, name, description, price } }
これで、製品の説明を取得できます。 今すぐユーザーを試してみましょう。
mutation{ user(id:200, firstName:"Marcos", lastName:"Silva", password:"amaz1ingP4ss", permissionLevel:9, email:"[email protected]") { id } }
そして、クエリは次のようになります。
query{ users{ id, firstName, lastName, password, email } }
次のような応答で:
{ "data": { "users": [ { "id": 200, "firstName": "Marcos", "lastName": "Silva", "password": "kpj6Mq0tGChGbZ+BT9Nw6RMCLReZEPPyBCaUS3X23lZwCCp1Ogb94/oqJlya0xOBdgEbUwqRSuZRjZGhCzLdeQ==", "email": "[email protected]" } ] } }
これで、GraphQLスケルトンの準備が整いました。 ここから、便利で完全に機能するAPIに向けて多くのステップがありますが、基本的なコアが設定されました。
まとめと最終的な考え
短縮するための最先端でさえ、この記事は非常に大きく、GraphQLNode.jsAPIの開発に関する多くの基本的な情報が含まれています。
これまでに取り上げた内容を確認しましょう。
- ExpressおよびGraphQLでNode.jsを使用して、GraphQLAPIを構築します。
- 基本的なGraphQLの使用;
- クエリとミューテーションの基本的な使用法。
- プロジェクトのモジュールを作成するための基本的なアプローチ。
- GraphQLAPIをテストします。
物事の開発面にさらに焦点を当てるために、次のように簡単に要約できるいくつかの重要な項目を避けました。
- 新しいアイテムの検証。
- 一般的なエラーサービスでエラーを適切に処理します。
- ユーザーが汎用サービスを使用して各リクエストで使用できるフィールドを検証します。
- APIを保護するためにJWTインターセプターを追加します。
- より効果的なアプローチでパスワードハッシュを処理します。
- ユニットテストと統合テストを追加します。
このGitリンクに完全なソースコードがあることを忘れないでください。 気軽に使用して、フォークして、問題を開いて、プルリクエストを作成して、それで遊んでください! この記事で行われたすべての基準と提案が石に刻まれているわけではないことに注意してください。
これは、独自のGraphQLAPIの設計を開始するために使用できる多くのアプローチの1つにすぎません。 また、GraphQLを読んで詳しく調べ、GraphQLが提供するものと、APIをさらに改善する方法を学びましょう。