Notion API Developer - Beta 한글 번역

 

 

 

0. 앞선 글

 

페이지는 사용자가 빠른 메모부터 공유문서, 랜딩페이지에 이르기까지 모든 것을 작성하는 곳입니다. 통합을 사용해 사용자는 콘텐츠를 조직하여 Notion을 단일 소스로 변경하거나 Notion내에서 콘텐츠를 수집, 연결, 시각화할 수 있습니다.

 

이 가이드에서는 페이지 콘텐츠의 구성요소가 API에 표시되는 방식과 이를 사용하여 수행할 수 있는 작업에 대해 알아보도록 하겠습니다. 이 가이드를 통해 사용자는 콘텐츠가 포함된 새 페이지를 만들고 다른 페이지의 콘텐츠를 읽어와 기존 페이지 블록에 추가할 수 있습니다.

 

 

 

1. 페이지 콘텐츠와 속성.

 

일반적으로 페이지 속성은 기한, 범주, 다른 페이지와의 관계 같은 구조화된 정보를 저장하는데 적합합니다. 페이지 콘텐츠는 좀 더 느슨한 구조나 자유 형식 콘텐츠를 저장하는데 적합합니다. 페이지 콘텐츠는 사용자의 생각을 작성하거나 이야기하는 곳입니다. 페이지 속성은 사용자가 데이터를 저장하고 시스템을 구축하는 곳입니다. 여러분의 통합은 여러분이 기대하는 대로 속성과 콘텐츠를 사용하는 것을 목표로 해야 합니다.

 

https://developers.notion.com/docs/working-with-page-content

 

 

2. 콘텐츠를 블록으로 모델링하기.

 

페이지 콘텐츠는 블록 객체 목록으로 표시됩니다. 이러한 블록을 페이지의 자식이라고도 합니다. 각 블록에는 단락, 제목, 이미지와 같은 타입이 있습니다. 토글 목록과 같은 일부 타입의 블록에는 자체 자식이 존재할 수 있습니다.

 

간단한 예제로 단락 블록을 확인해 보겠습니다.

 

{
  "object": "block",
  "id": "380c78c0-e0f5-4565-bdbd-c4ccb079050d",
  "type": "paragraph",
  "created_time": "",
  "last_edited_time": "",
  "has_children": false,

  "paragraph": {
    "text": [/* details omitted */]
  }
}

 

모든 단락 블록에는 object, type, created_time, last_edited_time, has_children의 공통된 속성을 포함합니다. 또한 단락 속성 내에 type-specific 정보가 포함되어 있습니다. 단락 블록에는 "text" 속성이 존재하며 블록 타입에 따라 type-specific 속성이 달라질 수 있습니다.

 

이제 블록에 자식 블록이 있는 예시를 살펴보도록 하겠습니다. "paragraph"에 들여 쓰기 된 "to_do" 블록을 확인해 보세요.

 

{
  "object": "block",
  "id": "380c78c0-e0f5-4565-bdbd-c4ccb079050d",
  "type": "paragraph",
  "created_time": "",
  "last_edited_time": "",
  "has_children": true,

  "paragraph": {
    "text": [/* details omitted */],
    "children": [
      {
        "object": "block",
        "id": "6d5b2463-a1c1-4e22-9b3b-49b3fe7ad384",
        "type": "to_do",
        "created_time": "",
        "last_edited_time": "",
        "has_children": false,
  
        "to_do": {
          "text": [/* details omitted */],
          "checked": false
        }
      }
    ]
  }
}

 

자식 블록은 type-specific 속성 내에 블록 목록으로 표시됩니다. 만약 블록에 자식이 있다면 "has_children" 속성은 true가 됩니다. 단락 블록과 같은 일부 블록 타입만 자식을 지원합니다.

 

* 지원하지 않는 블록 타입(Notion Version 2021-05-13 기준)

Notion API는 현자 텍스트와 유사한 블록만을 지원하며 곧 더 많은 블록을 지원할 예정입니다. 지원되지 않는 블록 타입은 페이지에 "unsupported" 타입으로 표시됩니다.

 

 

 

3. 서식이 있는 텍스트(Rich Text)

 

앞선 블록 예시에서 "text" 속성의 생략된 값은 서식이 있는 텍스트(Rich Text) 객체의 목록이었습니다. 서식이 있는 텍스트 객체는 단순한 문자열 이상을 표현할 수 있습니다. 이 객체에는 스타일 정보, 링크, 멘션 등이 포함될 수 있습니다.

 

"Grocery List"라는 단어만 포함된 간단한 예시를 살펴보도록 하겠습니다.

 

{
  "type": "text",
  "text": {
    "content": "Grocery List",
    "link": null
  },
  "annotations": {
    "bold": false,
    "italic": false,
    "strikethrough": false,
    "underline": false,
    "code": false,
    "color": "default"
  },
  "plain_text": "Grocery List",
  "href": null
}

 

서식이 있는 텍스트 객체는 type-specific 한 구성과 유사한 패턴을 따릅니다. 위의 서식이 있는 텍스트 객체에는 "text" 타입이 있으며 "text" 속성에 해당 타입과 관련된 추가 구성이 존재합니다. annotations, plain_text, href와 같은 타입에 의존하지 않는 기타 정보들은 서식이 있는 텍스트 객체의 최상위 수준에 위치하게 됩니다.

 

서식이 있는 텍스트는 페이지 콘텐츠와 내부 페이지 속성 값 모두에 사용될 수 있습니다.

 

 

 

4. 콘텐츠가 있는 페이지 만들기.

 

페이지 생성 엔드포인트를 사용하면 자식 블록을 통해 페이지를 만들 수 있습니다. 이 엔드포인트는 다름 페이지 내에서 페이지를 만들거나 데이터베이스 내에서 페이지 만들기를 지원합니다.

 

샘플 콘텐츠가 있는 다른 페이지 내에 페이지를 새로 만들어 보도록 하겠습니다. 이 엔트포인트에 대해 세 가지 파라미터를 사용하게 됩니다. "parnet" 파라미터는 부포 페이지가 됩니다. 기존의 페이지 ID를 사용할 수 있습니다.

 

{
  "type": "page_id",
  "page_id": "494c87d0-72c4-4cf6-960f-55f8427f7692"
}

 

"properites" 파라미터는 페이지 속성을 표현하는 객체입니다. 우선 이 예시에서는 "title" 속성만이 있는 간단한 페이지 속성을 구성하도록 하겠습니다.

 

{
  "Name": {
    "type": "title",
    "title": [{ "type": "text", "text": { "content": "A note from your pals at Notion" } }]
  }
}

 

"children" 파라미터는 페이지 콘텐츠를 표현하는 블록 객체 목록입니다. 몇 가지 샘플 콘텐츠를 사용하도록 하겠습니다.

 

