< BACK TO BLOG

Using Keystone for app Backend

๐Ÿ—“๏ธ2023-05-09

์ตœ๊ทผ ์ด๋ ฅ์‚ฌํ•ญ ๋ฐ์ดํ„ฐ๋ฅผ ์ •๋ฆฌํ•˜๋ฉด์„œ, ์ด๋ ฅ์‚ฌํ•ญ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ฐฑ์—”๋“œ ์‘์šฉํ”„๋กœ๊ทธ๋žจ ์ž‘์„ฑ์„ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ต์ˆ™ํ•œ .NET ํ™˜๊ฒฝ์—์„œ ์‹œ์ž‘ํ•˜๋ ค๊ณ , ์ €์žฅ์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ํ”„๋กœ์ ํŠธ๋ฅผ ์ค€๋น„ํ•œ ํ›„ ์—”ํ‹ฐํ‹ฐ ๋ชจ๋ธ์„ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ณ„ํšํ–ˆ๋˜ ๋‚ด์šฉ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ฐฑ์—”๋“œ ์‘์šฉํ”„๋กœ๊ทธ๋žจ: ASP.NET Core
  • ๋ฐฑ์—”๋“œ API ๋ฅผ ํ™œ์šฉํ•˜๋Š” ํ”„๋ก ํŠธ์—”๋“œ ์‘์šฉํ”„๋กœ๊ทธ๋žจ: next.js

์ตœ๊ทผ ์—…๋ฌด๊ฐ€ ๋Š˜์–ด ์ง„๋„๊ฐ€ ์ž˜ ๋‚˜๊ฐ€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ, ๊ท€์ฐฎ์Œ์„ ์ด๊ฒจ๋‚ด๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ ๋„๊ตฌ๋ฅผ ์ฐพ์•„๋ณด๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

KeystoneJS

Theย superpoweredย CMS for developers

KeystoneJS ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๊ด€๋ฆฌํ•˜๋ ค๊ณ  ํ•˜๋Š” ๋ฐ์ดํ„ฐ์˜ ์Šคํ‚ค๋งˆ๋ฅผ ๊ธฐ์ˆ ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์—”๋“œํฌ์ธํŠธ์™€ ๊ฐ„๋žตํ•œ UI ๊นŒ์ง€ ์ž‘์„ฑ๋œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์—”๋“œํฌ์ธํŠธ๋Š” GraphQL API ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๋งค์šฐ ํŽธ๋ฆฌํ•ด ๋ณด์—ฌ, ๊ธฐ์กด ๊ณ„ํšํ–ˆ๋˜ ๊ตฌํ˜„์‚ฌํ•ญ์„ ๋ชจ๋‘ ํ๊ธฐํ•˜๊ณ , KeystoneJS ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ด๋ ฅ์‚ฌํ•ญ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ค€๋น„

์‹œ์ž‘ํ•˜๊ธฐ ์œ„ํ•œ ๋ฌธ์„œ๊ฐ€ ๊ฐ„๋žตํ•˜๊ฒŒ ์ž˜ ์ •๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

# nodejs ํ™˜๊ฒฝ์ด ์ค€๋น„๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค
$ node -v
v18.16.0
$  npm -v
9.5.1
# ์ž‘์—… ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์œ„์น˜๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค
$ cd your/path/
# ํ”„๋กœ์ ํŠธ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
$ npx create-keystone-app@latest
โœจ You're about to generate a project using Keystone 6 packages.

โœ” What directory should create-keystone-app generate your app into? resume-backend-keystone

โ ‹ Installing dependencies with yarn. This may take a few minutes.
โš  Failed to install with yarn.
โœ” Installed dependencies with npm.


๐ŸŽ‰  Keystone created a starter project in: resume-backend-keystone

  To launch your app, run:

  - cd resume-backend-keystone
  - npm run dev

  Next steps:

  - Read resume-backend-keystone/README.md for additional getting started details.
  - Edit resume-backend-keystone/keystone.ts to customize your app.
  - Open the Admin UI
  - Open the Graphql API
  - Read the docs
  - Star Keystone on GitHub

