반응형
반응형

Apollo Server v4에서는 일반적으로 에러 코드도200 메세지를 준다 이거를 옵션을 줘서 200코드 값이 아닌 400등으로  변경할 수 있다 또한 StackTrace 기능도 제공한다

 

📝Apollo Server에서 기본적 제공하는 에러 종류

에러 설명
GRAPHQL_PARSE_FAILED
GraphQL 작업 문자열  구문 오류가 있습니다.
GRAPHQL_VALIDATION_FAILED
GraphQL 작업은 서버 의 스키마에 대해 유효하지 않습니다.
BAD_USER_INPUT
GraphQL 작업에 필드 인수  대한 잘못된 값이 포함되어 있습니다 .
PERSISTED_QUERY_NOT_FOUND
클라이언트는 다음 을 통해 실행할 쿼리 문자열의 해시를 보냈습니다.
, 그러나 쿼리가 APQ 캐시 에 없었습니다 .
PERSISTED_QUERY_NOT_SUPPORTED
클라이언트는 다음 을 통해 실행할 쿼리 문자열의 해시를 보냈습니다.
하지만 서버가 APQ를 비활성화했습니다 .
OPERATION_RESOLUTION_FAILURE
요청이 성공적으로 구문 분석되었으며 서버의 스키마에 대해 유효하지만 서버가 실행할 작업 을 확인할 수 없습니다.
이는 여러 명명된 작업이 포함된 요청이 실행할 작업(예: operationName)을 지정하지 않거나 명명된 작업이 요청에 포함되지 않은 경우에 발생합니다.
BAD_REQUEST
서버가 주어진 GraphQL 작업 을 구문 분석하기 전에 오류가 발생했습니다 .
INTERNAL_SERVER_ERROR
지정되지 않은 오류가 발생했습니다.
Apollo Server가 응답에서 오류 형식을 지정할 때 다른 코드가 설정되지 않은 경우 코드 확장을 이 값으로 설정합니다.

 

📝커스텀 에러

import { GraphQLError } from 'graphql';

throw new GraphQLError('You are not authorized to perform this action.', {
  extensions: {
    code: 'FORBIDDEN',
    argumentName: 'id',
  },
});

 

 

 

📝공통 에러 처리

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { ApolloServerErrorCode } from '@apollo/server/errors';

const server = new ApolloServer({
  typeDefs,
  resolvers,
  formatError: (formattedError, error) => {
    // Return a different error message
    if (
      formattedError.extensions.code ===
      ApolloServerErrorCode.GRAPHQL_VALIDATION_FAILED
    ) {
      return {
        ...formattedError,
        message: "Your query doesn't match the schema. Try double-checking it!",
      };
    }

    // Otherwise return the formatted error. This error can also
    // be manipulated in other ways, as long as it's returned.
    return formattedError;
  },
});

const { url } = await startStandaloneServer(server);
console.log(`🚀 Server listening at: ${url}`);

 

 

formatError을 통해 전체 에러에 대한 핸들링이 가능합니다

 

📝에러 리포팅 기능

formatError: (formattedError, error) => {
    if (error instanceof CustomDBError) {
      // do something specific
    }
  },
  
다른 거에 대한 것도 가능

버그에 대한 내용을 가지고 리포팅 등의 기능도 제공합니다

 

📝Subscription (웹소켓)

type Subscription {
  postCreated: Post
}

웹소켓에 대한 API 명세를 먼저 정의하고 따로 Graphql Websocket을 package 관리도구로 설치해 공식문서에 가르쳐준 대로 사용합니다

 

제가 정리한건 큼지막한 내용이 있을 뿐 자세한 옵션들은 공식문서 참고바랍니다

 

 

🔗 참고 및 출처

https://www.apollographql.com/docs/apollo-server/data/errors

https://www.apollographql.com/docs/apollo-server/data/subscriptions

반응형
반응형

📝Apollo Server

  • GraphQL코드를 효율적으로 관리하는데 도움을 줍니다
  • GraphQL의 Query, Type 등 문서화하는데 도움을 줍니다
  • Sandbox를 제공해 직접 GraphQL 테스트도 가능합니다
  • 최적화 기능도 제공합니다

 