[
  {
    "object": "block",
    "type": "paragraph",
    "paragraph": {
      "rich_text": [{ "type": "text", "text": { "content": "You made this page using the Notion API. Pretty cool, huh? We hope you enjoy building with us." } }]
    }
  }
]

 

이 세 가지 파라미터를 모두 사용해 엔드포인트에 요청을 전송하여 페이지를 생성해 보도록 하겠습니다.

 

curl -X POST https://api.notion.com/v1/pages \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
  --data '{
    "parent": { "database_id": "494c87d0-72c4-4cf6-960f-55f8427f7692" },
    "properties": {
        "title": {
      "title": [{ "type": "text", "text": { "content": "A note from your pals at Notion" } }]
        }
    },
    "children": [
    {
      "object": "block",
      "type": "paragraph",
      "paragraph": {
        "text": [{ "type": "text", "text": { "content": "You made this page using the Notion API. Pretty cool, huh? We hope you enjoy building with us." } }]
      }
    }
  ]
}'

* 토큰과 ID 정보는 적절히 수정되어야 합니다.

* API 요청에는 크기 제한이 존재합니다. 자세한 내용은 Size Limit를 확인해 주세요.

 

페이지가 추가되면 새 페이지 객체가 포함된 응답을 받게 됩니다. Notion을 살펴보고 새 페이지를 확인해 보세요.

 

 

 

5. 페이지에서 블록 읽어오기.

 

페이지 콘텐츠는 자식 블록 검색 엔드포인트를 이용해 읽어올 수 있습니다. 이 엔드포인트는 모든 자식 목록을 반환합니다. 페이지는 블록 자식을 읽어오기 위한 일반적인 시작 방법이지만 다른 종류의 블록에 대한 자식들도 검색할 수 있습니다.

 

"block_id" 파라미터는 블록의 ID를 의미합니다. 예시에 따른다면 응답에 페이지 ID가 포함되어 있을 것입니다. 해당 페이지의 ID를 "block_id"로 사용해 페이지에서 샘플 콘텐츠를 읽어오도록 하겠습니다.

 

이제 "block_id"를 사용해 엔드포인트에 요청을 보내고 하위의 블록을 검색합니다.

 

curl https://api.notion.com/v1/blocks/16d8004e-5f6a-42a6-9811-51c22ddada12/children?page_size=100 \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Notion-Version: 2021-05-13"

* block_id 및 토큰 정보는 적절히 수정되어야 합니다.

 

블록 객체 목록이 포함된 응답을 받게 됩니다.

 

{
  "object": "list",
  "results": [
    {
      "object": "block",
      /* details omitted */
    }
  ],
  "has_more": false,
  "next_cursor": null
}

 

페이징 된 응답을 받을 수 있습니다. 페이징 된 응답은 Notion API 전반에서 사용됩니다. 페이징 된 응답의 최대 결과 개수는 100개입니다. "start_cursor"과 "page_size" 파라미터를 통해 100개가 넘는 결과를 얻어올 수도 있습니다.

 

이 응답에서 요청한 자식 블록은 "results" 배열 내부에 존재하게 됩니다.

 

 

 

6. 중첩된 블록 읽어오기.

 

결과 자체에 자식이 포함된 블록이 있는 경우 어떤 일이 일어날까요? 이 경우 응답에 중첩된 블록이 포함되지는 않지만 "has_children"의 값은 true가 됩니다. 통합에 페이지 콘텐츠 혹은 모든 블록의 완전한 표현이 필요하다면 "has_children"이 true인 블록에 대해 결과를 검색하고 엔드포인트를 재귀적으로 호출해야 합니다.

 

큰 페이지를 읽는데 다소 시간이 걸릴 수 있습니다. 아키텍처에서 작업 대기열과 같은 비동기 작업을 사용하는 것이 좋습니다. 또한 요청 제한에 도달할 수 있으므로 새 요청을 전송하는 속도를 적절히 늦춰야 할 수도 있습니다.

 

 

 

7. 페이지에 블록 추가하기.

 

통합은 블록 자식 추가 엔드포인트를 사용해 더 많은 콘텐츠를 추가할 수도 있습니다. 예시에서 만든 페이지에 다른 블록을 추가해 보도록 하겠습니다. 이 엔드포인트에는 "block_id"와 "children"의 두 개의 파라미터가 필요합니다

 

"block_id"는 기존 블록의 ID입니다. 블록 ID에 앞선 예시에서 사용한 페이지 ID를 동일하게 사용하도록 합니다.

 

"children" 파라미터는 추가할 내용을 설명할 블록 객체 목록입니다. 더 만든 샘플 콘텐츠를 사용해 보도록 하겠습니다.

 

[
  {
    "object": "block",
    "type": "paragraph",
    "paragraph": {
      "text": [{ "type": "text", "text": { "content": "– Notion API Team", "link": { "type": "url", "url": "https://twitter.com/NotionAPI" } } }]
    }
  }
]

 

두 파라미터를 이용해 엔드포인트에 요청을 전송하여 블록을 추가합니다.

 

curl -X PATCH https://api.notion.com/v1/blocks/16d8004e-5f6a-42a6-9811-51c22ddada12/children \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
  --data '{
    "children": [
    {
      "object": "block",
      "type": "paragraph",
      "paragraph": {
        "text": [{ "type": "text", "text": { "content": "– Notion API Team", "link": { "type": "url", "url": "https://twitter.com/NotionAPI" } } }]
      }
    }
  ]
}'

* 블록 ID와 토큰을 적절히 수정하는 것을 잊지 마세요.

 

업데이트된 블록이 포함된 응답을 받게 됩니다. 응답에 하위 블록이 포함되어 있지는 않지만 "has_children"의 값이 true로 설정된 것을 확인할 수 있습니다.

 

 

 

8. 맺는 글.

 

사용자가 Notion에서 보는 것의 거의 모든 것이 블록으로 표시됩니다. 이제 통합으로 블록이 있는 페이즈를 만들었고 블록을 읽어올 수 있으며 페이지에 블록을 추가하는 방법을 이해했습니다. 이제 Notion에서 노출된 대부분의 영역을 다를 수 있게 되었습니다. 

 

 

 

* 현재 블록을 삭제하거나 업데이트하는 것은 불가능합니다.

(NotionVersion 2021-05-13) 이러한 작업은 파괴적이므로 API를 통해 이 작업을 노출하는 가장 좋은 방법을 신중히 조사하고 있습니다. 향후 기능에 대한 업데이트를 위해 계속 지켜봐 주시기 바랍니다.

 

 

* 이 글은 Notion API Develpers - Beta: Working with page content를 번역한 글입니다.

 

Working with page content

