In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly explains the "Node.js build GraphQL API method tutorial", the article explains the content is simple and clear, easy to learn and understand, now please follow the editor's train of thought slowly in depth, together to study and learn "Node.js build GraphQL API method tutorial"!
In the traditional REST-based API approach, the client makes a request and the server decides to respond:
Curl https://api.heroku.space/users/1 {"id": 1, "name": "Luke", "email": "luke@heroku.space", "addresses": [{"street": "1234 Rodeo Drive", "city": "Los Angeles", "country": "USA"}]}
However, in GraphQL, the client can determine exactly what data it gets from the server. For example, the client might only need a user name and email, but not any address information:
Curl-X POST https://api.heroku.space/graphql-d'query {user (id: 1) {name email}} {"data": {"name": "Luke", "email": "luke@heroku.space"}}
With this new model, customers can meet their needs by reducing the response, thus querying the server more efficiently. For single-page applications (SPA) or other front-end heavy client applications, you can speed up rendering time by reducing the payload size. However, like any framework or language, GraphQL requires trade-offs. In this article, we will explore the pros and cons of using GraphQL as a query language for API, and how to start building the implementation.
Why choose GraphQL?
As with any technical decision, it's important to know what advantages GraphQL offers to your project, rather than choosing it simply because it's a buzzword.
Consider a SaaS application that uses API to connect to a remote database. If you want to render the user's profile page, you may need to make an API GET call to get information about the user, such as a user name or email. You may then need to make another API call to get information about the address, which is stored in another table. As the application evolves, you may need to continue to make more API calls to different locations because of the way it is built. Although each API call can be done asynchronously, you must also handle their responses, whether it's an error, a network timeout, or even pause page rendering until all the data is received. As mentioned above, the payload of these responses may exceed the need to render your current page, and there is a network delay for each API call, and the total delay can be significant.
With GraphQL, instead of making multiple API calls (such as GET / user/:id and GET / user/:id/addresses), you make an API call and submit the query to a single endpoint:
Query {user (id: 1) {name email addresses {street city country}
GraphQL then provides only one endpoint to query all the required domain logic. If your application grows, you will find yourself adding more data stores to your architecture-PostgreSQL may be a good place to store user information, and Redis may be a good place to store other kinds of information-a call to GraphQL endpoints will address all these different locations and respond to the client with the data they request.
GraphQL is also useful here if you are unsure of the requirements of your application and how to store data in the future. To modify the query, you simply add the name of the desired field:
Addresses {street + apartmentNumber # new information city country}
This greatly simplifies the process of developing your application over time.
Define a GraphQL schema
There are GraphQL server implementations in various programming languages, but before you start, you need to identify objects in your business domain, just like any API. Just as REST API might use JSON schemas, GraphQL uses SDL or Schema definition language to define its schemas, which is an idempotent way to describe all the objects and fields available to GraphQL API. The general format of the SDL entry is as follows:
Type $OBJECT_TYPE {$FIELD_NAME ($ARGUMENTS): $FIELD_TYPE}
Let's define what the entries for user and address look like based on the previous example.
Type User {name: String email: String addresses: [Address]} type Address {street: String city: String country: String}
User defines two String fields, name and email, and it also includes a field called addresses, which is an array of Addresses objects. Addresses also defines several of its own fields. (by the way, the GraphQL schema has not only objects, fields, and scalar types, but more, and you can also merge interfaces, unions, and parameters to build more complex models, which are not covered in this article.)
We also need to define a type, which is the entry point for our GraphQL API. You remember, as we said earlier, the GraphQL query looks like this:
Query {user (id: 1) {name email}}
This query field belongs to a special reserved type, called Query, which specifies the main entry point to get the object. (there is also the Mutation type used to modify objects.) Here, we define a user field that returns a User object, so our schema needs to define this field as well:
Type Query {user (id: Int!): User} type User {...} type Address {...}
The parameters in the field are a comma-separated list of parameters in the format $NAME: $TYPE. ! The GraphQL indicates that the parameter is required and omitted to indicate that it is optional.
The process of merging this pattern into the server varies depending on the language you choose, but in general, using the information as a string is sufficient. Node.js has the graphql [2] package to prepare the GraphQL pattern, but we will use the graphql-tools [3] package instead, because it provides some more benefits. Let's import the package and read our type definitions to prepare for future development:
Const fs = require ('fs') const {makeExecutableSchema} = require ("graphql-tools"); let typeDefs = fs.readFileSync ("schema.graphql", {encoding: "utf8", flag: "r",})
Set up the parser
Schema sets the way queries are built, but building a schema to define a data model is only part of the GraphQL specification. The other part involves actually getting data, which is done by using a parser, which is a function that returns the base value of a field.
Let's take a look at how to implement a parser in Node.js. Our goal is to consolidate the concept around how the parser works with the schema, so we won't go into too much detail around how to set up the data store. In the "real world", we might use something like knex [4] to establish a database connection. Now, let's set up some virtual data:
Const users = {1: {name: "Luke", email: "luke@heroku.space", addresses: [{street: "1234 Rodeo Drive", city: "Los Angeles", country: "USA",},],}, 2: {name: "Jane", email: "jane@heroku.space" Addresses: [{street: "1234 Lincoln Place", city: "Brooklyn", country: "USA",}
The GraphQL parser in Node.js is equivalent to an Object,key that is the name of the field to retrieve, and value is the function that returns the data. Let's start with a simple example of an initial user lookup by id:
Const resolvers = {Query: {user: function (parent, {id}) {/ / user lookup logic},},}
This parser requires two parameters: an object that represents the parent (which was usually unused in the initial root query), and a JSON object that contains the parameters passed to your field. Not every field has parameters, but in this case, we will have parameters because we need to retrieve their users through the user ID. The rest of the function is simple:
Const resolvers = {Query: {user: function (_, {id}) {return users [id];},}}
You'll notice that we don't clearly define a parser for User or Addresses, and the graphql-tools package is smart enough to automatically map these for us. We can override these if we choose, but now that we have defined our type definition and parser, we can build our complete schema:
Const schema = makeExecutableSchema ({typeDefs, resolvers})
Run the server
Finally, let's run this demo! Because we are using Express, we can use the express-graphql [5] package to expose our schema as an endpoint. The package requires two parameters: schema and root value, which has an optional parameter graphiql, which we will discuss later.
Use GraphQL middleware to set up the Express server on your favorite port, as follows:
Const express = require ("express"); const express_graphql = require ("express-graphql"); const app = express (); app.use ("/ graphql", express_graphql ({schema: schema, graphiql: true,}); app.listen (5000, () = > console.log ("Express is now live at localhost:5000"))
Navigate the browser to http://localhost:5000/graphql and you should see an IDE interface. In the left pane, you can enter any valid GraphQL query you want, and on the right you will get the results.
This is what graphiql: true provides: a convenient way to test your query, which you may not want to expose in a production environment, but it makes testing much easier.
Try entering the query shown above:
Query {user (id: 1) {name email}}
To explore the typing capabilities of GraphQL, try passing a string instead of an integer for the ID parameter.
# this doesn't work. Query {user (id: "1") {name email}}
You can even try to request fields that don't exist:
# this doesn't work. Query {user (id: 1) {name zodiac}}
With only a few clear lines of code expressed in schema, a strongly typed contract can be established between the client and the server. This prevents your service from receiving false data and clearly indicates the error to the requester.
Performance consideration
Although GraphQL solves a lot of problems for you, it doesn't solve all the problems inherent in building API. Caching and authorization, in particular, just need some scenarios to prevent performance problems. The GraphQL specification does not provide any guidance for implementing these two methods, which means that the responsibility for building them falls on you.
Caching
REST-based API does not need to be cached because they can be built on top of existing HTTP header policies used by the rest of the web. GraphQL does not have these caching mechanisms, which can impose an unnecessary processing burden on duplicate requests. Consider the following two queries:
Query {user (id: 1) {name}} query {user (id: 1) {email}}
In the absence of some kind of cache, just to retrieve two different columns causes two database queries to get the User with ID 1. In fact, because GraphQL also allows aliases, the following query is valid and performs two lookups:
Query {one: user (id: 1) {name} two: user (id: 2) {name}}
The second example exposes the problem of how to batch queries. To be fast and efficient, we want GraphQL to access the same database rows with as few round trips as possible.
The dataloader [6] package is designed to solve these two problems. Given an array of ID, we will fetch all of these ID; from the database at once. Similarly, subsequent calls to the same ID will fetch the item from the cache. To use dataloader to build this, we need two things. First, we need a function to load all the requested objects. In our example, it looks like this:
Const DataLoader = require ('dataloader'); const batchGetUserById = async (ids) = > {/ / in real life, this would be a database call to return ids.map (id = > users [id]);}; / / userLoader is now our "bulk load function" const userLoader = new DataLoader (batchGetUserById)
This solves the problem of batch processing. To load the data and use the cache, we will replace the previous data lookup with a call to the load method and pass in our user ID:
Const resolvers = {Query: {user: function (_, {id}) {return userLoader.load (id);},},}
Authorization
For GraphQL, authorization is a completely different issue. In short, it is the process of identifying whether a given user has the right to view certain data. We can imagine a scenario where authenticated users can execute queries to get their own address information, but should not be able to get other users' addresses.
To solve this problem, we need to modify the parser function. In addition to the parameters of the field, the parser can access its parent node, as well as the special context values passed in that provide information about the currently authenticated user. Because we know that the address is a sensitive field, we need to modify our code so that the call to the user not only returns a list of addresses, but actually invokes some business logic to validate the request:
Const getAddresses = function (currUser, user) {if (currUser.id = = user.id) {return user.addresses} return [];} const resolvers = {Query: {user: function (_, {id}) {return users [id];},}, User: {addresses: function (parentObj, {}, context) {return getAddresses (context.currUser, parentObj);},},}
Again, instead of explicitly defining a resolver for each User field, we just need to define a resolver that we want to modify.
By default, express-graphql passes the current HTTP request as the value of the context, but you can change it when you set up the server:
App.use ("/ graphql", express_graphql ({schema: schema, graphiql: true, context: {currUser: user / / current authenticated user}}))
Schema best practices
One aspect missing from the GraphQL specification is the lack of guidance on versioning patterns. As applications grow and change, their API changes, and it is likely that GraphQL fields and objects need to be deleted or modified. But this disadvantage is also positive: by carefully designing your GraphQL schema, you can avoid obvious pitfalls in REST endpoints that are easier to implement (and more likely to break), such as naming inconsistencies and messy relationships.
In addition, you should try to separate business logic from parser logic. Your business logic should be a single source of fact for the entire application. It is tempting to perform validation checks in the parser, but as the pattern grows, it becomes a strategy that is difficult to maintain.
When is the wrong time for GraphQL?
GraphQL cannot meet the needs of HTTP communications as accurately as REST. For example, GraphQL specifies only one status code, 200 OK, regardless of whether the query is successful or not. A special error key is returned in this response for the client to parse and identify the error, so error handling can be tricky.
Again, GraphQL is just a specification, and it doesn't automatically solve every problem your application faces. Performance problems won't go away, database queries won't get any faster, and in general, you need to rethink everything about your API: authorization, logging, monitoring, caching. Versioning your GraphQL API can also be a challenge because the official specification currently does not support handling changes in interrupts, which is an inevitable part of building any software. If you are interested in exploring GraphQL, you need to invest some time to learn how to best integrate it with your needs.
Thank you for reading, the above is the content of "Node.js build GraphQL API method tutorial". After the study of this article, I believe you have a deeper understanding of the problem of Node.js building GraphQL API method tutorial, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.