Express GraphQL이 포함된 CRUD API 예

52834 단어 expresjsgraphqlnodeapi
너는 아마도 나의 이전 댓글을 기억할 것이다. 나는 이미GraphQL을 깊이 연구하기 시작했다.몸소 체험하는 것보다 더 좋은 방법으로 지식을 깊이 있게 하는 것은 무엇입니까?따라서 이 블로그에서 CRUD 조작을 제공하는 GraphQL 서버 API의 실현을 소개하겠습니다.저는 GraphQL의 자바스크립트를 선택하여 GraphQL js 1을 실현했고 ExpressGraphQL 2으로 GraphQL 서버를 설치했습니다.
장면을 더욱 진실하게 하기 위해 GraphQL에서 개발한 API는 기존 REST API을 지원하는 Bookmarks.dev의 집적층을 충당한다.

You can find the source code for the examples in this post on


CodepediaOrg / graphql express 때 묻은 프레젠테이션


graphql express로 작성된 전체 CRUD API


테스트를 위한 데모 항목 구성


테스트를 계속하려면 다음 절차를 따르십시오.

책갈피를 설정합니다.로컬 호스트 RESTAPI 개발


우선 책갈피의 localhost REST api를 설정해야 합니다.개발자: project from Github에 서명한 후 프로젝트의 README 파일에 열거된 절차에 따라 조작합니다.

프로젝트graphql expressjs crud 설치 및 실행


실제 GraphQL 프로젝트를 실행하려면 프로젝트의 README file에 설명된 대로 설정해야 합니다.

GraphiQL 액세스


설정이 완료되면 GraphiQL을 사용하여 GraphQL 쿼리를 입력할 수 있습니다.
가장 좋아하는 브라우저의 http://localhost:4000/graphql URL을 방문하여
다음 몇 절에서는 GraphQL의 주요 요소와 구체적인 예시와 GraphQL js에서의 실현을 소개할 것이다.

패턴


모든GraphQL 서비스는 이 서비스에서 조회할 수 있는 가능한 데이터 집합을 설명하는 그룹 형식을 정의합니다.그리고 조회가 들어갈 때 이 모델에 따라 검증하고 실행됩니다.다음은 가장 흔히 볼 수 있는 유형을 찾을 수 있습니다.

객체 유형 및 필드