Overview Pages are where users write everything from quick notes, to shared documents, to curated landing pages in Notion. Integrations can help users turn Notion into the single source of truth by syndicating content or help users gather, connect, and vis

developers.notion.com

 

 

 

반응형

 

Notion API Developer - Beta 한글 번역 

 

 

 

0. 앞선 글.

 

Notion에서 드디어 API 서비스를 시작했습니다. 오래 기다린 기능인만큼 바로 사용해보고 싶은데 아직 한글 가이드가 없어 공식 가이드를 읽으며 참고할만한 내용을 포스팅합니다.

 

 

 

1. 시작하기.

 

Notion API를 사용해 처음으로 API 요청을 만드는 방법에 대해 알아보겠습니다.

 

Notion API를 처음 사용한다면 잘 찾아오셨습니다. 이 가이드에서는 다음과 같은 방법을 알아봅니다.

* Notion 워크스페이스에서 통합(Integration)을 생성합니다.

* Notion에서 새 데이터베이스를 만들고 통합 권한을 부여해 액세스 합니다.

* 코드를 사용해 데이터베이스에 페이지를 추가합니다.

 

 

 

2. 시작하기 전에.

 

시작하기 전에 필요한 몇 가지 사항이 있습니다.

* 관리자 유저로 Notion 워크스페이스에 로그인합니다.

* CURL 커맨드가 설치된 터미널 프로그램.

 

 

 

3. 신규 통합 만들기.

 

브라우저를 새로 열어 Notion 통합 페이지를 엽니다. "새 통합" 버튼을 사용해 신규 통합을 생성합니다. 통합 이름을 지정하세요. 이 예시에서는 "Vacation Planner"로 정했습니다. 제출을 완료해 통합을 생성합니다.

 

https://developers.notion.com/docs/getting-started

 

시크릿 아래에서 내부용 통합 토큰을 찾을 수 있습니다. 이 토큰을 표시하도록 하고 복사해두세요. 텍스트 에디터와 같은 나중에 쉽게 찾을 수 있는 곳에 붙여 넣어 둡시다.

 

 

 

4. 통합을 사용해 데이터베이스 공유.

 

API로 구축된 통합은 사용자에 공유 권한과 유사한 권한 시스템을 따릅니다. 여기에는 중요한 차이점이 있습니다. 통합은 처음엔 워크스페이스의 페이지나 데이터베이스에 액세스 할 수 없습니다. API를 통해 해당 페이지에 액세스 하려면 사용자가 특정 페이지를 통합에 공유해야 합니다. 이런 방식으로 Notion에서 사용자와 팀의 정보를 안전하게 보호할 수 있습니다.

 

워크스페이스의 새 페이지 또는 기존 페이지에서 시작해봅시다. /표 혹은 /table을 입력하여 새 데이터베이스를 추가합니다. 제목을 정해줍니다. 이 예시에서는 "Weekend getaway destinations"라고 정했습니다. 이제 공유 버튼을 클릭해 실렉터에서 통합을 찾아 선택한 뒤 초대를 클릭합니다.

 

https://developers.notion.com/docs/getting-started

 

이제 통합에 새 데이터베이스를 읽고 쓰고 편집할 수 있는 권한이 부여되었습니다. 통합이 워크스페이스에 추가되면 모든 구성원과 통합이 같이 페이지 및 데이터베이스를 공유할 수 있습니다. 이 단계에서는 관리자 권한이 요구되지 않습니다.

 

계속하기 전에 방금 만든 데이터베이스의 ID를 알아보도록 합시다.

Notion 데스크톱 앱을 사용하는 경우 공유 버튼을 다시 한번 클릭해 링크 복사를 선택합니다. 브라우저에 이 URL을 붙여 넣고 확인하세요. 이 URL에서 데이터베이스 ID는 워크스페이스 이름 슬래시(/) 뒤부터 물음표(?) 앞까지입니다. 데이터베이스 ID는 문자와 숫자를 포함하는 32자입니다. 이 ID를 복사해 나중에 쉽게 찾을 수 있는 곳에 저장해 두세요.

 

https://www.notion.so/myworkspace/a8aec43384f447ed84390e8e42c2e089?v=...
                                                                    |-------------------- Database ID ------------------|

 

 

 

5. 데이터베이스에 아이템 추가하기.

 

Notion 데이터베이스에서 각각의 아이템은 자식 페이지입니다. 부모를 데이터베이스로 설정함으로써 새 페이지를 생성해 데이터베이스에 아이템을 추가할 수 있습니다. 새 아이템을 추가하기 위해 페이지 생성 엔드포인트에 HTTP 요청을 보내봅시다.

 

터미널 프로그램을 열고 다음 커맨드를 입력하세요. Authorization와 database_id의 값은 앞서 생성한 적절한 값으로 변경되어야 합니다. 줄 끝에 보이는 문자(\) 뒤에 공백이 없어야 함을 주의하세요.

 

curl -X POST https://api.notion.com/v1/pages \
  -H "Authorization: Bearer MY_NOTION_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
  --data '{
    "parent": { "database_id": "DATABASE_ID" },
    "properties": {
      "Name": {
        "title": [
          {
            "text": {
              "content": "Yurts in Big Sur, California"
            }
          }
        ]
      }
    }
  }'

 

커맨드를 실행하고 Notion으로 이동해 새 항목이 데이터베이스에 추가되었는지 확인하세요.

 

이제 Notion API를 사용해 데이터베이스에 새 항목을 추가했습니다. 커맨드와 함께 보낸 HTTP 요청에 대해 좀 더 자세히 살펴보겠습니다.

* Notion API는 REST API 규칙을 따릅니다.

* 토큰은 Authorization 헤더에 포함되며 요청의 출처를 식별합니다.

* Notion API의 각 엔드포인트는 파라미터를 사용해 호출할 수 있습니다. 엔드포인트의 참고 페이지에는 이러한 파라미터에 대해 설명되어 있습니다. 이 예시에서 parent와 properties는 모두 본문에 명시되어 있습니다. 데이터베이스 작업 가이드에는 다른 엔드포인트를 사용하는 방법에 대해 설명되어 있습니다,

 

 

 

6. 마무리

 

방금 배운 내용을 사용하면 다른 서비스와 시스템을 연결해 새로운 정보를 Notion에 보내거나 업데이트 해 여러분의 팀이 정보를 확인하고 조치를 취할 수 있도록 합니다.

 

이 가이드에서는 CURL 명령어를 통해 Notion API에 HTTP 요청을 보내는 방법을 사용하였습니다. 일반적으로 통합은 프로그래밍 언어를 사용하여 코드로 작성될 것입니다. 거의 모든 프로그래밍 언어를 사용할 수 있지만 통합을 사용한 코드를 실행하는데 가장 쉽고 빠른 방법을 찾고 있다면 이 예제를 사용해 보세요. 숙련된 프로그래머들에게도 이 예제는 훌륭한 시작점이 될 것입니다.

 