Graphql을 개발한 Meta에서 만든 Relay라는게 있지만 학습비용이 높고 React계열만 지원한다는 단점이 존재한다 그에 비해 Apollo는 유연하고 러닝커브가 높지 않다

 

📝리졸버

Apollo Server가 Graphql 작업 처리하는 방법입니다

요청이 들어오면 그에 따라 비즈니스 로직을 처리해 결과를 반환해주는 역할입니다

 

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';

// Hardcoded data store
const books = [
  {
    title: 'The Awakening',
    author: 'Kate Chopin',
  },
  {
    title: 'City of Glass',
    author: 'Paul Auster',
  },
];

// Schema definition
const typeDefs = `#graphql
  type Book {
    title: String
    author: String
  }

  type Query {
    books: [Book]
  }
`;

// Resolver map
const resolvers = {
  Query: {
    books() {
      return books;
    },
  },
};

// Pass schema definition and resolvers to the
// ApolloServer constructor
const server = new ApolloServer({
  typeDefs,
  resolvers,
});

// Launch the server
const { url } = await startStandaloneServer(server);
console.log(`🚀 Server listening at: ${url}`);

위에 예시 코드의 경우 resolvers에서 books Query에 대한 리턴을 정의합니다 그 이후에 server에 스키마와 resolver를 등록합니다

 

📝리졸버 체이닝

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';

const libraries = [
  {
    branch: 'downtown',
  },
  {
    branch: 'riverside',
  },
];

// The branch field of a book indicates which library has it in stock
const books = [
  {
    title: 'The Awakening',
    author: 'Kate Chopin',
    branch: 'riverside',
  },
  {
    title: 'City of Glass',
    author: 'Paul Auster',
    branch: 'downtown',
  },
];

// Schema definition
const typeDefs = `#graphql
  # A library has a branch and books
  type Library {
    branch: String!
    books: [Book!]
  }

  # A book has a title and author
  type Book {
    title: String!
    author: Author!
  }

  # An author has a name
  type Author {
    name: String!
  }

  # Queries can fetch a list of libraries
  type Query {
    libraries: [Library]
  }
`;

// Resolver map
const resolvers = {
  Query: {
    libraries() {
      // Return our hardcoded array of libraries
      return libraries;
    },
  },
  Library: {
    books(parent) {
      // Filter the hardcoded array of books to only include
      // books that are located at the correct branch
      return books.filter((book) => book.branch === parent.branch);
    },
  },
  Book: {
    // The parent resolver (Library.books) returns an object with the
    // author's name in the "author" field. Return a JSON object containing
    // the name, because this field expects an object.
    author(parent) {
      return {
        name: parent.author,
      };
    },
  },

  // Because Book.author returns an object with a "name" field,
  // Apollo Server's default resolver for Author.name will work.
  // We don't need to define one.
};

// Pass schema definition and resolvers to the
// ApolloServer constructor
const server = new ApolloServer({
  typeDefs,
  resolvers,
});

// Launch the server
const { url } = await startStandaloneServer(server);
console.log(`🚀 Server listening at: ${url}`);


// 호출
query GetBooksByLibrary {
  libraries {
    books {
      title
      author {
        name
      }
    }
  }
}

리졸버 체이닝이란 리졸버의 결과가 다음 리졸버의 입력으로 연결되는 패턴입니다

 

위 예시 코드에 대해 설명하면 Query Libraries에 대한 정의를 하고 해당 리턴의 타입인 [Library]의 값 받습니다 그 이후 결과값을 받아 Library 타입 안에 속하는 books의 타입인 [Book]의 값을 정의합니다

이렇게 이어받아서 작업하는 걸 리졸버 체이닝이라고합니다

 

아래는 리졸버 체이닝에 쓰이는 인자값 입니다

parent 이전 리졸버의 반환값입니다.
args  필드 에 제공된 모든 GraphQL 인수를 포함하는 객체입니다 .
예를 들어 를 실행할 때 리졸버에 전달되는 객체 query{ user(id: "4") } 입니다. argsuser { "id": "4" }
contextValue 특정 작업을 실행하는 모든 확인자 간에 공유되는 개체입니다.
이를 사용하여 인증 정보, 데이터로더 인스턴스 및 확인자 전체에서 추적할 기타 항목을 포함하여 작업별 상태를 공유합니다.

