지정되지 않은 오류가 발생했습니다. 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 관리도구로 설치해 공식문서에 가르쳐준 대로 사용합니다
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),
}),
});
화폐의 수요와 공급에 따라 달라진다 한국에서 달러가 많아지면 원달러는 약세이지만 달러가 많이 없으면 비싸진다
대부분 나라는 변동 환율제 채택
📝고정환율제
특정 외화에 대한 환율을 일정수준에 고정시키는 제도로 정부가 1000원을 1달러라고 결정하면 언제든 1달러는 1000원에 거래가 된다. 홍콩 등 특정 나라들이 이와 같은 정책을 선택하고있다.
📝원환율
1달러 사는데 필요한 원화
📝FED (연방준비제도[연준])
미국의 중앙 은행
📝환율이 오르는 이유
기본적인 이유
한국에서 달러를 많이 원한다면 달러의 수요가 많아지고 원화 가치가 떨어지게된다.
1. 무역
기본적으로 무역시 달러로 계산을 많이 한다.
수입 > 수출 → 수입이 더 많은 경우
달러가 많이 국가에서 빠져나가게 되어 희귀해지게 된다 → 달러 가격 상승 [무역 적자]
수입 < 수출 → 수출이 더 많은 경우
달러가 많이 국가에서 들어오게 되어 상대적 덜 희귀해지게 된다 → 달러 가격 하락 [무역 흑자]
2. 외국인 자본 유입 및 유출 한국에 엄청난 기술 및 엄청난 기업이 있는 경우 외국인들은 한국 기업에 투자하려고한다. 투자시 원화가 많이 필요한데 달러를 원화로 바꾸는 과정에 달러 유입이 많아지고 환율이 낮아지게 된다. 하지만 미사일맨(북한)이 미사일을 쏘게 되면 위험을 느낀 외국인들은 원화를 달러로 환전해서 해외로 돌리게 됩니다. → 미사일이 어떤 회사에 떨어지면 연구 정보가 다 사라지게 되어 종이장이 되기 때문입니다.
3. 미국 금리인상 미국에서의 금리 인상 비율이 한국보다 높아진 경우 한국에 투자하는 것 보다 자국에 투자하는게 더 이득이기 때문에 달러가 부족하게 되어 가격이 오르게 됩니다. 그래서 최근에 미국이 금리인상을 하며 한국이 따라가는 듯이 금리를 인상하고 있습니다. 하지만 금리를 올리면 대출에 대한 금리도 올라가기 때문에 돈을 빌린 사람들이 많이 손해보게 되는 구조입니다. 미국같은 경우는 탄탄한 기업들이 많아 기업 평가시 가장 크게 보는 것이 Cashflow이고 Cash Is King이라는 격언까지도 있습니다. 그래서 현금 보유량을 탄탄하게 가져가는 기업들이 많이 존재합니다. 하지만 한국은 현금흐름이 원할하지 않은 기업이 많아 금리를 계속 올릴 수 없게 됩니다.
4. 해외 관광객들 증가 해외 관광객들이 많이 한국에 놀러와서 돈을 쓸수록 달러가 많이 쌓이기 때문에 달러는 가치가 하락하게 된다.
엄청 다양한 이유가 존재해서 모든 걸 특정할 순 없습니다.
📝달러 환율 증가시 장점
1달러가 1400원으로 거래될 경우 미국인의 경우 한국으로 여행도 많이 올 거고 상대적으로 싼 한국 제품을 많이 사게 되어 달러가 공급되며 달러 환율을 낮아지게 된다. 일반적인 상황이라면 이래야하지만 우크라이나 러시아의 전쟁으로 원자재 부족으로 인한 수출 제품에 들어가는 재료 가격 상승으로 상쇄되던가 이러한 변수들도 존재합니다.
📝2022년 미국 물가 상승 이유 및 미국 대처 방안
코로나로 인해 지원금을 많이 뿌리게 되고 금리는 낮으니 안 사게 되는 물건까지도 막 사게 되니 수요가 엄청나게 증가해 물건 가격이 오르게 됩니다. 그래서 금리를 인상시켜서 이자놀이라도 시켜서 수요를 낮추는 방식을 채택해 물가가 낮아지게 됩니다.
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}`);
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 };
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
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.