컨텐츠로 건너뛰기

Drupal & Astro

Drupal은 오픈소스 콘텐츠 관리 도구입니다.

시작하려면 다음이 필요합니다:

  1. Astro 프로젝트 - 아직 Astro 프로젝트가 없는 경우, 설치 가이드를 참조하면 금방 시작할 수 있습니다.

  2. Drupal 사이트 - Drupal 사이트를 설정하지 않은 경우 공식 가이드라인 Drupal 설치하기를 따르세요.

JSON:API Drupal 모듈 설치하기

섹션 제목: JSON:API Drupal 모듈 설치하기

Drupal에서 콘텐츠를 가져오려면 Drupal JSON:API 모듈을 활성화해야 합니다.

  1. Manage administrative 메뉴를 통해 Extend 페이지 admin/modules로 이동합니다.
  2. JSON:API 모듈을 찾아 옆의 확인란을 선택합니다.
  3. Install을 클릭하여 새 모듈을 설치합니다.

이제 JSON:API를 통해 Drupal 애플리케이션에 GET 요청을 할 수 있습니다.

.env에 Drupal URL 추가하기

섹션 제목: .env에 Drupal URL 추가하기

Astro에 Drupal URL을 추가하려면 프로젝트의 루트에 .env 파일을 만들고 (아직 없는 경우) 다음 변수를 추가하세요:

.env
DRUPAL_BASE_URL="https://drupal.ddev.site/"

개발 서버를 재시작하여 Astro 프로젝트에서 이 환경 변수를 사용하세요.

기본적으로 외부 데이터 가져오기 요청에 대해 인증 없이도 Drupal JSON:API 엔드포인트에 액세스할 수 있습니다. 이를 통해 자격 증명 없이도 Astro 프로젝트에서 데이터를 가져올 수 있지만 사용자가 데이터나 사이트 설정을 수정할 수는 없습니다.

그러나 액세스를 제한하고 인증이 필요한 경우 Drupal은 다음과 같은 여러 인증 방법을 제공합니다:

.env 파일에 자격 증명을 추가할 수 있습니다.

.env
DRUPAL_BASIC_USERNAME="editor"
DRUPAL_BASIC_PASSWORD="editor"
DRUPAL_JWT_TOKEN="abc123"
...
Astro의 환경 변수 사용.env 파일에 대해 자세히 알아보세요.

이제 루트 디렉터리에 이 새 파일들이 포함되어야 합니다:

  • .env
  • astro.config.mjs
  • package.json

JSON:API 요청과 응답은 종종 복잡하고 깊게 중첩될 수 있습니다. 작업을 간소화하기 위해 요청과 응답 처리를 모두 간소화하는 두 가지 npm 패키지를 사용할 수 있습니다:

  • JSONA: 서버와 브라우저에서 사용하기 위해 JSON API v1.0 사양을 직렬화 및 역직렬화 할 수 있습니다.
  • Drupal JSON-API Params: 이 모듈은 필요한 쿼리를 생성하는 헬퍼 클래스를 제공합니다. 이 과정에서 가능한 경우 짧은 형식을 사용하여 쿼리를 최적화하려고 시도합니다.
Terminal window
npm install jsona drupal-jsonapi-params

Drupal에서 데이터 가져오기

섹션 제목: Drupal에서 데이터 가져오기

콘텐츠는 JSON:API URL에서 가져옵니다.

기본 URL 구조: /jsonapi/{entity_type_id}/{bundle_id}

URL 앞에는 항상 jsonapi가 붙습니다.

  • entity_type_id는 node, block, user 등의 엔티티 타입을 나타냅니다.
  • bundle_id는 엔티티 번들을 나타냅니다. Node 엔티티 타입의 경우 번들은 article이 될 수 있습니다.
  • 이 경우 모든 articles 목록을 가져오기 위해 URL은 [DRUPAL_BASE_URL]/jsonapi/node/article이 됩니다.

개별 엔티티를 검색하기 위한 URL 구조는 /jsonapi/{entity_type_id}/{bundle_id}/{uuid}이며, 여기서 uuid는 엔티티의 UUID입니다. 예를 들어 특정 article을 가져오는 URL은 /jsonapi/node/article/2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e 형태가 됩니다.

쿼리 문자열 필드를 요청에 추가하여 특정 필드만 검색합니다.

GET: /jsonapi/{entity_type_id}/{bundle_id}?field[entity_type]=field_list

예시:

  • /jsonapi/node/article?fields[node--article]=title,created
  • /jsonapi/node/article/2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e?fields[node--article]=title,created,body

쿼리 문자열 필터를 추가하여 요청에 필터를 추가합니다.

가장 간단하고 일반적인 필터는 키-값 필터입니다: GET: /jsonapi/{entity_type_id}/{bundle_id}?filter[field_name]=value&filter[field_other]=value

예시:

  • /jsonapi/node/article?filter[title]=Testing JSON:API&filter[status]=1
  • /jsonapi/node/article/2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e?fields[node--article]=title&filter[title]=Testing JSON:API

더 많은 쿼리 옵션은 JSON:API 문서에서 확인할 수 있습니다.

Astro 컴포넌트는 drupal-jsonapi-params 패키지로 쿼리를 작성하여 Drupal 사이트에서 데이터를 가져올 수 있습니다.

다음 예시는 “article” 콘텐츠 타입을 쿼리하는 컴포넌트를 보여줍니다. 이 콘텐츠 타입은 제목용 일반 텍스트 필드와 본문용 서식 있는 텍스트 필드를 포함하고 있습니다.

---
import {Jsona} from "jsona";
import {DrupalJsonApiParams} from "drupal-jsonapi-params";
import type {TJsonApiBody} from "jsona/lib/JsonaTypes";
// Drupal 기본 URL 가져오기
export const baseUrl: string = import.meta.env.DRUPAL_BASE_URL;
// JSON:API 쿼리를 생성합니다. 게시된 articles에서 모든 제목과 본문을 가져옵니다.
const params: DrupalJsonApiParams = new DrupalJsonApiParams();
params.addFields("node--article", [
"title",
"body",
])
.addFilter("status", "1");
// 쿼리 문자열 생성
const path: string = params.getQueryString();
const url: string = baseUrl + '/jsonapi/node/article?' + path;
// articles 가져오기
const request: Response = await fetch(url);
const json: string | TJsonApiBody = await request.json();
// Jsona 초기화
const dataFormatter: Jsona = new Jsona();
// 응답 역직렬화
const articles = dataFormatter.deserialize(json);
---
<body>
{articles?.length ? articles.map((article: any) => (
<section>
<h2>{article.title}</h2>
<article set:html={article.body.value}></article>
</section>
)): <div><h1>No Content found</h1></div> }
</body>

더 많은 쿼리 옵션은 Drupal JSON:API 문서에서 확인할 수 있습니다.

Astro 및 Drupal로 블로그 만들기

섹션 제목: Astro 및 Drupal로 블로그 만들기

위의 설정으로 이제 Drupal을 CMS로 사용하는 블로그를 만들 수 있습니다.

  1. JSONADrupal JSON-API Params가 설치된 Astro 프로젝트

  2. 항목이 하나 이상 있는 Drupal 사이트 - 이 튜토리얼에서는 표준 설치로 새 Drupal 사이트를 시작하는 것을 권장합니다.

    Drupal 사이트의 Content 섹션에서 Add 버튼을 클릭하여 새 항목을 만듭니다. 그런 다음 Article을 선택하고 필드를 채웁니다:

    • Title: My first article for Astro!
    • Alias: /articles/first-article-for astro
    • Description: This is my first Astro article! Let's see what it will look like!

    Save를 클릭하여 첫 번째 Article을 작성합니다. 원하는 만큼 자유롭게 articles를 추가할 수 있습니다.

  1. 아직 존재하지 않는 경우 src/types.ts를 생성하고 다음 코드를 사용하여 DrupalNodePath라는 두 개의 새 인터페이스를 추가합니다. 이 인터페이스는 Drupal의 article 콘텐츠 타입 필드 및 Path 필드와 일치합니다. 이를 사용하여 article 항목 응답에 대한 타입을 정의합니다.

    src/types.ts
    export interface Path {
    alias: string
    pid: number
    langcode: string
    }
    export interface DrupalNode extends Record<string, any> {
    id: string
    type: string
    langcode: string
    status: boolean
    drupal_internal__nid: number
    drupal_internal__vid: number
    changed: string
    created: string
    title: string
    default_langcode: boolean
    sticky: boolean
    path: Path
    }

    이제 src 디렉터리에 새 파일이 포함되어야 합니다:

    • .env
    • astro.config.mjs
    • package.json
    • 디렉터리src/
      • types.ts
  2. src/apidrupal.ts라는 새 파일을 만들고 다음 코드를 추가합니다:

    src/api/drupal.ts
    import {Jsona} from "jsona";
    import {DrupalJsonApiParams} from "drupal-jsonapi-params";
    import type {DrupalNode} from "../types.ts";
    import type {TJsonApiBody} from "jsona/lib/JsonaTypes";
    // Drupal 기본 Url을 가져옵니다.
    export const baseUrl: string = import.meta.env.DRUPAL_BASE_URL;

    이렇게 하면 응답을 역직렬화하기 위한 Jsona, 요청 URL 및 Node와 Jsona 타입의 형식을 지정하는 DrupalJsonApiParams와 같은 필수 라이브러리를 가져옵니다. 또한 .env 파일에서 baseUrl을 가져옵니다.

    이제 src/api 디렉터리에 새 파일이 포함되어야 합니다:

    • .env
    • astro.config.mjs
    • package.json
    • 디렉터리src/
      • 디렉터리api/
        • drupal.ts
      • types.ts
  3. 같은 파일에서 fetchUrl 함수를 생성하여 가져오기 요청을 하고 응답을 역직렬화합니다.

    src/api/drupal.ts
    import {Jsona} from "jsona";
    import {DrupalJsonApiParams} from "drupal-jsonapi-params";
    import type {DrupalNode} from "../types.ts";
    import type {TJsonApiBody} from "jsona/lib/JsonaTypes";
    // Drupal 기본 Url 가져오기
    export const baseUrl: string = import.meta.env.DRUPAL_BASE_URL;
    /**
    * Fetch url from Drupal.
    *
    * @param url
    *
    * @return Promise<TJsonaModel | TJsonaModel[]> as Promise<any>
    */
    export const fetchUrl = async (url: string): Promise<any> => {
    const request: Response = await fetch(url);
    const json: string | TJsonApiBody = await request.json();
    const dataFormatter: Jsona = new Jsona();
    return dataFormatter.deserialize(json);
    }
  4. 게시된 모든 articles를 가져오는 getArticles() 함수를 만듭니다.

    src/api/drupal.ts
    import {Jsona} from "jsona";
    import {DrupalJsonApiParams} from "drupal-jsonapi-params";
    import type {DrupalNode} from "../types.ts";
    import type {TJsonApiBody} from "jsona/lib/JsonaTypes";
    // Drupal 기본 Url 가져오기
    export const baseUrl: string = import.meta.env.DRUPAL_BASE_URL;
    /**
    * Fetch url from Drupal.
    *
    * @param url
    *
    * @return Promise<TJsonaModel | TJsonaModel[]> as Promise<any>
    */
    export const fetchUrl = async (url: string): Promise<any> => {
    const request: Response = await fetch(url);
    const json: string | TJsonApiBody = await request.json();
    const dataFormatter: Jsona = new Jsona();
    return dataFormatter.deserialize(json);
    }
    /**
    * Get all published articles.
    *
    * @return Promise<DrupalNode[]>
    */
    export const getArticles = async (): Promise<DrupalNode[]> => {
    const params: DrupalJsonApiParams = new DrupalJsonApiParams();
    params
    .addFields("node--article", [
    "title",
    "path",
    "body",
    "created",
    ])
    .addFilter("status", "1");
    const path: string = params.getQueryString();
    return await fetchUrl(baseUrl + '/jsonapi/node/article?' + path);
    }

    이제 .astro 컴포넌트에서 getArticles() 함수를 사용하여 각 제목, 본문, 경로, 작성 날짜에 대한 데이터가 포함된 게시된 모든 articles를 가져올 수 있습니다.

  5. Drupal에서 데이터를 가져올 Astro 페이지로 이동합니다. 다음 예시는 src/pages/articles/index.astro에 articles 랜딩 페이지를 만듭니다.

    필요한 종속성을 가져오세요. 그리고 getArticles() 함수를 사용하여 Drupal에서 article 콘텐츠 타입의 모든 항목을 가져오세요. 이때 응답의 타입을 지정하기 위해 DrupalNode 인터페이스를 함수에 전달하세요.

    src/pages/articles/index.astro
    ---
    import {Jsona} from "jsona";
    import {DrupalJsonApiParams} from "drupal-jsonapi-params";
    import type {TJsonApiBody} from "jsona/lib/JsonaTypes";
    import type { DrupalNode } from "../../types";
    import {getArticles} from "../../api/drupal";
    // 게시된 모든 articles 가져오기
    const articles = await getArticles();
    ---

    getArticles()를 사용한 이 가져오기 호출은 페이지 템플릿에서 사용할 수 있는 항목의 타입이 있는 배열을 반환합니다.

    동일한 페이지 파일을 사용했다면 이제 src/pages/ 디렉터리에 새 파일이 포함되어야 합니다:

    • .env
    • astro.config.mjs
    • package.json
    • 디렉터리src/
      • 디렉터리api/
        • drupal.ts
      • 디렉터리pages/
        • 디렉터리articles/
          • index.astro
      • types.ts
  6. 제목과 같은 콘텐츠를 페이지에 추가합니다. articles.map()을 사용하여 Drupal 항목을 목록의 줄 항목으로 표시합니다.

    src/pages/articles/index.astro
    ---
    import {Jsona} from "jsona";
    import {DrupalJsonApiParams} from "drupal-jsonapi-params";
    import type {TJsonApiBody} from "jsona/lib/JsonaTypes";
    import type { DrupalNode } from "../types";
    import {getArticles} from "../api/drupal";
    // 게시된 모든 articles 가져오기
    const articles = await getArticles();
    ---
    <html lang="en">
    <head>
    <title>My news site</title>
    </head>
    <body>
    <h1>My news site</h1>
    <ul>
    {articles.map((article: DrupalNode) => (
    <li>
    <a href={article.path.alias.replace("internal:en/", "")}>
    <h2>{article.title}</h2>
    <p>Published on {article.created}</p>
    </a>
    </li>
    ))}
    </ul>
    </body>
    </html>

개별 블로그 게시물 생성

섹션 제목: 개별 블로그 게시물 생성

위와 동일한 방법을 사용하여 Drupal에서 데이터를 가져오되 이번에는 각 article에 대해 고유한 페이지 경로를 만드는 페이지에서 데이터를 가져옵니다.

이 예시는 Astro의 기본 정적 모드를 사용하고 getStaticPaths() 함수를 사용하여 동적 라우팅 페이지 파일을 생성합니다. 이 함수는 빌드 시 호출되어 페이지가 되는 경로 목록을 생성합니다.

  1. 새 파일 src/pages/articles/[path].astro를 만들고 src/api/drupal.ts에서 DrupalNode 인터페이스와 getArticle()을 가져옵니다. getStaticPaths() 함수에서 데이터를 가져와 블로그의 경로를 만듭니다.

    src/pages/articles/[path].astro
    ---
    import {Jsona} from "jsona";
    import {DrupalJsonApiParams} from "drupal-jsonapi-params";
    import type {TJsonApiBody} from "jsona/lib/JsonaTypes";
    import type { DrupalNode } from "../../types";
    import {getArticles} from "../../api/drupal";
    // 게시된 모든 articles 가져오기
    export async function getStaticPaths() {
    const articles = await getArticles();
    }
    ---

    이제 src/pages/articles 디렉터리에 새 파일이 포함되어야 합니다:

    • .env
    • astro.config.mjs
    • package.json
    • 디렉터리src/
      • 디렉터리api/
        • drupal.ts
      • 디렉터리pages/
        • 디렉터리articles/
          • index.astro
          • [path].astro
      • types.ts
  2. 같은 파일에서 각 Drupal 항목을 paramsprops 속성을 가진 객체에 매핑합니다. params 속성은 페이지의 URL을 생성하는 데 사용되며 props 값은 페이지 컴포넌트에 props로 전달됩니다.

    src/pages/articles/[path].astro
    ---
    import {Jsona} from "jsona";
    import {DrupalJsonApiParams} from "drupal-jsonapi-params";
    import type {TJsonApiBody} from "jsona/lib/JsonaTypes";
    import type { DrupalNode } from "../../types";
    import {getArticles} from "../../api/drupal";
    // 게시된 모든 articles 가져오기
    export async function getStaticPaths() {
    const articles = await getArticles();
    return articles.map((article: DrupalNode) => {
    return {
    params: {
    // `path`를 `[path]` 라우팅 값과 일치하도록 선택
    path: article.path.alias.split('/')[2]
    },
    props: {
    title: article.title,
    body: article.body,
    date: new Date(article.created).toLocaleDateString('en-EN', {
    day: "numeric",
    month: "long",
    year: "numeric"
    })
    }
    }
    });
    }
    ---

    params 내부의 속성은 동적 경로의 이름과 일치해야 합니다. 파일 이름이 [path].astro이므로 params에 전달되는 속성 이름은 path여야 합니다.

    예시에서 props 객체는 페이지에 세 가지 속성을 전달합니다:

    • title: 글의 제목을 나타내는 문자열입니다.
    • body: 글의 내용을 나타내는 문자열입니다.
    • created: 파일 작성 날짜를 기준으로 한 타임스탬프입니다.
  3. 페이지 props를 사용하여 블로그 글을 표시합니다.

    src/pages/articles/[path].astro
    ---
    import {Jsona} from "jsona";
    import {DrupalJsonApiParams} from "drupal-jsonapi-params";
    import type {TJsonApiBody} from "jsona/lib/JsonaTypes";
    import type { DrupalNode } from "../../types";
    import {getArticles} from "../../api/drupal";
    // 게시된 모든 articles 가져오기
    export async function getStaticPaths() {
    const articles = await getArticles();
    return articles.map((article: DrupalNode) => {
    return {
    params: {
    path: article.path.alias.split('/')[2]
    },
    props: {
    title: article.title,
    body: article.body,
    date: new Date(article.created).toLocaleDateString('en-EN', {
    day: "numeric",
    month: "long",
    year: "numeric"
    })
    }
    }
    });
    }
    const {title, created, body} = Astro.props;
    ---
    <html lang="en">
    <head>
    <title>{title}</title>
    </head>
    <body>
    <h1>{title}</h1>
    <time>{date}</time>
    <article set:html={body.value} />
    </body>
    </html>
  4. 개발 서버 미리 보기로 이동하여 게시물 중 하나를 클릭하여 동적 경로가 작동하는지 확인합니다.

웹사이트를 배포하려면 배포 가이드를 방문하여 선호하는 호스팅 제공업체의 지침을 따르세요.

더 많은 CMS 안내서

기여하기

여러분의 생각을 들려주세요!

GitHub Issue 생성

우리에게 가장 빨리 문제를 알려줄 수 있어요.

커뮤니티