info 필드 이름, 루트에서 필드까지의 경로 등을 포함하여 작업 실행 상태 에 대한 정보가 포함되어 있습니다 .

 

 

contextValue 예시

import { GraphQLError } from 'graphql';

const resolvers = {
  Query: {
    // Example resolver
    adminExample: (parent, args, contextValue, info) => {
      if (contextValue.authScope !== ADMIN) {
        throw new GraphQLError('not admin!', {
          extensions: { code: 'UNAUTHENTICATED' },
        });
      }
    },
  },
};

interface MyContext {
  // You can optionally create a TS interface to set up types
  // for your contextValue
  authScope?: String;
}

const server = new ApolloServer<MyContext>({
  typeDefs,
  resolvers,
});

const { url } = await startStandaloneServer(server, {
  // Your async context function should async and
  // return an object
  
  context: async ({ req, res }) => ({
    authScope: getScope(req.headers.authorization),
  }),
  
});

 

contextValue 예시 2

context: async () => ({
  db: await client.connect(),
})

// Resolver
(parent, args, contextValue, info) => {
  return contextValue.db.query('SELECT * FROM table_name');
}

 

contextValue 예시 3

import { AnimalAPI } from './datasources/animals';

const resolvers = {
  Query: {
    // All of our resolvers can access our shared contextValue!
    dogs: (_, __, contextValue) => {
      return contextValue.dataSources.animalApi.getDogs();
    },
    cats: (_, __, contextValue) => {
      return contextValue.dataSources.animalApi.getCats();
    },
  },
};

interface MyContext {
  // Context typing
  dataSources: {
    animalApi: AnimalAPI;
  };
}

const server = new ApolloServer<MyContext>({
  typeDefs,
  resolvers,
});

const { url } = await startStandaloneServer(server, {
  context: async () => {
    const animalApi = new AnimalAPI();
    return {
      dataSources: {
        animalApi,
      },
    };
  },
});

contextValue통해 공유 객체에 액세스할 수 있습니다

 

 

 

 

반응형
반응형

📝변동환율제

화폐의 수요와 공급에 따라 달라진다 한국에서 달러가 많아지면 원달러는 약세이지만 달러가 많이 없으면 비싸진다

대부분 나라는 변동 환율제 채택

📝고정환율제

특정 외화에 대한 환율을 일정수준에 고정시키는 제도로 정부가 1000원을 1달러라고 결정하면 언제든 1달러는 1000원에 거래가 된다.
홍콩 등 특정 나라들이 이와 같은 정책을 선택하고있다.

📝원환율

1달러 사는데 필요한 원화

📝FED (연방준비제도[연준])

미국의 중앙 은행

📝환율이 오르는 이유

기본적인 이유

  • 한국에서 달러를 많이 원한다면 달러의 수요가 많아지고 원화 가치가 떨어지게된다.

 

1. 무역

기본적으로 무역시 달러로 계산을 많이 한다.

  • 수입 > 수출 → 수입이 더 많은 경우
    • 달러가 많이 국가에서 빠져나가게 되어 희귀해지게 된다 → 달러 가격 상승 [무역 적자]
  • 수입 < 수출 → 수출이 더 많은 경우
    • 달러가 많이 국가에서 들어오게 되어 상대적 덜 희귀해지게 된다 → 달러 가격 하락 [무역 흑자]


2. 외국인 자본 유입 및 유출
한국에 엄청난 기술 및 엄청난 기업이 있는 경우 외국인들은 한국 기업에 투자하려고한다.
투자시 원화가 많이 필요한데 달러를 원화로 바꾸는 과정에 달러 유입이 많아지고 환율이 낮아지게 된다.
하지만 미사일맨(북한)이 미사일을 쏘게 되면 위험을 느낀 외국인들은 원화를 달러로 환전해서 해외로 돌리게 됩니다.
→ 미사일이 어떤 회사에 떨어지면 연구 정보가 다 사라지게 되어 종이장이 되기 때문입니다.