* 이 글은 Notion API Develpers - Beta: Getting started를 번역한 글입니다.

 

Getting started

Learn how to make your first API requests using the Notion API

developers.notion.com

 

 

반응형

 

Notion API Developer - Beta 한글 번역

 

 

 

0. 앞선 글.

 

데이터베이스 스키마, 쿼리 등에 대해 알아봅시다.

 

데이터베이스를 통해 사용자는 Notion에서 구조화된 데이터를 만들고 다룰 수 있습니다. 통합을 사용해 사용자는 데이터베이스를 외부 시스템과 동기화하거나 Notion 데이터베이스를 중심으로 워크플로우를 구축할 수 있습니다.

 

이 가이드에서는 데이터베이스가 API에서 어떻게 표현되는지부터 데이터베이스에 아이템을 추가하는 방법, 아이템을 찾는 방법뿐 아니라 페이지의 속성(properties)을 업데이트하는 방법도 배울 것입니다.

 

 

 

1. 데이터베이스의 구조.

 

데이터베이스 객체는 사용자가 데이터베이스를 열 때 Notion에서 보는 것을 표현합니다. 가장 중요한 부분은 속성(properties) 컬렉션에 정의된 데이터베이스의 스키마입니다.

 

{
  "object": "database",
  "id": "2f26ee68-df30-4251-aad4-8ddc420cba3d",
  "created_time": "2020-03-17T19:10:04.968Z",
  "last_edited_time": "2020-03-17T21:49:37.913Z",
  "title": [/* details omitted */],
  "properties": {/* a collection of property objects */},
}

 

 

 

2. 데이터베이스의 속성(Properties)

 

여러분이 보고 있는 데이터베이스가 표라고 가정해 보도록 합시다. 속성 객체는 열에 있는 모든 값들의 타입을 포함하며 열에 대한 설명을 저장합니다. 텍스트, 숫자, 날짜, 사람 등의 일반적인 타입을 사용할 수 있으며 각 타입에 대한 추가 구성 또한 사용할 수 있습니다. 다음 데이터베이스 객체 예시를 통해 속성 섹션에 대해 알아보도록 하겠습니다.

 

{
  "object": "database",
  "properties": {
    "Grocery item": {
      "id": "fy:{",
      "type": "title",
      "title": {}
    },
    "Price": {
      "id": "dia[",
      "type": "number",
      "number": {
        "format": "dollar"
      }
    },
    "Last ordered": {
      "id": "]\\R[",
      "type": "date",
      "date": {}
    },
  }
  // remaining details omitted
}

 

이 데이터베이스 객체에는 세 가지 속성이 정의되어 있습니다. 각각의 키는 속성의 이름이며 그 값은 속성 객체입니다. 몇 가지 핵심 사항에 대해 알아보겠습니다.

* "title"은 특별한 타입입니다. 모든 데이터베이스에는 "title" 타입을 가진 딱 하나의 속성이 존재합니다. 이 타입의 속성은 데이터베이스에서 각각의 아이템에 대한 페이지 제목을 참조하게 됩니다. 이 예시에서는 "Grocery item" 속성에 이 "title" 타입이 있습니다.

* "type"의 값은 속성 객체의 또 다른 키에 해당됩니다. 각 속성 객체에는 "type"의 값과 동일한 이름의 속성이 존재합니다. 예를 들어 "Last ordered"에는 "type"에 "date"라는 값이 존재하고 "date" 속성도 존재합니다. 이 패턴은 Notion API 전체에서 사용되며 type-specific 데이터라고 합니다.

* 특정 속성 객체에는 추가 구성이 있습니다. "number" 속성 내부에는 추가 구성이 있는 것을 확인할 수 있습니다. 이 예시에서 포맷 설정은 이 열이 보이는 방식을 제어하며 "dollar"로 설정되었습니다.

 

 

 

3. 데이터베이스에 페이지 추가하기.

 

페이지는 데이터베이스 내부의 아이템으로 사용되며 각 페이지의 속성은 부모 데이터베이스의 스키마를 따라야 합니다. 데이터베이스를 표라고 가정하면 페이지의 속성들은 한 행의 모든 값을 정의합니다.

 

페이지는 페이지 생성 API의 엔드포인트를 사용해 데이터베이스에 추가됩니다. 이 예시에서 데이터베이스에 새 페이지를 추가해 보도록 하겠습니다. 엔드포인트는 "parent"와 "properies"라는 두 가지 파라미터가 요구됩니다.

 

데이터베이스에 페이지를 추가할 때 "parent" 파라미터는 데이터베이스가 되어야 합니다. 

 

{
  "type": "database_id",
  "database_id": "2f26ee68-df30-4251-aad4-8ddc420cba3d"
}

* 데이터베이스에 접근하기 위해 통합에 미리 권한을 부여해야 합니다.

 

"properties" 파라미터는 속성 이름이나 ID를 키로 사용하고 속성 값 객체를 값으로 사용하는 객체입니다. 이 파라미터를 올바르게 작성하기 위해 데이터베이스 스키마의 특성 객체를 참고하세요. 예시 데이터베이스에 대해서 다음 객체를 생성할 수 있습니다.

 

{
  "Grocery item": {
    "type": "title",
    "title": [{ "type": "text", "text": { "content": "Tomatoes" } }]
  },
  "Price": {
    "type": "number",
    "number": 1.49
  },
  "Last ordered": {
    "type": "date",
    "date": { "start": "2021-05-11" }
  }
}

 

이제 위의 "parent"와 "properties" 두 파라미터를 사용해 페이지를 생성하기 위해 엔드포인트에 HTTP 요청을 전송해 보겠습니다.

 

curl -X POST https://api.notion.com/v1/pages \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
  --data '{
      "parent": { "type": "database_id", "database_id": "2f26ee68-df30-4251-aad4-8ddc420cba3d" },
      "properties": {
      "Grocery item": {
        "type": "title",
        "title": [{ "type": "text", "text": { "content": "Tomatoes" } }]
      },
      "Price": {
        "type": "number",
        "number": 1.49
      },
      "Last ordered": {
        "type": "date",
        "date": { "start": "2021-05-11" }
      }
    }
  }'

* Authorization와 database_id를 적절히 바꾸는 것을 잊지 마세요

* 정상적으로 페이지가 추가되기 위해선 데이터베이스의 스키마가 알맞게 구성되어야 함을 잊지 마세요.

 

페이지가 추가된다면 새 페이지 객체가 포함된 응답을 받게 됩니다. 이 응답에서 중요한 속성은 페이지 ID입니다. Notion을 외부 시스템에 연결하여 사용하는 경우 이 페이지 ID를 알아두는 것이 좋습니다. 나중에 이 페이지의 속성을 업데이트할 때 업데이트 페이지 엔드포인트에서 이 ID를 사용합니다.

 

 

 