create-keystone-app@latest CLI ๋„๊ตฌ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๋ฌธ๋‹ต์‹์œผ๋กœ ์ž…๋ ฅ๋ฐ›๋Š” ์ ˆ์ฐจ๊ฐ€ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ ํ”„๋กœ์ ํŠธ ์ด๋ฆ„๋งŒ ์ง€์ •ํ•˜๋ฉด, ์ž…๋ ฅ๋œ ํ”„๋กœ์ ํŠธ ์ด๋ฆ„์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ํ•ด๋‹น ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•„์š”ํ•œ ํŒŒ์ผ๋“ค์ด ๋ณต์‚ฌ๋ฉ๋‹ˆ๋‹ค.

# ์ž‘์„ฑ๋œ ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
$ cd path/to/project
# ์˜์กด ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.
$ npm install
...
# ๊ธฐ๋ณธ ๊ตฌ์„ฑ์œผ๋กœ ๊ฐœ๋ฐœ์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
$ npm run dev

์›น ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์—ด๊ณ , ์ฃผ์†Œ์ฐฝ์— ๊ฐœ๋ฐœ์„œ๋ฒ„์˜ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

http://localhost:3000

์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‚ฌ์šฉ์ž ์ž‘์„ฑ ์ ˆ์ฐจ๊ฐ€ ์ง„ํ–‰๋˜๊ณ , ์ด ํ›„ ์ถ”๊ฐ€ํ•œ ์‚ฌ์šฉ์ž๋กœ ๋กœ๊ทธ์ธํ•˜๋ฉด, User ์™€ Post ํ•ญ๋ชฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ํ™•์ธํ•ด๋ณด๋‹ˆ, ๊ธฐ๋ณธ์ ์ธ ์กฐํšŒ, ์ž…๋ ฅ, ์ˆ˜์ •, ์‚ญ์ œ๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

GraphQL API ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์™€ nextjs ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋ฒ„๊ฐ€ ํ†ตํ•ฉ๋˜์–ด ์‹คํ–‰๋˜๋Š” ๊ตฌ์กฐ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ํ•˜์ง€๋งŒ ์•Š์œผ๋ฉด, ๋งค์šฐ ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ธˆ๋ฐฉ ์™„๋ฃŒํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์Šคํ‚ค๋งˆ

ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ์˜ schema.ts ํŒŒ์ผ์„ ์—ด๊ณ , ํŽธ์ง‘์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

ํ•„์š”ํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ฒฐ์ •ํ•˜๊ณ , ์Šคํ‚ค๋งˆ๋ฅผ ๊ธฐ์ˆ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์Šคํ‚ค๋งˆ๋ฅผ ์ •์˜ํ•˜๋Š” ํ˜•์‹์€ ์•„๋ž˜ ์ฝ”๋“œ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ชฉ๋ก์˜ ์ด๋ฆ„์„ ๊ฒฐ์ •ํ•˜๊ณ , ์•ก์„ธ์Šค์™€ ํ•„๋“œ ๋ชฉ๋ก, ํ•„์š”ํ•˜๋ฉด ํ›…์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

import { list } from '@keystone-6/core';

export const lists: Lists = {
    // ๋ชฉ๋ก (๋ฐ์ดํ„ฐ ์ง‘ํ•ฉ)์˜ ์ด๋ฆ„; ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”
    User: list({
        // ๋ชฉ๋ก ์ ‘๊ทผ ์ œ์–ด
        access: {
            // ์ž‘์„ฑ๋œ UI ์—์„œ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์ œ์–ด
            operation: {},
            // ... ํ•„์š”๊ฐ€ ์—†์„ ๊ฒƒ ๊ฐ™์•„ ์ฐพ์•„๋ณด์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
            item: {},
            // GraphQL API ์—์„œ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์ œ์–ด
            filter: {},
        },
        // ๊ด€๋ฆฌํ•  ๋ฐ์ดํ„ฐ ๋ชฉ๋ก; ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์—ด(Column)
        fields: {},
        // ๋ฐ์ดํ„ฐ ์ž…์ถœ๋ ฅ์‹œ ์ถ”๊ฐ€์ ์œผ๋กœ ๋™์ž‘ํ•  ๊ธฐ๋Šฅ
        hooks: {},
    }),
    // ...
};