GraphQL 모드의 가장 기본적인 구성 요소는 대상 형식입니다. 가져올 수 있는 대상만 표시합니다.
당신의 서비스와 어떤 분야가 있는지.GraphQL 모드 언어에서는 다음과 같이 표현할 수 있습니다.
type Bookmark {
  _id: ID!
  userId: ID!
  public: Boolean
  location: String!
  name: String!
  description: String
  tags: [String!]!
  likeCount: Int
  sourceCodeURL: String
}
이 언어는 가독성이 매우 강하지만, 우리가 복습을 하면 우리는 어휘를 공유할 수 있다.
  • Bookmark은GraphQL의 대상 유형으로 일부 필드가 있는 유형임을 의미한다.모드의 대다수 유형은 대상 유형이다.
  • String, BooleanInt은 일부 내장 표량 유형이다. 이런 유형은 하나의 표량 대상으로 해석되고 조회에서 하위 선택이 있을 수 없다.잠시 후에 우리는 표량 유형을 더욱 토론할 것이다.
  • ID: ID 스칼라 유형은 객체를 재부각하거나 캐시 키로 사용하는 고유 식별자를 나타냅니다.
    ID 유형은 문자열과 동일하게 시리얼화됩니다.그러나 ID로 정의하면 사용자가 읽을 수 없는 것입니다.
  • String!은 이 필드를 비울 수 없음을 나타냅니다. 이것은GraphQL 서비스가 이 필드를 조회할 때 항상 값을 제공하겠다고 약속한 것을 의미합니다.
    유형 언어에서는 이러한 유형을 느낌표로 나타낼 것입니다.
  • [String!]!은 문자열의 대상을 나타내는 수조입니다.이것도 비울 수 없기 때문에, tags 필드를 조회할 때, 항상 하나의 그룹 (0 개 또는 여러 항목 포함) 을 예상할 수 있습니다.String!도 비울 수 없기 때문에, 그룹의 모든 항목이 문자열의 대상이 되기를 기대할 수 있습니다.
  • graphql js의 구현은 다음과 같습니다.
    const Bookmark = new GraphQLObjectType({
        name: "Bookmark",
        fields: {
            _id: {
                type: GraphQLID,
                description: "The id of the bookmark it's generated in MongoDb"
            },
            userId: {
                type:  GraphQLNonNull(GraphQLID),
                description: "The id of the user that created the bookmark"
            },
            public: {
                type: GraphQLBoolean,
                description: "Whether the bookmark is public or not"
            },
            location: {
                type:  GraphQLNonNull(GraphQLString),
                description: "Mostly the URL of the link"
            },
            name: {
                type: GraphQLNonNull(GraphQLString),
                description: "Title of the bookmark"
            },
            description: {
                type: GraphQLString,
                description: "Notes about the bookmark - supports Markdown"
            },
            tags: {
                type:  GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString))),
                description: "Tags are highly used on Bookmarks.dev"
            },
            likeCount: {
                type: GraphQLInt,
                description: "Number of public likes"
            },
            sourceCodeURL: {
                type: GraphQLString,
                description: "Where you can find the source code related to bookmark"
            }
        }
    });
    

    논거


    GraphQL 객체 유형의 각 필드에는 다음 history 필드와 같은 0개 이상의 매개 변수가 있을 수 있습니다.
    type User {
     userId: ID!
     history(last: Int = 5): [Bookmark]
    }
    
    모든 매개변수의 이름이 지정되었습니다.JavaScript와 Python 같은 언어와 달리 함수는 질서정연한 매개 변수 목록을 사용합니다.
    GraphQL의 모든 매개 변수는 이름에 따라 전달됩니다.이 예에서 history 필드에는 정의된 매개 변수 last이 있습니다.
    매개 변수는 필수일 수도 있고 선택할 수도 있다.매개 변수가 선택할 수 있을 때, 우리는 기본값을 정의할 수 있습니다. 만약 last 매개 변수가 통과되지 않으면 기본값을 5로 설정합니다.
    위의 예제에서는 GraphQL js에서 history 객체 섹션의 User 필드를 살펴보았습니다.
    const User = new GraphQLObjectType({
        name: "User",
        fields: {
            userId: {
                type: GraphQLID,
                description: "user identifier - keycloak ID"
            },
            history: {
                type: new GraphQLList(Bookmark),
                description: "Bookmarks the user created, updated or clicked recently",
                args: {
                    last: {
                        type: GraphQLInt,
                        defaultValue: 5,
                        description: "Fetches only *last* bookmarks from history "
                    }
                },
                resolve: async (root, args, context) => {
                    const userId = root.userId;
                    const bearerToken = context.bearerToken;
                    const last = args.last;
                    const response = await bookmarksApiService.getBookmarksOfUserHistory(userId, bearerToken, last);
    
                    return response.body;
                }
            }
        }
    });
    

    Note the resolve method for now, but we'll talk about that later


    열거 유형


    매거 유형도 매거라고 하는데 하나의 특정한 허용 값에만 한정되는 특수한 표량이다.이를 통해 다음을 수행할 수 있습니다.
  • 이 유형의 매개 변수가 허용 값
  • 중 하나인지 확인
  • 은 유형 시스템을 통해 한 필드가 항상 유한 값 집합
  • 중 하나가 된다는 것을 전달한다
    다음은 enum이GraphQL 모드 언어에 정의된 모습입니다.
    enum OrderBy {
      MOST_LIKES
      LAST_CREATED
      MOST_USED
    }
    
    이것은 우리가 모델에서 OrderBy 유형을 사용하든지 간에 우리는 그것이 바로 MOST_LIKES, LAST_CREATED 또는 MOST_USED 중의 하나이기를 바란다.
    Javascript 그래픽 QL에서 열거된 정의는 다음과 같습니다.
    const BookmarkOrderByType = new GraphQLEnumType({
        name: 'OrderBy',
        values: {
            MOST_LIKES: {value: "MOST_LIKES"},
            LAST_CREATED: {value: "LAST_CREATED"},
            MOST_USED: {value: "MOST_USED"}
        }
    });
    

    By using the value parameter we force the serialization to these values.


    -CRUD의 R 조회


    조회는GraphQL의 주요 임무입니다.루트 "Query"객체에서 GraphQL이 제공하는 모드에서 질의를 정의합니다.
    type Query {
        publicBookmarks: [Bookmark]
        user(userId: ID!): [User]
        bookmark(bookmarkId: ID!): [Bookmark]
    }
    
    GraphQL javascript로 변환하기
    const Query = new GraphQLObjectType({
        name: 'Query',
        fields: {
            publicBookmarks: {
                type: new GraphQLList(Bookmark),
                resolve: async (root, args, context, info) => {
                    const response = await bookmarksApiService.getPublicBookmarks();
                    return response.body;
                }
            },
            userFeedBookmarks: {
                type: new GraphQLList(Bookmark),
                resolve: async (root, args, context, info) => {
                    const {userId, bearerToken} = context;
                    const response = await bokmarksApiService.getBookmarksForFeed(userId, bearerToken);
                    return response.body;
                }
            },
            user: {
                type: User,
                args: {
                    userId: {type: GraphQLID}
                },
                resolve: async (root, args, context) => {
                    const bearerToken = context.bearerToken;
                    const {userId} = args;
                    const response = await bookmarksApiService.getUserData(userId, bearerToken);
    
                    return response.body;
                }
            },
            bookmark: {
                type: Bookmark,
                args: {
                    bookmarkId: {type: GraphQLID}
                },
                resolve: async (root, args, context, info) => {
                    const bearerToken = context.bearerToken;
                    const {bookmarkId} = args;
                    const response = await bookmarksApiService.getBookmarkById(userId, bearerToken, bookmarkId);
    
                    return response.body;
                }
            }
        },
    });
    
    이제 클라이언트의 외관을 살펴보자. 예를 들어 책갈피에서 제공하는 아날로그 사용자의 데이터를 받는 것이다.개발자 설정:
    {
     user(userId:"a7908cb5-3b37-4cc1-a751-42f674d870e1") {
        userId,
        profile {
          displayName
          imageUrl
        },
        bookmarks(orderBy:LAST_CREATED) {
          ...bookmarkFields
        },
        feed  {
          ...bookmarkFields
        },
        history {
          ...bookmarkFields
        }
      }
    }
    
    fragment bookmarkFields on Bookmark {
      _id
      name
      location
      tags
      sourceCodeURL
      likeCount
    }
    

    Note the fragment construct - Fragments let you construct sets of fields, and then include them in queries where you need to,
    to not have to repeat yourself.


    응답은 다음과 유사해야 합니다.
    {
      "data": {
        "user": {
          "userId": "a7908cb5-3b37-4cc1-a751-42f674d870e1",
          "profile": {
            "displayName": "Mock",
            "imageUrl": "https://gravatar.com/avatar/bc461041c4caf5493530db7a69d4bf83?s=340"
          },
          "bookmarks": [
            {
              "_id": "5fa8db1897519f34ae94f7e2",
              "name": "Build a CRUD functionality with GraphQL and ExpressJS",
              "location": "https://www.codepedia.org/ama/complete-example-crud-api-express-graphql",
              "tags": [
                "graphql",
                "expressjs",
                "graphql-express",
                "rest",
                "api-design"
              ],
              "sourceCodeURL": "https://github.com/CodepediaOrg/graphql-express-crud-demo",
              "likeCount": null
            },
            {
              "_id": "5e9d4a463b837e57e76de0ae",
              "name": "Getting started with www.bookmarks.dev",
              "location": "https://www.bookmarks.dev/howto",
              "tags": [
                "programming",
                "resource",
                "blog",
                "open-source"
              ],
              "sourceCodeURL": "https://github.com/CodepediaOrg/bookmarks",
              "likeCount": 0
            },
            {
              "_id": "5e9d4a463b837e57e76de0ad",
              "name": "Collection of public dev bookmarks, shared with from www.bookmarks.dev",
              "location": "https://github.com/CodepediaOrg/bookmarks#readme",
              "tags": [
                "programming",
                "resource",
                "blog",
                "open-source"
              ],
              "sourceCodeURL": "https://github.com/CodepediaOrg/bookmarks",
              "likeCount": 0
            },
            {
              "_id": "5e9d4a463b837e57e76de0ac",
              "name": "Bookmarks Manager for Devevelopers & Co",
              "location": "https://www.bookmarks.dev/",
              "tags": [
                "programming",
                "blog",
                "resources",
                "open-source"
              ],
              "sourceCodeURL": "https://github.com/CodepediaOrg/bookmarks.dev",
              "likeCount": 0
            },
            {
              "_id": "5e9d4a463b837e57e76de0ab",
              "name": "Share coding knowledge – CodepediaOrg",
              "location": "https://www.codepedia.org/",
              "tags": [
                "programming",
                "blog",
                "open-source"
              ],
              "sourceCodeURL": "",
              "likeCount": 0
            }
          ],
          "feed": [
            {
              "_id": "5fa8db1897519f34ae94f7e2",
              "name": "Build a CRUD functionality with GraphQL and ExpressJS",
              "location": "https://www.codepedia.org/ama/complete-tutorial-crud-graphql-express",
              "tags": [
                "graphql",
                "expressjs",
                "graphql-express",
                "rest",
                "api-design"
              ],
              "sourceCodeURL": "https://github.com/CodepediaOrg/graphql-express-crud-demo",
              "likeCount": null
            },
            {
              "_id": "5f93b3a51e55b52d7b5d73bd",
              "name": "Issues · BookmarksDev/bookmarks.dev · GitHub",
              "location": "https://github.com/BookmarksDev/bookmarks.dev/issues",
              "tags": [
                "bookmarksdev"
              ],
              "sourceCodeURL": "",
              "likeCount": 0
            }
          ],
          "history": [
            {
              "_id": "5f93b3a51e55b52d7b5d73bd",
              "name": "Issues · BookmarksDev/bookmarks.dev · GitHub",
              "location": "https://github.com/BookmarksDev/bookmarks.dev/issues",
              "tags": [
                "bookmarksdev"
              ],
              "sourceCodeURL": "",
              "likeCount": 0
            }
          ]
        }
      }
    }
    

    파서


    조회 부분에서, 당신은 이미 resolve 방법을 알아차렸을 것입니다.GraphQL 용어에서 이른바 해석기다.모드가 GraphQL API의 구조를 정의한 경우 파서는 API와
    서버의 비헤이비어를 결정합니다.

    Each field in a GraphQL schema is backed by a resolver


    "그 가장 기본적인 형식에서 GraphQL 서버는 패턴의 모든 필드에 해상도 함수를 가지고 있다. 모든 해상도는 필드의 데이터를 어떻게 얻는지 알고 있다. GraphQL 조회는 본질적으로 필드의 집합일 뿐이기 때문에 GraphQL 서버가 요청한 데이터를 수집하는 것은 조회에서 지정한 필드의 모든 해상도 함수를 호출하는 것이다.(이것도 GraphQL이 본질적으로 원격 함수를 호출하는 언어이기 때문에 RPC 스타일의 시스템에 비유되는 이유이다.)"3

    분해기의 분석

    bookmark 쿼리의 코드 세그먼트를 다시 살펴보겠습니다.
            bookmark: {
                type: Bookmark,
                args: {
                    bookmarkId: {type: GraphQLID}
                },
                resolve: async (root, args, context, info) => {
                    const bearerToken = context.bearerToken;
                    const {bookmarkId} = args;
                    const response = await bookmarksApiService.getBookmarkById(userId, bearerToken, bookmarkId);
    
                    return response.body;
                }
            }
    
    resolve 함수의 매개 변수를 주의하십시오.다음과 같은 의미가 있습니다.
    "
  • root(때로는parent라고도 부른다):GraphQL 서버에서 조회를 해석하기 위해 무엇을 해야 하는지 기억나세요?
    검색 필드의 해상도를 호출하고 있습니까?그래, 그것은 이렇게 한 것이다. 광도 우선 (단계별) 과 근본 논점
    모든 해상도에서 호출은 이전 호출의 결과일 뿐입니다. (따로 지정하지 않으면 초기값은null입니다.)
  • args: 이 매개 변수는 조회하는 매개 변수를 포함하고, 이 예에서 가져올 사용자 id입니다.
  • context: 해석기 체인을 통해 전달되는 대상은 모든 해석기가 이를 기록하고 읽을 수 있다(기본적으로 해석기가 정보를 통신하고 공유하는 방식이다).
  • info: 조회 또는 돌연변이의AST 표시.Demystifying the info Argument in GraphQL Resolvers에 대한 자세한 내용은 을 참조하십시오.
    " 3
  • express 중간부분에서 해석기의 상하문에 파라미터를 설정합니다


    Express 중간부품의 req 대상에 파라미터를 설정할 수 있습니다. 이 파라미터는
    분석 프로그램의 context 매개 변수는 이전 예시의 bearerToken의 경우이기 때문에 - const bearerToken = context.bearerToken;
    const app = express();
    
    const setAccessTokenMiddleware = async (req, res, next) => {
      const accessToken = await accessTokenService.getKeycloakAccessToken();
      req.bearerToken = 'Bearer ' + accessToken;
    
      const decoded = jwt.decode(accessToken);
      const userId = decoded.sub;
      req.userId = userId;
      next();
    }
    
    app.use(setAccessTokenMiddleware);
    
    bearerToken Express 중간부품을 통해 위아래 문장으로 설정

    돌연변이-묵은 때의 반추


    GraphQL 서버에서 데이터를 얻는 데 사용될 경우 GraphQL 서버의 데이터를 수정해야 합니다.
    "REST에서는 어떤 요청도 결국 서버에 부작용을 일으킬 수 있지만, 관례에 따라 GET 요청을 사용해서 데이터를 수정하지 않는 것이 좋습니다. GraphQL은 이와 유사합니다. 기술적으로는 모든 조회가 데이터 쓰기를 초래할 수 있습니다. 그러나 관례를 세우는 것은 매우 유용합니다. 즉, 쓰기를 초래하는 모든 작업은 돌연변이를 통해 발송해야 합니다.
    검색에서처럼,mutation 필드가 대상 형식을 되돌려주면, 플러그인 필드를 요청할 수 있습니다.이것은 업데이트된 대상의 새로운 상태를 가져오는 데 매우 유용합니다."4
    프레젠테이션 프로젝트에서 어떤 변화가 있었는지 살펴보겠습니다.
    type Mutation {
        createBookmark(input: BookmarkInput!): Bookmark
        updateBookmark(bookmarkId: ID!, input: BookmarkInput!): Bookmark
        deleteBookmark(bookmarkId: ID!): Bookmark
    }
    
    GraphQL js의 구현은 다음과 같습니다.
    const Mutation = new GraphQLObjectType({
        name: 'Mutation',
        fields: {
            createBookmark: {
                type: Bookmark,
                args: {
                    input: {type: BookmarkInput}
                },
                resolve: async (root, args, context) => {
                    const { input } = args;
    
                    const {userId, bearerToken} = context;
                    const bookmark = await bookmarksApiService.createBookmark(bearerToken, userId, input);
    
                    return bookmark;
                }
            },
            updateBookmark: {
                type: Bookmark,
                args: {
                    bookmarkId: {type: GraphQLID},
                    input: {type: BookmarkInput}
                },
                resolve: async (root, args, context) => {
                    const { input, bookmarkId } = args;
    
                    const {userId, bearerToken} = context;
                    const bookmark = await bookmarksApiService.updateBookmark(bearerToken, userId, bookmarkId, input);
    
                    return bookmark;
                }
            },
            deleteBookmark: {
                description: "Given its ID a bookmark can be deleted. Either by the one that created it or an Admin",
                type: Bookmark,
                args: {
                    bookmarkId: {type: GraphQLID}
                },
                resolve: async (root, args, context) => {
                    const bookmarkId = args.bookmarkId;
                    const {userId, bearerToken} = context;
                    const deletedBookmark = await bookmarksApiService.deleteBookmarkId(bearerToken, userId, bookmarkId);
                    return deletedBookmark;
                }
            }
        }
    });
    

    결론


    이 문장에서, 너는GraphQL의 주요 요소에 관한 이론을 배웠고, 상응하는 예시를 첨부하였다
    GraphQL JS에서 구현됩니다.나는 정말로 GraphQL을 좋아하기 시작했다. 다시 한 번 말하지만, 가장 좋은 학습 체험은 손놀림이다.
    https://github.com/graphql/graphql-js  
    https://github.com/graphql/express-graphql  
    https://www.prisma.io/blog/graphql-server-basics-the-schema-ac5e2950214e  
    https://graphql.org/learn/queries/#mutations  

    좋은 웹페이지 즐겨찾기