3. 미국 금리인상
미국에서의 금리 인상 비율이 한국보다 높아진 경우 한국에 투자하는 것 보다 자국에 투자하는게 더 이득이기 때문에 달러가 부족하게 되어 가격이 오르게 됩니다.
그래서 최근에 미국이 금리인상을 하며 한국이 따라가는 듯이 금리를 인상하고 있습니다.
하지만 금리를 올리면 대출에 대한 금리도 올라가기 때문에 돈을 빌린 사람들이 많이 손해보게 되는 구조입니다.
미국같은 경우는 탄탄한 기업들이 많아 기업 평가시 가장 크게 보는 것이 Cashflow이고 Cash Is King이라는 격언까지도 있습니다.
그래서 현금 보유량을 탄탄하게 가져가는 기업들이 많이 존재합니다. 하지만 한국은 현금흐름이 원할하지 않은 기업이 많아 금리를 계속 올릴 수 없게 됩니다.

4. 해외 관광객들 증가
해외 관광객들이 많이 한국에 놀러와서 돈을 쓸수록 달러가 많이 쌓이기 때문에 달러는 가치가 하락하게 된다.

엄청 다양한 이유가 존재해서 모든 걸 특정할 순 없습니다.

 

📝달러 환율 증가시 장점

1달러가 1400원으로 거래될 경우 미국인의 경우 한국으로 여행도 많이 올 거고 상대적으로 싼 한국 제품을 많이 사게 되어 달러가 공급되며 달러 환율을 낮아지게 된다.
일반적인 상황이라면 이래야하지만 우크라이나 러시아의 전쟁으로 원자재 부족으로 인한 수출 제품에 들어가는 재료 가격 상승으로 상쇄되던가 이러한 변수들도 존재합니다.

📝2022년 미국 물가 상승 이유 및 미국 대처 방안

코로나로 인해 지원금을 많이 뿌리게 되고 금리는 낮으니 안 사게 되는 물건까지도 막 사게 되니 수요가 엄청나게 증가해 물건 가격이 오르게 됩니다. 그래서 금리를 인상시켜서 이자놀이라도 시켜서 수요를 낮추는 방식을 채택해 물가가 낮아지게 됩니다.



🔗 참고 및 출처
https://anhong2.tistory.com/86

https://www.youtube.com/watch?v=H7CZuf-oNDQ 

반응형
반응형

 

📝Apollo Server로 시작하기

Apollo Server 공식 문서와 제가 개인적으로 연습에 필요한 패키지로 진행했습니다

귀찮아서 ts가 아니라 js로 진행했다는 점 참고바랍니다

 

 

1. 프로젝트 폴더 만들기

mkdir graphql-server-example
cd graphql-server-example

 

2. Node 패키지 설치 및 셋팅

npm init --yes && npm pkg set type="module"

 

3. 필요 패키지 설치

npm install apollo-server graphql
npm install nodemon -D

 

4. 실행 파일 생성 (src/index.js)

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';

// A schema is a collection of type definitions (hence "typeDefs")
// that together define the "shape" of queries that are executed against
// your data.

const books = [
    {
        title: 'The Awakening',
        author: 'Kate Chopin',
    },
    {
        title: 'City of Glass',
        author: 'Paul Auster',
    },
];

// Resolvers define how to fetch the types defined in your schema.
// This resolver retrieves books from the "books" array above.
const resolvers = {
    Query: {
        books: () => books,
    },
};

const typeDefs = `#graphql
# Comments in GraphQL strings (such as this one) start with the hash (#) symbol.

# This "Book" type defines the queryable fields for every book in our data source.
type Book {
    title: String
    author: String
}

# The "Query" type is special: it lists all of the available queries that
# clients can execute, along with the return type for each. In this
# case, the "books" query returns an array of zero or more Books (defined above).
type Query {
    books: [Book]
}
`;

// The ApolloServer constructor requires two parameters: your schema
// definition and your set of resolvers.
const server = new ApolloServer({
    typeDefs,
    resolvers,
});

// Passing an ApolloServer instance to the `startStandaloneServer` function:
//  1. creates an Express app
//  2. installs your ApolloServer instance as middleware
//  3. prepares your app to handle incoming requests
const { url } = await startStandaloneServer(server, {
    listen: { port: 4000 },
});

console.log(`🚀  Server ready at: ${url}`);

 

5. 실행 스크립트 작성 (package.json)

{
  "dependencies": {
    "@apollo/server": "^4.10.2",
    "apollo-server": "^3.13.0",
    "graphql": "^16.8.1"
  },
  "devDependencies": {
    "nodemon": "^3.1.0"
  },
  "name": "graphql-server-example",
  "version": "1.0.0",
  "main": "src/index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon src/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "type": "module"
}

 

6. npm start로 시작

localhost:4000/grpahql로 apollo server 접속

 

 

https://www.apollographql.com/docs/apollo-server/getting-started/

 

Get started with Apollo Server

This tutorial helps you: Obtain a basic understanding of GraphQL principlesDefine a GraphQL schema that represents the structure of your data setRun an instance of Apollo Server that lets you execute queries against your schema This tutorial assumes that y

www.apollographql.com

 

반응형
반응형

📝GET

{
  me {
    name
  }
}

// 위와 등치
http://myapi/graphql?query={me{name}}

HTTP GET 요청을 수신할 때 GraphQL 쿼리는 "query" 쿼리 문자열에 지정되어야 합니다

예를 들어, 다음 GraphQL 쿼리를 실행하려는 경우는 위와 같습니다

 

📝POST

/** ─── 호출 ───**/
{
  "query": "...",
  "operationName": "...",
  "variables": { "myVariable": "someValue", ... }
}

/** ─── 응답 ───**/
{
  "data": { ... },
  "errors": [ ... ]
}

표준 GraphQL POST 요청은 application/json콘텐츠 유형을 사용해야 하며 다음 형식의 JSON 인코딩 본문을 포함해야합니다

 

operationName및 variables선택적 필드입니다 그리고 operationName쿼리에 여러 작업이 있는 경우에만 필요합니다

응답의경우 잘못된 요청인 경우 errors 필드가 존재하며 그렇지 않을 땐 data 필드만 존재합니다

 

 

반응형
반응형

 

 

 

📝Json gzip 압축

GraphQL에서는 Accept-Encoding: gzip으로 Json 압축 기능도 제공한다

https://graphql.org/learn/best-practices/#json-with-gzip

 

GraphQL Best Practices | GraphQL

Copyright © 2024 The GraphQL Foundation. All rights reserved. For web site terms of use, trademark policy and general project policies please see https://lfprojects.org

graphql.org

 

반응형
반응형

📝Mutation

/** ─── 호출 ───**/
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}

/** ─── 호출 변수 ───**/
{
  "ep": "JEDI",
  "review": {
    "stars": 5,
    "commentary": "This is a great movie!"
  }
}

/** ─── 응답 ───**/
{
  "data": {
    "createReview": {
      "stars": 5,
      "commentary": "This is a great movie!"
    }
  }
}

Mutation의 경우는 데이터의 조회를 제외한 모든 것에 사용됩니다 특히 데이터 생성, 삭제, 수정에 해당하죠

 

쿼리 필드는 병렬로 실행되는 반면 변형 필드는 순차적으로 실행됩니다

한 요청에 두 개의 Mutation을 보내면 두번째 Mutation이 시작되기 전에 첫 번째 Mutation이 완료되어 우리 자신과의 경쟁 조건이 발생하지 않도록 보장합니다

 

쿼리와 마찬가지로 변형 필드가 객체 유형을 반환하는 경우 중첩 필드를 요청할 수 있습니다

이는 업데이트 후 객체의 새 상태를 가져오는 데 유용합니다

 

📝Query

HTTP에서 Get 방식 통신에 해당하는 걸로 데이터를 조회할 때 사용한다

 

기본 예제 1

/** ─── 호출 ───**/
Query Hero {
  hero {
    name
  }
}

// 생략
{
  hero {
    name
  }
}


/** ─── 응답 ───**/
{
  "data": {
    "hero": {
      "name": "R2-D2"
    }
  }
}

단일 작업 및 복잡하지 않는 단일 요청일 때 query 키워드랑 쿼리 이름을 생략할 수 있지만 생략해서 혼돈만 초래할 뿐 그냥 적어주자

 

기본 예제 2

/** ─── 호출 ───**/
Query Hero {
  hero {
    name
    # Queries can have comments!
    friends {
      name
    }
  }
}


/** ─── 응답 ───**/
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

 

📝Query 파라미터

파라미터 사용 예제 1

# Human 타입 정의
type Human {
  id: ID!
  name: String!
  height: Float
}

# 쿼리 타입 정의
type Query {
  human(id: ID!): Human
}

/** ─── 호출 ───**/
{
  human(id: "1000") {
    name
    height
  }
}

/** ─── 응답 ───**/
{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "height": 1.72
    }
  }
}

 

 

정의한 쿼리 타입 토대로 파라미터를 넣어서 요청할 수 있다

 

파라미터 사용 예제 2

enum Unit {
  METER
  FOOT
}

# Human 타입 정의
type Human {
  id: ID!
  name: String!
  height(unit: Unit = METER): Float
}

/** ─── 호출 ───**/
{
  human(id: "1000") {
    name
    height(unit: FOOT)
  }
}

/** ─── 응답 ───**/
{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "height": 5.6430448
    }
  }
}

 

📝Query 별칭

별칭 예제

/** ─── 호출 ───**/
{
  empireHero: hero(episode: EMPIRE) {
    name
  }
  jediHero: hero(episode: JEDI) {
    name
  }
}

/** ─── 응답 ───**/
{
  "data": {
    "empireHero": {
      "name": "Luke Skywalker"
    },
    "jediHero": {
      "name": "R2-D2"
    }
  }
}

두 필드는 hero로 충돌이 될 예정이였지만 alias로 인해 문제 없이 진행되게 했다

 

📝Query Fragment

fragment 예제

fragment comparisonFields on Character {
  name
  appearsIn
  friends {
    name
  }
}


/** ─── 호출 ───**/
{
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

/** ─── 응답 ───**/
{
  "data": {
    "leftComparison": {
      "name": "Luke Skywalker",
      "appearsIn": [
        "NEWHOPE",
        "EMPIRE",
        "JEDI"
      ],
      "friends": [
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        },
        {
          "name": "C-3PO"
        },
        {
          "name": "R2-D2"
        }
      ]
    },
    "rightComparison": {
      "name": "R2-D2",
      "appearsIn": [
        "NEWHOPE",
        "EMPIRE",
        "JEDI"
      ],
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

fragment를 이용해 재사용할 수 있게 하고 반복적인 코드를 줄일 수 있습니다
on Type명으로 꼭 타입을 지정해줘야합니다 여기에서는 Character라는 타입입니다

 

📝Query 동적 파라미터

동적 파라미터 예제 1

/** ─── 호출 ───**/
query HeroNameAndFriends($episode: Episode) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}

/** ─── 호출 변수 ───**/
{
  "episode": "JEDI"
}

/** ─── 응답 ───**/
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

변수를 이용해 동적으로 데이터를 받을 수 있다

 

동적 파라미터 예제 2

query HeroNameAndFriends($episode: Episode = JEDI) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}

기본값 설정도 가능함

 

📝지시문

/** ─── 호출 ───**/
query Hero($episode: Episode, $withFriends: Boolean!) {
  hero(episode: $episode) {
    name
    friends @include(if: $withFriends) {
      name
    }
  }
}

/** ─── 호출 변수 ───**/
{
  "episode": "JEDI",
  "withFriends": false
}

/** ─── 응답─**/
{
  "data": {
    "hero": {
      "name": "R2-D2"
    }
  }
}

지시문으로 필드를 동적으로 받을 수 있다

  • @include(if: Boolean)
    • 인수가 다음인 경우에만 결과에 이 필드를 포함합니다
  • @skip(if: Boolean)
    • 인수가 이면 이 필드를 건너뛰십시오

 

 

반응형
반응형

📝Exclude<UnionType, ExcludedMembers>

type T0 = Exclude<"a" | "b" | "c", "a">;
// type T0 = "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">;
// type T1 = "c"
type T2 = Exclude<string | number | (() => void), Function>;
// type T2 = string | number

UnionType에 할당된 것에 제외할 멤버를 제외하고 Type 형식을 구성합니다

 

📝Extract<Type, Union>

type T0 = Extract<"a" | "b" | "c", "a" | "f">;
// type T0 = "a"
type T1 = Extract<string | number | (() => void), Function>;
// type T1 = () => void

Type과 Union의 교집합에 해당하는 부분으로 Type형식을 구성합니다

 

📝NonNullable<Type>

type T0 = NonNullable<string | number | undefined>;
// type T0 = string | number
type T1 = NonNullable<string[] | null | undefined>;
// type T1 = string[]

null및 undefined를 제외하여 유형을 구성합니다

 

📝Parameters<Type>

function greet(name: string, age: number): string {
  return `Hello, ${name}. You are ${age} years old.`;
}
type GreetParameters = Parameters<typeof greet>;
// GreetParameters 타입은 [string, number]와 동일합니다.
const user: GreetParameters = ["John Doe", 30];

유틸리티 타입은 함수의 매개변수 타입들을 튜플 타입으로 추출합니다

 

📝ConstructorParameters

class User {
  constructor(public name: string, public age: number) {}
}

// User 생성자의 매개변수 타입을 추출합니다.
type UserConstructorParameters = ConstructorParameters<typeof User>;

// UserConstructorParameters는 [string, number] 타입과 동일합니다.
const userParams: UserConstructorParameters = ["Jane Doe", 32];

클래스 생성자의 매개변수 타입들을 튜플로 추출합니다

 

📝ReturnType<Type>

function getUser() {
  return { name: "John Doe", age: 30 };
}

// getUser 함수의 반환 타입을 추출합니다.
type User = ReturnType<typeof getUser>;

// User 타입은 { name: string; age: number; }와 동일합니다.
const user: User = { name: "Jane Doe", age: 32 };

함수의 반환 타입을 추출하는 유틸리티 타입입니다

반응형
반응형

📝Awaited<Type>

type A = Awaited<Promise<string>>;
// type A = string
type B = Awaited<Promise<Promise<number>>>;
// type B = number
type C = Awaited<boolean | Promise<number>>;
// type C = number | boolean

프로미스(Promise)가 resolve된 후의 타입을 나타내는 유틸리티 타입입니다

📝Partial<Type>

interface Todo {
  title: string;
  description: string;
}
 
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
  return { ...todo, ...fieldsToUpdate };
}
 
const todo1 = {
  title: "organize desk",
  description: "clear clutter",
};
 
const todo2 = updateTodo(todo1, {
  description: "throw out trash",
});

기존 타입의 구조를 유지하면서 모든 필드를 필수가 아닌 선택적으로 변경할 수 있습니다

 

📝Required<Type>

interface Props {
  a?: number;
  b?: string;
}
 
const obj: Props = { a: 5 };
const obj2: Required<Props> = { a: 5 };
// Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'.

해당 필드에 내용이 반드시 필요하다는 선언이 가능합니다

 

📝Readonly<Type>

interface Todo {
  title: string;
}
 
const todo: Readonly<Todo> = {
  title: "Delete inactive users",
};
 
todo.title = "Hello";
Cannot assign to 'title' because it is a read-only property.

생성된 유형의 속성을 재할당할 수 없습니다

 

📝Record<Keys, Type>

Record <K, V>

export enum categoryEnum {
  FC12000000 = 'FC12000000',
  FC14000000 = 'FC14000000',
}

static readonly names: Record<categoryEnum, string> = {
    FC12000000: '취미 / 문구 / 도서',
    FC14000000: 'e쿠폰 / 여행 / 렌탈',
}

Typescript에서는 Record라는게 존재하는데 이것은 Map과 같이 Key, Value로 사용 가능한 타입이다

 

📝Pick<Type, Keys>

interface Todo {
  title: string;
  description: string;
  completed: boolean;
}
 
type TodoPreview = Pick<Todo, "title" | "completed">;
 
const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};

속성 집합(문자열 리터럴 또는 문자열 리터럴의 합집합) 을 선택하여 유형을 구성합니다

 

📝Omit<Type, Keys>

interface Todo {
  title: string;
  description: string;
  completed: boolean;
  createdAt: number;
}
 
type TodoPreview = Omit<Todo, "description">;
 
const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
  createdAt: 1615544252770,
};

(문자열 리터럴 또는 문자열 리터럴의 합집합) 에서 모든 속성을 선택한 Type다음 제거 하여 유형을 구성합니다

반응형