๋ชฉ๋ก์˜ ํ•„๋“œ๋ฅผ ์ •์˜ํ•  ๋•Œ, relationship ํ˜•์‹์„ ์‚ฌ์šฉํ•ด์„œ ๋‹ค๋ฅธ ๋ชฉ๋ก๊ณผ์˜ ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

import { relationship } from '@keystone-6/core/fields';

Post ์™€ Tag ๋ชฉ๋ก์˜ ๋‹ค๋Œ€๋‹ค ๊ด€๋ก€์„ค์ •์˜ ์˜ˆ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

import { list } from '@keystone-6/core';
import { relationship } from '@keystone-6/core/fields';

export const lists: Lists = {
    // ...
    Post: list({
        // ...
        fields: {
            tags: relationship({
                ref: 'Tag.posts',
                many: true,
                ui: {
                    displayMode: 'cards',
                    cardFields: ['name'],
                    inlineEdit: { fields: ['name'] },
                    linkToItem: true,
                    inlineConnect: true,
                    inlineCreate: { fields: ['name', 'owner'] },
                },
            }),
        },
        // ...
    }),
    // ...
    Tag: list({
        // ...
        fields: {
            posts: relationship({
                ref: 'Post.tags',
                many: true,
                ui: { hideCreate: true, displayMode: 'count' },
            }),
        },
        // ...
    }),
    // ...
};

์ ‘๊ทผ์ œ์–ด๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์˜ˆ1) ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๋งŒ UI ์—์„œ ๋ฆฌ์ŠคํŠธ ๋ชฉ๋ก์„ ํ™•์ธ ๊ฐ€๋Šฅ

import { list } from '@keystone-6/core';

const isAuthorized = ({ session }: { session: Session }) =>
    Boolean(session?.data?.id);

export const lists: Lists = {
    User: list({
        access: {
            operation: {
                query: isAuthorized,
                // ...
            },
            item: {},
            // GraphQL API ์—์„œ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์ œ์–ด
            filter: {},
        },
        // ...
    }),
    // ...
};

์˜ˆ2) ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๋Š” ๋ณธ์ธ์ด ์ž‘์„ฑ์žํ•œ ํ•ญ๋ชฉ๋งŒ ์กฐํšŒ ๊ฐ€๋Šฅ

๋ชฉ๋ก์˜ ํ•„๋“œ์— ์†Œ์œ ์ž๋ฅผ ํ‘œ์‹œํ•˜๋Š” owner ํ•„๋“œ๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

import { list } from '@keystone-6/core';

const filterByOwner = ({ session }: { session: Session }) => {
    if (session?.data?.isAdmin ?? true) {
        return true;
    }

    if (session?.data?.id) {
        return {
            owner: {
                id: {
                    equals: session.data.id,
                },
            },
        };
    }

    return false;
};

export const lists: Lists = {
    User: list({
        access: {
            filter: {
                query: filterByOwner,
            },
        },
        // ...
    }),
    // ...
};

๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜๊ณ , ์ง€์›ํ•˜๋Š” ํ•„๋“œ๋ฅผ ํ™œ์šฉํ•ด์„œ ํ•„์š”ํ•œ ํ•„๋“œ๋“ค์„ ๋ชจ๋‘ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

ํ•„๋“œ๋ฅผ ๋ชจ๋‘ ์ •์˜ํ•œ ํ›„ ๊ฐœ๋ฐœ์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•ด์„œ ๋ฐ์ดํ„ฐ ์ž…์ถœ๋ ฅ์ด ๋ชจ๋‘ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด๋‹ˆ, ์˜๋„ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด ์ž˜ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

๋งค์šฐ ์ค‘์š”ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๊ณ , ๋งŽ์€ ํŠธ๋ž˜ํ”ฝ์„ ์ฒ˜๋ฆฌํ•  ๋Œ€์ƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ํŽธ๋ฆฌํ•˜๊ฒŒ ํŒŒ์ผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” Sqlite ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

Sqlite ๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์Šคํ‚ค๋งˆ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ณต์žกํ•˜๊ฒŒ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์ง„ํ–‰ํ•  ํ•„์š”๋„ ์—†๋Š” ๊ฒƒ์œผ๋กœ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

๋„์ปค

GitHub workflows ๋ฅผ ํ™œ์šฉํ•ด์„œ ์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œํ•˜๊ณ , ๊ด€๋ฆฌ์ค‘์ธ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์—…๋กœ๋“œํ•˜๋ ค๊ณ  ํ•˜๋‹ˆ ์ด๋ฏธ์ง€ ํŒŒ์ผ์˜ ํฌ๊ธฐ๊ฐ€ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ๊ณ„๋ฅผ ๋„˜์–ด์„œ ๋ฒ„๋ ค ๋กœ์ปฌ ์„œ๋ฒ„์—์„œ ๋นŒ๋“œํ•ด์„œ ์—…๋กœ๋“œํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ด€๋ฆฌ๋ฐฉ๋ฒ•์„ ์ฑ„ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.

์ž๋™ํ™”ํ•˜๋ฉด ํŽธ๋ฆฌํ•œ๋ฐ, GitHub workflows ์—์„œ๋Š” 500MB (์ •ํ™•ํ•œ ํฌ๊ธฐ๋Š” ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค) ๋ณด๋‹ค ํฐ ํŒŒ์ผ์€ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

413 Request Entity Too Large

๋กœ์ปฌ์„œ๋ฒ„์—์„œ ์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œํ•œ ํ›„ ๋™์ผํ•œ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— docker push ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ฌธ์ œ์—†์ด ์—…๋กœ๋“œ๋˜๊ณ  ์žˆ์–ด ๋”์ด์ƒ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ์ฐพ๋Š” ๊ฒƒ์„ ์ค‘์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฒŒ์‹œ

์ž‘์„ฑ๋œ ์ด๋ ฅ์‚ฌํ•ญ ๋ฐฑ์—”๋“œ ์‘์šฉํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰๋  ์„œ๋ฒ„์— docker-compose.yml ํŒŒ์ผ์„ ์ž‘์„ฑํ•ด์„œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•  ์ค€๋น„๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.

sqlite ํŒŒ์ผ์„ ๋งˆ์šดํŠธํ•ด์„œ ์ปจํ…Œ์ด๋„ˆ ์™ธ๋ถ€์—์„œ ํŒŒ์ผ์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ์—†์ด ์‹คํ–‰๋œ ๊ฒƒ์„ ํ™•์ธํ•˜๊ณ , ์—ญ ํ”„๋ก์‹œ ๊ตฌ์„ฑ์œผ๋กœ, ๋„๋ฉ”์ธ์„ ์—ฐ๊ฒฐํ•ด์„œ ์›น๋ธŒ๋ผ์šฐ์ €์—์„œ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

๋กœ๊ทธ์ธ, ๋ฐ์ดํ„ฐ ์กฐํšŒ, โ€ฆ ์ž˜ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ, ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜, ๋ณ€๊ฒฝ, ์‚ญ์ œ๋ฅผ ์‹œ๋„ํ•˜๋ฉด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜๊ณ , ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์ด ๋ฐ˜์˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ปจํ…Œ์ด๋„ˆ์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์ปจํ…Œ์ด๋„ˆ์— ๋งˆ์šดํŠธํ•œ ํŒŒ์ผ์— ์“ฐ๊ธฐ ๊ถŒํ•œ์ด ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œํ•œ ๊ธฐ๋ฐ˜ ์ด๋ฏธ์ง€๋ฅผ ํ™•์ธํ•˜๋‹ˆ, ์‚ฌ์šฉ์ž ์ด๋ฆ„ node ๊ทธ๋ฃน node ๋กœ ํ™•์ธ๋ฉ๋‹ˆ๋‹ค.

Non-root user

# ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€ ์‚ฌ์šฉ์ž ์ •๋ณด
$ id node
uid=1000(node) gid=1000(node) groups=1000(node)

ํ˜ธ์ŠคํŠธ ์„œ๋ฒ„์—์„œ sqlite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŒŒ์ผ์˜ ์†Œ์œ ์ž๋ฅผ 1000:1000 ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์„œ ๊ถŒํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

$ chwon -R 1000:1000 ./sqlite.db

์†Œ์œ ์ž๋ฅผ ๋ณ€๊ฒฝํ•œ ํ›„ ๋ฐ์ดํ„ฐ ์ž…๋ ฅ์ด ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์—ฐ๋™

ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ CORS ํ—ˆ์šฉ ์›๋ณธ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌ์„ฑํ•ด๋’€์Šต๋‹ˆ๋‹ค.

์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰์‹œ ์ด๋ ฅ์‚ฌํ•ญ ์›น์•ฑ์˜ ์ฃผ์†Œ๋ฅผ ํ™˜๊ฒฝ๋ณ€์ˆ˜์— ์ž…๋ ฅํ•ด์„œ, ์ด๋ ฅ์‚ฌํ•ญ ์›น์•ฑ์ด ์š”์ฒญํ•˜๋ฉด ์ •์ƒ์‘๋‹ตํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ ฅ์‚ฌํ•ญ ์›น์•ฑ ์„œ๋ฒ„์ธก์—์„œ ์ด๋ ฅ์‚ฌํ•ญ ๋ฐฑ์—”๋“œ GraphQL API ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๊ฒŒ ๋ณ€๊ฒฝํ•œ ํ›„ ๊ฒŒ์‹œํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์—ฐ๋™์„ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

query User($where: UserWhereUniqueInput!) {
  user(where: $where) {
    # ...
    aboutMe: # ...
    contentCategories: # ...
    contents: # ...
    skillCategories: # ...
    skills:  # ...
  }
}

GraphQL ์„œ๋ฒ„๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ์‹ซ์–ดํ•˜์ง€๋งŒ ์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ ์ƒ๊ฐํ•˜๋ฉด ํ•œ๋ฒˆ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์›ํ•˜๋Š” ๋ชจ์–‘์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์–ด ์ข‹์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์™„๋ฃŒ

๊ธธ๊ฒŒ ๊ณ„ํšํ•˜๊ณ  ์ฒœ์ฒœํžˆ ์ง„ํ–‰ํ•˜๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ, ๋Œ€๋ถ€๋ถ„์˜ ๊ตฌํ˜„์ด KeystoneJS ๋‚ด๋ถ€์—์„œ ์ฒ˜๋ฆฌ๋˜์–ด ๊ธˆ๋ฐฉ ๋๋‚˜๋ฒ„๋ ธ์Šต๋‹ˆ๋‹ค.

๋งˆ์น˜๋ฉฐ

์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ๋กœ ์žฌ๋ฏธ๋‚œ ์„œ๋น„์Šค๋ฅผ ์ค€๋น„ํ•  ๋•Œ, KeystoneJS๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฐฑ์—”๋“œ๋ฅผ ๊ตฌ์„ฑํ•˜๋ฉด ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋ผ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์„œ๋น„์Šค๋ฅผ ํ™•์žฅํ•ด์•ผ ํ•˜๋Š” ์‹œ์ ์ด ์˜ค๋ฉด, ๊ทธ ๋•Œ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์˜ ๋ฐฑ์—”๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์‹œ์ž‘ํ•ด๋„ ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.


๊ด€๋ จ ์ €์žฅ์†Œ:

GitHub Repository


Profile picture

Pon Cheol Ku (๊ตฌ๋ณธ์ฒ )

Software developer

Other sites

If does not find interesting topic, you might visit other site on below link.

ยฉ 2024, Built with Gatsby