Hasura를 Discourse의 Postgres 데이터베이스에 연결하여 더 맞춤화되거나 범위가 좁아진 FE를 만들 수 있다는 생각을 해본 분이 있나요?

  • 사용해 봤고, 좋은 아이디어
  • 사용해 봤고, 나쁜 아이디어
  • 아직 안 해봤지만, 흥미롭다
  • 왜 이걸에 시간을 낭비하죠?
  • 잘 모르겠는데…
  • 기타
0 voters

재밌네요, 며칠 전 제가 정확히 이렇게 했거든요!

Hasura/nuxt.js를 1년째 다양한 프로젝트에서 사용하고 있습니다.
Hasura는 매우 강력하고, 예정된 기능들도 매우 기대됩니다!

discourse 포럼을 매우 좋아하지만(Ruby와 Ember는 잘 몰라서요), Hasura를 여기에 적용해 보았습니다.

Ruby 개발자가 아니어서 설치가 필요했는데, Mac에서 개발 환경을 설치하는 데 몇 가지 문제가 있었습니다. cppjieba_rb gem 때문에 고생하고 있어요…

그래서 결국 이 덤프를 가져와서 PostgreSQL과 Hasura에 설정했습니다.

모든 테이블이 가져온 것 같습니다. 뷰는 하나만 있나요? (badge_posts)
모든 외래키 관계도 추적했기 때문에, 다음과 같은 쿼리를 수행할 수 있습니다:

{
  posts {
    id
    user_id
    bookmarks {
      id
      name
    }
    uploads {
      id
      url
    }
  }
}

지금은 여기까지 왔습니다…

와, 기대되네요. 실환경에서 Hasura 컨테이너를 실행해 보고 결과를 공유하겠습니다. 정보를 교환해 볼 수 있겠네요.

참고로, 실행 중인 Discourse의 Postgres 데이터베이스 서버에서 psql 셸을 실행하려면 docker exec --user postgres -it app psql -d discourse를 사용할 수 있습니다. 따라서 전체 덤프를 생성하려면 다음을 실행할 수 있습니다(이 경우 -t 옵션은 필요 없으므로 제거했습니다):

docker exec --user postgres -i app pg_dump -Fc -d discourse > discourse.sql.pgcustom

이제 이를 도커화된 postgres(docker pull postgres:10.12)에 복원하고 개발을 위해 Hasura에 연결할 수 있습니다(이제 별도의 데이터베이스이므로 읽기 전용 수준에서만 실제로 유용합니다).

프로덕션 수준으로 이를 수행하려면, Discourse가 제공하는 환경을 설정하고 Amazon RDS와 같은 서비스에 데이터베이스를 호스팅해야 합니다. 그러면 해당 데이터베이스에 대한 읽기 및 쓰기 액세스가 용이해집니다.

위 덤프를 로컬에 복원하려면:

  1. 도커 네트워크 생성:
docker network create discourse-dev-net
  1. 첫 번째 셸에서:
docker run --rm -it -p 2345:5432 -e POSTGRES_DB=discourse -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres --name=discourse-dev-pg --network=discourse-dev-net postgres:10.12

(백그라운드에서 실행하려면 -it 대신 -d를 사용하면 됩니다. -p 2345:5432는 선택 사항이지만 호스트에서 postgres에 연결하려는 경우 편리합니다)

  1. 다른 셸에서 postgres에 discourse 사용자 생성(덤프에 필요):
docker run --rm -it -v /path/to/discourse.sql.pgcustom:/discourse.sql.pgcustom:ro -e PGPASSWORD=postgres --network=discourse-dev-net postgres:10.12 createuser -h discourse-dev-pg -U postgres -P discourse

(그 후 프롬프트에서 비밀번호를 두 번 입력합니다. 저는 discourse를 비밀번호로 사용했습니다)

  1. 복원 수행:
docker run --rm -i -v /home/dean/Downloads/discourse.sql.pgcustom:/discourse.sql.pgcustom:ro -e PGPASSWORD=postgres --network=discourse-dev-net postgres:10.12 pg_restore -h discourse-dev-pg -U postgres -d discourse /discourse.sql.pgcustom
  1. Hasura를 위 설정에 연결하려면:
docker run --rm -it --network=discourse-dev-net -p 1234:1234 -e HASURA_GRAPHQL_ENABLE_CONSOLE=true -e HASURA_GRAPHQL_DATABASE_URL=postgres://postgres:postgres@discourse-dev-pg:5432/discourse hasura/graphql-engine:v1.2.1 graphql-engine serve --server-port=1234