4. 데이터베이스에서 페이지 찾기.

 

데이터베이스 쿼리 엔드포인트를 사용해 데이터베이스에서 페이지를 읽어올 수 있습니다. 이 엔드포인트를 사용하려면 "Last ordered가 지난주부터"와 같은 기준에 따라 페이지를 찾을 수 있습니다. 일부 큰 데이터베이스에서는 이 엔드 포인트를 사용하면 특정 순서의 더 작은 결과를 얻어 낼 수 있습니다.

 

이렇게 페이지를 찾는 데 사용되는 조건을 필터라고 합니다. 필터는 "Tag에 긴급이 포함됨"과 같은 단순한 조건부터 "Tag에 긴급이 포함되어야 하고 Due date는 몇 주 이내여야 하며 Assignee는 Cassandra Vasquez여야 함"과 같은 복잡한 조건으로 설정할 수 있습니다. 이러한 복잡한 조건은 "and"나 "or"을 사용해 여러 개의 단순한 조건을 결합하여 사용하므로 복합필터라고 합니다.

 

이 가이드에서는 예시 데이터베이스에 단일 속성 조건을 사용하는 것을 중점으로 둡니다. 데이터베이스 스키마를 살펴보면 "Last ordered" 속성이 "date" 타입을 사용한다는 것을 알고 있습니다. 즉 "date" 타입에 대한 조건을 사용해 "Last ordered"에 대한 필터를 만들 수 있습니다. 

 

{
  "property": "Last ordered",
  "date": {
    "past_week": {}
  }
}

 

이 필터를 사용해 예시 데이터베이스에서 조건에 맞는 페이지를 찾아와 보도록 합시다.

 

curl -X POST https://api.notion.com/v1/databases/2f26ee68df304251aad48ddc420cba3d/query \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"''
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
    --data '{
      "filter": {
      "property": "Last ordered",
      "date": {
        "past_week": {}
      }
        }
    }'

* Authorization과 URL의 databases 뒤에 데이터베이스 ID를 적절하게 바꿔야 함을 잊지 마세요.

 

필터에 일치하는 페이지 객체 목록이 포함된 응답을 받을 수 있습니다.

 

{
  "object": "list",
  "results": [
    {
      "object": "page",
      /* details omitted */
    }
  ],
  "has_more": false,
  "next_cursor": null
}

 

사실 이 응답은 페이징 된(paginated) 응답입니다. 페이징 된 응답은 큰 객체 목록을 반환하는 모든 Notion API의 응답에 사용됩니다. 페이징 된 응답의 최대 결과 개수는 100개입니다. 페이징 된 결과는 "start_cursor"과 "page_size" 파라 미터를 사용해 100개 이상의 결과를 얼어올 수도 있습니다.

 

이 예시에서 요청한 개별 페이지에 대한 정보는 "results"에 있습니다. 통합이나 사용자가 최근에 만들어진 페이지에 관심이 있다면 어떨까요? 가장 최근에 생성된 페이지가 첫 번째로 오도록 결과를 정렬할 수 있습니다. 특히 결과 페이지가 하나가 아닌 경우에 유용합니다.

 

"sort" 파라미터는 개별 속성 혹은 타임스탬프에 의해 결과를 정렬하는 데 사용됩니다. 이 파라미터는 정렬 객체의 배열에 할당될 수 있습니다.

 

페이지가 생성된 시간은 데이터베이스 스키마를 따르는 페이지 속성이 아닙니다. 이 속성은 모든 페이지에 존재는 두 종류의 타임스탬프 중 하나입니다. 이를 "created_time" 타임스탬프라고 합니다. 

 

이제 가장 최근에 생성된 페이지가 먼저 표시되도록 결과를 정렬하는 정렬 객체를 만들어보도록 하겠습니다.

 

{
  "timestamp": "created_time",
  "direction": "descending"
}

 

마지막으로 이 정렬 객체를 사용해 페이지를 요청해 보도록 하겠습니다.

 

curl -X POST https://api.notion.com/v1/databases/2f26ee68df304251aad48ddc420cba3d/query \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"''
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
    --data '{
      "filter": {
      "property": "Last ordered",
      "date": {
        "past_week": {}
      }
        },
    "sorts": [{ "timestamp": "created_time", "direction": "descending" }]
    }'

* 데이터베이스 ID과 토큰 정보를 적절히 수정해야 함을 잊지 마세요.

 

 

 

5. 맺는 글.

 

데이터베이스 속성들에 의해 만들어진 데이터베이스 스키마를 이해하는 것은 Notion 데이터베이스 작업의 핵심입니다. 이를 통해 데이터베이스에 페이지를 추가하고 데이터베이스에서 아이템을 찾을 수 있습니다.

 

* 이 글은 Notion API Develpers - Beta: Working with database를 번역한 글입니다.

 

Working with databases

Learn about database schemas, querying databases, and more.

developers.notion.com

 

 

 

반응형

이 글은 다음 영상의 튜토리얼을 글로 풀어쓴 내용을 담고 있습니다: Build a Weather App in VueJS | VueJS Beginner Tutorial

 

 

 

1. 앞선 글.

 

이 글에선 위의 링크에서 안내되는 튜토리얼을 따라 해 볼 예정입니다. 이 영상에서 소개하는 내용은 외부 API를 사용해 검색한 도시의 날씨 정보를 보여주는 앱을 작성하는 것입니다.

 

소개된 튜토리얼의 난이도는 초심자 급으로 VueJS를 갓 시작한 개발자를 위한 튜토리얼입니다. 영상의 길이는 약 27분으로 짧은 편이므로 영상을 직접 보시는 것을 추천드립니다.

 

또한 모든 소스코드는 다음 경로에서 확인할 수 있습니다: TylerPottsDev/weather-vue

 

TylerPottsDev/weather-vue

Contribute to TylerPottsDev/weather-vue development by creating an account on GitHub.

github.com

 

 

 

2. 날씨 API 준비하기.

 

외부에서 날씨정보를 읽어오기 위해 OpenWeatherMap라는 사이트를 사용할 예정입니다. 여기로 이동해 회원가입을 진행해 주세요.

 

회원가입 후 위의 그림처럼 API -> Current Weather Data -> Subscribe를 클릭합니다.

 

 

별도의 유료 플랜은 선택사항입니다. 우린 무료 플랜을 사용할 예정입니다. 위의 표시된 Get APU key를 클릭해 주세요.

 

 

전 이미 키를 받았기 때문에 이미 키가 있다는 알림이 표시됩니다. 키를 발급받은 후 메인 페이지에서 볼 수 있는 API Keys 메뉴로 이동합니다. 위의 가려진 곳에 우리가 발급받은 API 키가 존재합니다.

 

만약 새로운 키를 발급받고 싶으시다면 우측의 Create Key에 원하는 이름을 입력 후 Generate버튼을 클릭해 새로운 키를 발급받을 수 있습니다.

 

키를 여기서 확인할 수 있다는 사실을 기억해 두세요!

 

 

 

3. VueJS 프로젝트 만들기.

 

VueJS 프로젝트를 생성하는 방법은 여러 방법이 있습니다만 여기에서는 yarn과 vue-cli을 이용해 프로젝트를 생성하는 방법에 대해 알아보도록 하겠습니다. 

 

** yarn을 설치하는 방법에 대해선 이 글에서 설명하지 않습니다. 설치 방법은 yarn 공식 홈페이지의 설치 문서를 참고해 주세요.

 

yarn을 설치했다면 다음 명령어를 통해 vue-cli를 글로벌로 설치합니다.

 

yarn global add @vue/cli

 

 

위와 같이 vue-cli 설치가 완료되면 이제 vue 프로젝트를 생성할 준비가 다 되었습니다. 다음 명령어를 통해 vue 프로젝트를 생성해 봅시다.

 

vue create weather-app

 

위 명령어를 입력하면 다음과 같이 프리셋을 고르는 옵션이 보입니다. 

 

 

특별히 원하는 옵션이 없는 경우 Vue2를 사용하는 Default 옵션을 선택해 줍시다.

 

 

약간의 시간이 지난 후 위와 같이 Vue 프로젝트가 생성되게 됩니다. 안내에 표시된 대로 다음 명령어를 통해 프로젝트를 실행시켜 봅시다.

 

cd weather-app
yarn serve

 

 

정상적으로 실행이 되었다면 http://localhost:8080/으로 이동해 다음과 같은 기본 페이지를 확인할 수 있습니다.

 

 

 

 

4. 페이지 가다듬기.

 

이제 기본 페이지에서 불필요한 파일과 코드를 제거하고 날씨 정보를 표시해 줄 수 있도록 페이지를 수정해 보도록 하겠습니다.

 

우선 여기로 이동해 백그라운드 이미지를 다운로드하여줍니다. cold-bg.jpg와 warm-bg.jpg파일을 다운 받아 asset폴더에 저장해 주세요. 그리고 assets 폴더 내의 logo.png파일을 삭제한 뒤 App.vue 파일을 열어 내용을 다음과 같이 수정해 주세요.

 

<template>
  <div id="app">
    <main>
      <div class="search-box">
        <input type="text" class="search-bar" placeholder="Search..."/>
      </div>
    </main>
  </div>
</template>

<script>
export default {};
</script>

<style>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  font-family: 'montserrat', sans-serif;
}
#app {
  background-image: url('./assets/cold-bg.jpg');
  background-size: cover;
  background-position: bottom;
  transition: 0.4s;
}
main {
  min-height: 100vh;
  padding: 25px;
  background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.75));
}
.search-box {
  width: 100%;
  margin-bottom: 30px;
}
.search-box .search-bar {
  display: block;
  width: 100%;
  padding: 15px;
  
  color: #313131;
  font-size: 20px;
  appearance: none;
  border:none;
  outline: none;
  background: none;
  box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.25);
  background-color: rgba(255, 255, 255, 0.5);
  border-radius: 0px 16px 0px 16px;
  transition: 0.4s;
}
.search-box .search-bar:focus {
  box-shadow: 0px 0px 16px rgba(0, 0, 0, 0.25);
  background-color: rgba(255, 255, 255, 0.75);
  border-radius: 16px 0px 16px 0px;
}
</style>

 

파일을 저장하고 다시 localhost:8080으로 이동해 봅시다.

 

 

화면이 위와 같이 바뀐 게 보이시나요? 이제 우리는 임시 데이터를 갖고 날씨 정보를 표시해 볼 예정입니다. 다시 App.vue를 열고 코드를 수정해 주세요.

 

<template>
  <div id="app">
    <main>
      <div class="search-box">
        <input type="text" class="search-bar" placeholder="Search..." />
      </div>
      <div class="weather-wrap">
        <div class="location-box">
          <div class="location">Northampton, UK</div>
          <div class="date">Monday 20 January 2020</div>
        </div>
        <div class="weather-box">
          <div class="temp">9℃</div>
          <div class="weather">Rain</div>
        </div>
      </div>
    </main>
  </div>
</template>

<script>
export default {};
</script>

<style>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  font-family: "montserrat", sans-serif;
}
#app {
  background-image: url("./assets/cold-bg.jpg");
  background-size: cover;
  background-position: bottom;
  transition: 0.4s;
}
main {
  min-height: 100vh;
  padding: 25px;
  background-image: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.25),
    rgba(0, 0, 0, 0.75)
  );
}
.search-box {
  width: 100%;
  margin-bottom: 30px;
}
.search-box .search-bar {
  display: block;
  width: 100%;
  padding: 15px;

  color: #313131;
  font-size: 20px;
  appearance: none;
  border: none;
  outline: none;
  background: none;
  box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.25);
  background-color: rgba(255, 255, 255, 0.5);
  border-radius: 0px 16px 0px 16px;
  transition: 0.4s;
}
.search-box .search-bar:focus {
  box-shadow: 0px 0px 16px rgba(0, 0, 0, 0.25);
  background-color: rgba(255, 255, 255, 0.75);
  border-radius: 16px 0px 16px 0px;
}
.location-box .location {
  color: #fff;
  font-size: 32px;
  font-weight: 500;
  text-align: center;
  text-shadow: 1px 3px rgba(0, 0, 0, 0.25);
}
.location-box .date {
  color: #fff;
  font-size: 20px;
  font-weight: 300;
  font-style: italic;
  text-align: center;
}
.weather-box {
  text-align: center;
}
.weather-box .temp {
  display: inline-block;
  padding: 10px 25px;
  color: #fff;
  font-size: 102px;
  font-weight: 900;
  text-shadow: 3px 6px rgba(0, 0, 0, 0.25);
  background-color: rgba(255, 255, 255, 0.25);
  border-radius: 16px;
  margin: 30px 0px;
  box-shadow: 3px 6px rgba(0, 0, 0, 0.25);
}
.weather-box .weather {
  color: #fff;
  font-size: 48px;
  font-weight: 700;
  font-style: italic;
  text-shadow: 3px 6px rgba(0, 0, 0, 0.25);
}
</style>

 

위와 같이 코드를 수정하고 다시 localhost:8080로 이동해 보세요.

 

 

우리가 직접 넣은 데이터가 잘 표시되는 것을 확인할 수 있습니다.

 

 

 

5. API를 통해 데이터를 불러오기.

 

소스코드를 찬찬히 살펴보면 사실 지금까지 우리가 작성한 코드는 단지 html 약간과 화면을 꾸미기 위한 css가 전부임을 확인할 수 있습니다.

 

이제 우리가 앞에서 발급받은 API 키를 이용해 날씨 정보를 받아와 화면에 뿌려주는 로직을 작성해 보도록 하겠습니다.

 

먼저 App.vue의 script 영역을 다음과 같이 수정해 줍시다.

 

<script>
export default {
  data: function () {
    return {
      api_key: "YOUR_API_KEY_HERE",
      url_base: "https://api.openweathermap.org/data/2.5/",
      query: "",
      weather: {},
    };
  },
  methods: {
    fetchWeather: function (e) {
      if (e.key == "Enter") {
        let fetchUrl = `${this.url_base}weather?q=${this.query}&units=metric&APPID=${this.api_key}`;
        fetch(fetchUrl)
          .then((res) => {
            console.log(res);
            return res.json();
          })
          .then((results) => {
            return this.setResult(results);
          });
      }
    },
    setResult: function (results) {
      this.weather = results;
    },
    dateBuilder: function () {
      let d = new Date();
      let months = [
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December",
      ];
      let days = [
        "Sunday",
        "Monday",
        "Tuesday",
        "Wednesday",
        "Thursday",
        "Friday",
        "Saturday",
      ];
      let day = days[d.getDay()];
      let date = d.getDate();
      let month = months[d.getMonth()];
      let year = d.getFullYear();
      return `${day} ${date} ${month} ${year}`;
    },
  },
};
</script>

 

위에서부터 차근차근 보도록 합시다.

 

data 함수에는 vue 컴포넌트에서 사용할 데이터가 담겨 있습니다. 우리는 이제 이 컴포넌트에서 api_key, url_base, query, weather을 사용할 수 있습니다.

  • api_key에는 앞서 우리가 발급받은 API 키값을 넣어 주시면 됩니다.
  • url_base는 API를 호출할 URL입니다.
  • query는 search시 우리가 입력한 데이터가 들어갈 공간입니다.
  • weather은 검색 결과 데이터가 들어갈 공간입니다.

 

methods에는 이 컴포넌트에서 사용할 method들이 정의되어 있는 곳입니다.

  • fetchWeather 함수는 search에 값을 입력하고 엔터를 누를 경우 해당 값을 사용해 날씨를 검색해오는 작업을 수행합니다. 내부에서 fetch 함수를 사용하고 있으며 수행 결과를 promise를 사용해 json으로 변환한 뒤 결과를 data에 저장하는 작업을 수행합니다.
  • setResult는 입력받은 결과 값을 앞서 정의한 weather에 저장하는 역할을 수행합니다.
  • dateBuilder는 현재 시간을 보기 좋게 만들어주는 역할을 수행합니다.

 

다음으로 스크립트를 사용할 수 있도록 탬플릿을 수정해 줍시다. App.vue의 template영역을 다음과 같이 수정합니다.

 

<template>
  <div id="app">
    <main>
      <div class="search-box">
        <input
          type="text"
          class="search-bar"
          placeholder="Search..."
          v-model="query"
          @keypress="fetchWeather"
        />
      </div>
      <div class="weather-wrap" v-if="typeof weather.main != 'undefined'">
        <div class="location-box">
          <div class="location">{{weather.name}}, {{weather.sys.country}}</div>
          <div class="date">{{dateBuilder()}}</div>
        </div>
        <div class="weather-box">
          <div class="temp">{{weather.main.temp}}℃</div>
          <div class="weather">{{weather.weather[0].main}}</div>
        </div>
      </div>
    </main>
  </div>
</template>

 

새로 추가된 속성에 대해 차근차근 알아봅시다.

  • v-model은 해당 input에 입력된 값을 앞서 정의한 query에 저장해 주는 역할을 합니다. 
  • @keyprss는 해당 input에서 키가 입력될 때마다 fetchWeather함수를 실행시킵니다.
  • v-if는 if문의 역할을 합니다. weather.main이 'undefined'가 아닐 경우에만 해당 div를 표시합니다.
  • {{}}는 data에서 정의한 변수와 methods에 정의한 함수를 사용할 수 있도록 해줍니다.

 

이제 다시 페이지를 새로고침 후 seoul을 검색해 보세요.

 

 

위와 같이 표시되면 정상입니다. 그런데 기억하고 계신가요? 우리는 앞서 warm-bg.jpg도 같이 다운로드하였습니다. 위의 결과인 27.7℃는 충분히 따뜻한 온도이므로 배경화면을 바꿔서 표시해 주는 것이 좋아 보입니다.

 

앞서 설명한 v-if를 사용하면 됩니다. 마지막으로 코드를 다음과 같이 수정해 줍시다.

 

<template>
  <div
    id="app"
    :class="typeof weather.main !='undefined' && Math.round(weather.main.temp) > 16 ? 'warm' : ''"
  >
    <main>
      <div class="search-box">
        <input
          type="text"
          class="search-bar"
          placeholder="Search..."
          v-model="query"
          @keypress="fetchWeather"
        />
      </div>
      <div class="weather-wrap" v-if="typeof weather.main != 'undefined'">
        <div class="location-box">
          <div class="location">{{weather.name}}, {{weather.sys.country}}</div>
          <div class="date">{{dateBuilder()}}</div>
        </div>
        <div class="weather-box">
          <div class="temp">{{Math.round(weather.main.temp)}}℃</div>
          <div class="weather">{{weather.weather[0].main}}</div>
        </div>
      </div>
    </main>
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      api_key: "YOUR_API_KEY_HERE",
      url_base: "https://api.openweathermap.org/data/2.5/",
      query: "",
      weather: {},
    };
  },
  methods: {
    fetchWeather: function (e) {
      if (e.key == "Enter") {
        let fetchUrl = `${this.url_base}weather?q=${this.query}&units=metric&APPID=${this.api_key}`;
        fetch(fetchUrl)
          .then((res) => {
            console.log(res);
            return res.json();
          })
          .then((results) => {
            return this.setResult(results);
          });
      }
    },
    setResult: function (results) {
      this.weather = results;
    },
    dateBuilder: function () {
      let d = new Date();
      let months = [
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December",
      ];
      let days = [
        "Sunday",
        "Monday",
        "Tuesday",
        "Wednesday",
        "Thursday",
        "Friday",
        "Saturday",
      ];
      let day = days[d.getDay()];
      let date = d.getDate();
      let month = months[d.getMonth()];
      let year = d.getFullYear();
      return `${day} ${date} ${month} ${year}`;
    },
  },
};
</script>

<style>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  font-family: "montserrat", sans-serif;
}
#app {
  background-image: url("./assets/cold-bg.jpg");
  background-size: cover;
  background-position: bottom;
  transition: 0.4s;
}
#app.warm {
  background-image: url("./assets/warm-bg.jpg");
}
main {
  min-height: 100vh;
  padding: 25px;
  background-image: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.25),
    rgba(0, 0, 0, 0.75)
  );
}
.search-box {
  width: 100%;
  margin-bottom: 30px;
}
.search-box .search-bar {
  display: block;
  width: 100%;
  padding: 15px;

  color: #313131;
  font-size: 20px;
  appearance: none;
  border: none;
  outline: none;
  background: none;
  box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.25);
  background-color: rgba(255, 255, 255, 0.5);
  border-radius: 0px 16px 0px 16px;
  transition: 0.4s;
}
.search-box .search-bar:focus {
  box-shadow: 0px 0px 16px rgba(0, 0, 0, 0.25);
  background-color: rgba(255, 255, 255, 0.75);
  border-radius: 16px 0px 16px 0px;
}
.location-box .location {
  color: #fff;
  font-size: 32px;
  font-weight: 500;
  text-align: center;
  text-shadow: 1px 3px rgba(0, 0, 0, 0.25);
}
.location-box .date {
  color: #fff;
  font-size: 20px;
  font-weight: 300;
  font-style: italic;
  text-align: center;
}
.weather-box {
  text-align: center;
}
.weather-box .temp {
  display: inline-block;
  padding: 10px 25px;
  color: #fff;
  font-size: 102px;
  font-weight: 900;
  text-shadow: 3px 6px rgba(0, 0, 0, 0.25);
  background-color: rgba(255, 255, 255, 0.25);
  border-radius: 16px;
  margin: 30px 0px;
  box-shadow: 3px 6px rgba(0, 0, 0, 0.25);
}
.weather-box .weather {
  color: #fff;
  font-size: 48px;
  font-weight: 700;
  font-style: italic;
  text-shadow: 3px 6px rgba(0, 0, 0, 0.25);
}
</style>

 

완성된 코드입니다. 탬플릿의 #app에 v-if를 사용해 온도가 16℃보다 높은 경우 .warm 클래스를 추가하도록 했습니다. 추가된 클래스에 따라 백그라운드가 변경되도록 #app.warm에 대해 background-image가 변경되도록 스타일을 변경하였습니다. 또한 기존 소수점까지 표시되는 기온을 Math.round를 사용해 정수만 표시되도록 수정했습니다.

 

페이지에서 다시 서울을 검색해 보도록 하겠습니다.

 

 

이제 서울을 검색하니 백그라운드 이미지가 따뜻한 이미지로 변경되었습니다. 혹시 모르니 추운 도시를 검색해 봅시다. 남반구는 8월 지금 겨울입니다. 시드니를 검색해 보세요.

 

 

백그라운드 이미지가 정상적으로 변경되어 출력되는 것을 확인할 수 있습니다.

 

 

 

 

 

반응형

루프백을 사용하는 방법에 대해 알아봅니다.

 

 

 

 

1. Loopback

 

루프백을 한마디로 설명하자면 다음과 같습니다.

 

LoopBack은 Node.js에서 API 및 마이크로 서비스를 구축하기 위한 플랫폼입니다.

 

또한 공식 문서에서 추가적으로 루프백에 대해 다음과 같이 설명하고 있습니다.

 

LoopBack은 Express를 기반으로하는 확장 성이 뛰어난 오픈 소스 Node.js 및 TypeScript 프레임 워크로, 데이터베이스 및 SOAP 또는 REST 서비스와 같은 백엔드 시스템으로 구성된 API 및 마이크로 서비스를 신속하게 작성할 수 있습니다.

 

아래 다이어그램은 어떻게 LoopBack이 들어오는 요청과 나가는 결과들 사이에 다리 역할을 하고 있는지 보여줍니다. 또한 루프백이 제공하는 다양한 기능들도 보여줍니다.

 

 

이 글을 작성하는 시점에서 최신 버전인 Loopback4를 사용하도록 하겠습니다. Loopback3은 현재 여전히 마이그레이션 중이며 몇몇 기능은 루프백 4에서 동작하지 않을 수 있습니다. 이러한 차이점에 대해선 별도로 다루지 않으며 이 글을 참고해 주시기 바랍니다.

 

 

 

2. LoopBack4 시작하기

 

루프백4는 NodeJs 버전 10 이상을 요구합니다. 미리 설치해 줍시다.

 

NodeJs를 설치하고 난 뒤 아래의 명령어를 통해 LoopBack4 CLI를 설치합니다.

 

> npm i -g @loopback/cli

 

이 LoobBack CLI 도구는 프로젝트를 스캐폴딩 하고 TypeScript 컴파일러를 구성하며 필요한 모든 종속성을 설치합니다. 이제 다음과 같이 명령어를 입력해 프로젝트를 생성합니다.

 

> lb4 app

 

 

옵션을 선택해 프로젝트를 구성합니다. 구성이 완료되면 만들어진 프로젝트 폴더로 이동해 루프백을 실행합니다.

 

> cd loopback

> npm start

 

정상적으로 실행되었는지 확인해보기 위해 http://localhost:3000/ping 로 이동합니다. "greeting":"Hello from LoopBack"이 포함된 json 응답이 보이면 정상적으로 실행된 것입니다.

 

 

 

3. 컨트롤러 추가하기.

 

이제 간단하게 새로운 컨트롤러를 추가해 봅시다. 일단 Ctrl + C를 눌러 실행 중인 루프백을 먼저 종료해 줍니다. 그런 뒤 다음 명령어를 통해 새로운 컨트롤러를 추가합니다.

 

> lb4 controller

 

 

안내에 따라 컨트롤러 이름을 정한 뒤 유형을 선택합니다. 예시에서는 빈 컨트롤러를 선택하였습니다.

 

이제 디렉터리에 우리가 생성한 컨트롤러가 추가된 것을 확인할 수 있습니다. .\src\controllers\hello.controller.ts 파일을 열어보세요.

 

// Uncomment these imports to begin using these cool features!

// import {inject} from '@loopback/context';


export class HelloController {
  constructor() {}
}

 

빈 컨트롤러를 선택했기 때문에 아무런 동작을 하지 않습니다. 이제 여기에 hello에 대한 응답으로 "Hello world!"를 보내주도록 코드를 작성해 봅시다.

 

import { get } from "@loopback/rest";

export class HelloController {
    @get("/hello")
    hello(): string {
        return "Hello world!";
    }
}

 

이제 다시 루프백을 실행 후 http://localhost:3000/hello 로 이동합니다. 

 

 

정상적으로 보이시나요? 이렇게 원하는 컨트롤러를 추가해줄 수 있습니다.

 

 

 

 

 

반응형

+ Recent posts