(이제 http://localhost:1234을 방문할 수 있습니다)

상속된 데이터베이스를 직접 다루어 보니, @Falco 님이 이 게시물에서 지적한 내용이 매우 명확하게 드러났습니다.

Postgres의 강력한 기능 중 거의 대부분이 활용되지 않고 있습니다. 로직의 거의 전부가 Ruby 쪽에서 처리되고 있죠.

따라서 제 결론은, 이 접근법 자체가 완전히 도움이 되지 않는다는 것입니다.

다른 방법으로는 Hasura의 원격 스키마 기능을 사용하는 것이 있지만, 이를 위해서는 Discourse가 REST가 아닌 GraphQL API를 제공해야 합니다… 따라서 이 역시 자체적으로는 큰 도움이 되지 않습니다.

하지만 기존 REST API를 GraphQL 레이어로 감싸는 방법이 있습니다. 이는 위에서 언급한 방법들보다(또는 그것들과 결합했을 때) 더 유망해 보입니다. 해당 기사에서는 시작할 수 있는 보일러플레이트 코드가 포함된 저장소를 안내하고 있습니다.

답변해 주셔서 감사합니다.

저는 도커를 아주 잘 다루지는 못하지만, 제 문제는 도커 쪽에 있는 것이 아닙니다. discourse 개발 환경을 설정할 수 없어서 데이터베이스가 없습니다… 그저 이 빈 덤프 파일만 있을 뿐입니다.

어쨌든, 저는 이 덤프를 Heroku 인스턴스에 바로 배포했습니다! 그래서 라이브로 직접 테스트해 보실 수 있습니다 :slight_smile:
이 온라인 GraphiQL에 접속하여 아래 엔드포인트를 설정해 보세요:
https://discourse-hasura.herokuapp.com/v1/graphql
자유롭게 조작해 보실 수 있습니다! 관리자 비밀번호가 없으므로 mutation과 subscription도 수행할 수 있습니다…

Hasura에서 discourse를 테스트하면서 제가 발견한 바로는, 모든 커스텀 함수, 트리거, 계산 필드… 모두 Ruby로 정의되어 있습니다. 이식성 측면에서 좋지 않습니다 :confused:

큰 도움이 되지 않습니다. discourse GraphQL API가 없기 때문이죠. 하지만 이는 Hasura의 강력한 기능입니다. 저는 Stripe의 커스텀 GraphQL과 함께 이 기능을 많이 사용하고 있습니다. 만약 discourse GraphQL API가 있다면, 리모트 스키마를 통해 우리 자신의 GraphQL에 연결할 수 있을 것입니다!

네, 하지만 모든 스키마와 리졸버(resolver)를 직접 구축해야 합니다. 작업량이 상당합니다!
여기서는 discourse의 Open API를 사용하는 것이 더 나을 것 같습니다: https://docs.discourse.org/ (다운로드 버튼 참고), 그리고 https://graphql-mesh.com/docs/handlers/openapi와 같은 GraphQL 생성기를 함께 사용하면 됩니다.
가능한 한 빨리 시도해 보겠습니다…

오, 기대됩니다! graphql-mesh를 시도해 보았습니다.
하지만 https://docs.discourse.org/ 의 다운로드 버튼 아래에 있는 openapi 파일이 깨져 있는 것 같습니다 :confused:
여기에서 유효성을 검사해 봤는데, 다음과 같은 오류가 나네요:

Swagger schema validation failed. 
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/3
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/3
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/3
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/2
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/2
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/2
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/1
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/1
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/1
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/0
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/0
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/0
 
JSON_OBJECT_VALIDATION_FAILED

Error: Swagger schema validation failed. 
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/3
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/3
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/3
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/2
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/2
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/2
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/1
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/1
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/1
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/0
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/0
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/0
 
JSON_OBJECT_VALIDATION_FAILED
    at o (https://apitools.dev/swagger-parser/online/js/bundle.min.js:1:73766)
    at https://apitools.dev/swagger-parser/online/js/bundle.min.js:17:227596

SyntaxError: Swagger schema validation failed. 
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/3
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/3
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/3
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/2
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/2
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/2
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/1
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/1
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/1
  Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/0
    Data does not match any schemas from 'oneOf' at #/paths//page_view_total_reqs/get/parameters/0
      Missing required property: schema at #/
      Missing required property: content at #/
    Missing required property: $ref at #/paths//page_view_total_reqs/get/parameters/0
 
JSON_OBJECT_VALIDATION_FAILED
    at Function.o [as syntax] (https://apitools.dev/swagger-parser/online/js/bundle.min.js:1:73766)
    at validateSchema (https://apitools.dev/swagger-parser/online/js/bundle.min.js:1:5021)
    at SwaggerParser.validate (https://apitools.dev/swagger-parser/online/js/bundle.min.js:1:3171)

z-schema validation error: JSON_OBJECT_VALIDATION_FAILED
    at ZSchema.getLastError (https://apitools.dev/swagger-parser/online/js/bundle.min.js:17:211187)
    at validateSchema (https://apitools.dev/swagger-parser/online/js/bundle.min.js:1:4925)
    at SwaggerParser.validate (https://apitools.dev/swagger-parser/online/js/bundle.min.js:1:3171)

그래서 discourse API의 다른 openapi나 swagger 파일을 찾아보았습니다. 이것만 찾았네요.
426번째 줄이 조금 깨져 있긴 했지만, 제가 직접 수정했습니다.

graphql-mesh를 설정한 후, 작동하는 graphql API를 만들 수 있었습니다! 그런데…
이 swagger 파일은 불완전하거나 너무 오래된 것 같습니다. 쿼리가 4개뿐이고, mutation은 없으며, user 타입의 속성도 몇 개만 있네요… :confused:

discourse의 swagger나 openapi 파일을 구할 수 있는 곳이 있을까요?

유망해 보이는 작업입니다. 잘하셨습니다! Discourse가 Swagger/OpenAPI와 같은 오픈 스펙을 준수하면 좋겠습니다. 찾고 있는 정보를 찾기를 바랍니다.

지금 이 일에 쓸 시간이 많지 않지만, 나중에 다시 확인해 보겠습니다.

흥미로운 작업이네요. 현재 상태에서 어떤 graphql 쿼리가 가능한지 확인해볼 수 있도록 해당 코드를 어디에 공개해 두셨나요?

기타로 투표하려고 했는데 작동하지 않았습니다.

늦게 답변드려 죄송합니다. 질문을 놓쳤습니다.
네, discourse hasura graphql 엔드포인트로 플레이할 수 있습니다: