オープンソースなローコードプラットフォーム



社内でローコード／ノーコードに関するトピックが多くなってきまして、どんなツールを使用してそれを実現するのかといった場合、プロプライエタリまたは商用ライセンスのプラットフォームの名前があがっておりました。

なにからどう始めたらよいかわからない場合、初めの足がかりや、技術サポートなどを考えるとその選択肢も理解できます。

では、オープンソースでそれを実現する場合に、どんな選択肢があるのか？というところで気になったので試してみました。

## OSSなローコードプラットフォーム

ローコードツールと表現しないようなものも含みますが、いろいろな系統がありますのでざっと紹介します。  
基準としては、GitHubのスターが多いものや、ニュースで聞いたことがあるものを選びました。

* Budibase <https://github.com/Budibase/budibase>  &#11088;13820

  内部ツールと言われる位置づけのツール。内部ツールとは、集客やコンシューマに向けた外向けの画面ではなく、内部だけで使うような管理ツール、ダッシュボード、CRUD画面の作成を目的としたツールを指します。既存のDBと接続可能なタイプ

* convertigo <https://www.convertigo.com/>  &#11088;139

  Eclipseをベースにした開発ツールでconvertigoサーバと通信しながら開発するスタイル。
  Eclipse Foundationに加盟というニュースを見て、触ってみましたがチュートリアルは完走しませんでした。

* Appsmith <https://github.com/appsmithorg/appsmith>  &#11088;18934

    内部ツール系。既存のDBと接続可能なタイプ

* ToolJet <https://github.com/ToolJet/ToolJet>        &#11088;11344

    内部ツール系。既存のDBと接続可能なタイプ

* strapi <https://github.com/strapi/strapi>  &#11088;45768

    headless CMS系。ヘッドレスCMSとは、バックエンドの機能だけを持ち、見た目やUIを作るフロントエンドは持ちません。  
    フロントエンドの自由度が高くなり、好きなやり方でフロントエンド開発に集中できます。

* supabase <https://github.com/supabase/supabase>   &#11088;34598

    BaaS(Backend as a Service)系。 Google Firebaseの代わりを目的としたようなツール。こちらも見た目やUIを作るフロントエンドは持ちません。  
    ユーザ管理、認証、CRUD API、ストレージなどの機能を提供します。  
    まだパブリックベータ版の段階ですが人気の高さがうかがえます。

* Hausa <https://github.com/hasura/graphql-engine>   &#11088;27222

    DBを統合したGraphQLサーバ。どの権限にたいしてどのテーブルの、どの列を更新/挿入許可するかなどを管理画面で定義してGraphQL APIを作成できます。  
    見た目やUIを作るフロントエンドは持ちません。フロントエンドにGraphQLを利用した開発が可能なチームであれば、これほどラクなことはないでしょう。人気です。

上記のツールは、クラウドサービス化されているものもありますが、すべてローカル、オンプレなどでセルフホスティング可能なものとなります。

## Webを作成してみる

試しにBudibaseで、外部APIとの連携を想定したニュースリーダーを作ってみます。  
完成イメージとしては以下のような、スポーツとITという部分がタブで切り替えられるようなものです。

![screencapture40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/61b0b80d-cef9-ba2c-6adc-5a6a7c450b7a.png)

Budibaseを選んだ理由としては、Microsoft, Apple, LOUIS VUITTON, P&G, NFL, googleなどの利用実績がありそうだったので選びました。  
BudibaseはBudibase Cloud(<https://budibase.com/>) を使用して作成するか、Docker、Kubernetes、などを使用してアプリをセルフホストできます。今回はdockerを使用します。  
データベースはPostgreSQL、Rest API、MS SQL、MySQLなどのデータソースに接続することも、Budibaseの組み込みデータベース（CouchDBの上に構築されたBudibase DB）でゼロから始めることもできます。

## 環境

Windows 10のWSL(Ubuntu20.04)にインストールしたdockerで構築してみます。

~~~bash
$ docker -v
Docker version 20.10.14, build a224086
$ docker-compose -v
Docker Compose version v2.4.1
~~~

## budibase CLI のインストール

Buidibaseはコマンドラインインターフェイスを使用してセットアップ用docker-composeファイルを作成したり、アプリを起動/停止できます。

~~~bash

$ mkdir budi-sample
$ cd budi-sample
$ wget https://github.com/Budibase/budibase/releases/latest/download/cli-linux
$ chmod +x cli-linux
$ mv cli-linux budi
$ ./budi help
Usage: budi [command]
…
~~~

## 初期設定

初期設定でポートなどを指定すると、docker-compose.ymlと.envファイルが作成されます。  
※コマンドラインツールは外部通信が行われるため、proxy環境ではエラーとなるようでした。  

~~~bash
$  ./budi hosting --init
? This will create multiple files in current directory, should continue? (Y/n) Y
? Please enter the port on which you want your installation to run:  10000
Configuration has been written successfully - please check .env file for more details.
~~~

作成されたdocker-compose.ymlは以下のようになります。  
コピペして保存し、.envファイルで環境変数を設定することで、コマンドラインツールがなくても、docker-compose upで起動も可能です。

~~~yml
version: "3"

# optional ports are specified throughout for more advanced use cases.

services:
  app-service:
    restart: unless-stopped
    image: budibase.docker.scarf.sh/budibase/apps
    container_name: bbapps
    environment:
      SELF_HOSTED: 1
      COUCH_DB_URL: http://${COUCH_DB_USER}:${COUCH_DB_PASSWORD}@couchdb-service:5984
      WORKER_URL: http://worker-service:4003
      MINIO_URL: http://minio-service:9000
      MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
      MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
      INTERNAL_API_KEY: ${INTERNAL_API_KEY}
      BUDIBASE_ENVIRONMENT: ${BUDIBASE_ENVIRONMENT}
      PORT: 4002
      JWT_SECRET: ${JWT_SECRET}
      LOG_LEVEL: info
      SENTRY_DSN: https://a34ae347621946bf8acded18e5b7d4b8@o420233.ingest.sentry.io/5338131
      ENABLE_ANALYTICS: "true"
      REDIS_URL: redis-service:6379
      REDIS_PASSWORD: ${REDIS_PASSWORD}
    depends_on:
      - worker-service
      - redis-service

  worker-service:
    restart: unless-stopped
    image: budibase.docker.scarf.sh/budibase/worker
    container_name: bbworker
    environment:
      SELF_HOSTED: 1
      PORT: 4003
      CLUSTER_PORT: ${MAIN_PORT}
      JWT_SECRET: ${JWT_SECRET}
      MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
      MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
      MINIO_URL: http://minio-service:9000
      APPS_URL: http://app-service:4002
      COUCH_DB_USERNAME: ${COUCH_DB_USER}
      COUCH_DB_PASSWORD: ${COUCH_DB_PASSWORD}
      COUCH_DB_URL: http://${COUCH_DB_USER}:${COUCH_DB_PASSWORD}@couchdb-service:5984
      SENTRY_DSN: https://a34ae347621946bf8acded18e5b7d4b8@o420233.ingest.sentry.io/5338131
      INTERNAL_API_KEY: ${INTERNAL_API_KEY}
      REDIS_URL: redis-service:6379
      REDIS_PASSWORD: ${REDIS_PASSWORD}
    depends_on:
      - redis-service
      - minio-service
      - couch-init

  minio-service:
    restart: unless-stopped
    image: minio/minio
    volumes:
      - minio_data:/data
    environment:
      MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
      MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
      MINIO_BROWSER: "off"
    command: server /data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3

  proxy-service:
    restart: unless-stopped
    ports:
      - "${MAIN_PORT}:10000"
    container_name: bbproxy
    image: budibase/proxy
    depends_on:
      - minio-service
      - worker-service
      - app-service
      - couchdb-service

  couchdb-service:
    restart: unless-stopped
    image: ibmcom/couchdb3
    environment:
      - COUCHDB_PASSWORD=${COUCH_DB_PASSWORD}
      - COUCHDB_USER=${COUCH_DB_USER}
    volumes:
      - couchdb3_data:/opt/couchdb/data

  couch-init:
    image: curlimages/curl
    environment:
      PUT_CALL: "curl -u ${COUCH_DB_USER}:${COUCH_DB_PASSWORD} -X PUT couchdb-service:5984"
    depends_on:
      - couchdb-service
    command: ["sh","-c","sleep 10 && $${PUT_CALL}/_users && $${PUT_CALL}/_replicator; fg;"]

  redis-service:
    restart: unless-stopped
    image: redis
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data

  watchtower-service:
    restart: always
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --debug --http-api-update bbapps bbworker bbproxy
    environment:
      - WATCHTOWER_HTTP_API=true
      - WATCHTOWER_HTTP_API_TOKEN=budibase
      - WATCHTOWER_CLEANUP=true
    labels:
      - "com.centurylinklabs.watchtower.enable=false"

volumes:
  couchdb3_data:
    driver: local
  minio_data:
    driver: local
  redis_data:
    driver: local
~~~

## サーバ群の立ち上げ

~~~bash
$ ./budi hosting --start
…
Creating bbproxy                       ... done
Services started, please go to http://localhost:10000 for next steps.
~~~

## サーバにサインイン

<http://localhost:10000> を開きます。 メール認証はされないので適当なメールアドレスを設定します。  

email : test@example.com  
Password: test

![localhost1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/c2df6ff4-7f49-4816-7e66-fca26d5440d0.jpeg)

ログインできました。
![localhost2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/eead0b80-4f1f-0c80-1158-e9c7b55d151a.jpeg)

アプリテンプレートが充実しています。
![screencapture2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/3acf73e5-da50-4e99-bbbb-3d5c44d8abe5.png)

## アプリケーションの作成

青いボタンの "Start from scratch" から始めます。気合でスクラッチ。

![screencapture3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/43b0a78e-106b-4428-9142-77024f1d88cb.png)

適当な名前を付けます。

![screencapture4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/0caa18ca-797e-f80a-8d78-9ed4e2c2068e.png)!

データソースを選択します。"REST"を選択します。RSSフィードのXMLをREST APIと想定します。

![screencapture5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/1019bd87-5dff-d278-f447-20178eb88831.png)


## データの作成

左上のBBアイコンをクリックし、いったんトップーページに戻ります。

![screencapture7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/6bfaa04c-439d-b67a-982c-0147411b8ac1.png)

Appsを選択し、アプリケーションの一覧から作成した"My RSS"を選びます。

![screencapture8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/10d0815d-b198-97fe-284b-d03a456b03f0.png)

"Edit"をクリックします。

![screencapture9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/7fa6ce5f-4048-5477-e9a5-2cfcf1ce8747.png)

アプリケーションの大まかなメニュー構成は、アプリケーションで利用するデータ(Data)、アプリケーションのページ(Design)、アプリケーションのアクション、バッチ処理など(Automate)があります。

![screencapture10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/9eaafea0-b696-26a9-3261-69ba7d660c86.png)

データを設定します。RESTの設定画面から"Add Query"を選びます。

![screencapture11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/8d6b8837-9717-ac89-7c16-670aa6cee00d.png)

今回はデータとなるRSSフィードに本社であるDNPのフィードを使用してみます。
yahooなどいろいろなRSSがあるので探してみてください。

DNP 大日本印刷 ニュースリリース
<http://www.dnp.co.jp/rss_cms/news_jp.xml>

<sub><sup>※RSSおよびRSSのリンク先に掲載している個々の文章、写真、その他一切の著作物の著作権は、DNPグループまたは原著作者その他の権利者に帰属します。</sup></sub>


アドレスを入力し、"Send"ボタンをクリックして一度データが取得できるか確認します。
正常に取得できると、JSONタブに、XMLから変換されたJSONデータが表示されます。
※Proxy環境下のPCではエラーになる場合があるのでご注意ください。
![screencapture12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/ea985d1a-bffa-731b-45cc-910758375b69.png)

データとしては、テーブルのように配列データとしたいので、Transformerタブで、取得したい部分の配列データに絞り込みます。

~~~javascript
return data.channel.item
~~~

![screencapture13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/f291d78f-7f2d-febd-f17d-4439b99ac52a.png)

再度 "Send"ボタンを押すと一行分のデータが認識されました。

![screencapture14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/45804bc7-599a-f51f-2fb7-bcf2323aa644.png)

Schemaタブでも記事の各フィールドが認識されていることが確認できます。

![screencapture15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/fb7a0a34-e6b9-556b-b499-6ddcd64da1b2.png)

適当な名前をつけて保存します。
![screencapture17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/e853b36c-44d1-9da2-32d7-54c676ddf113.png)

同様に"Add Query"からDNPトピックスも登録します。

DNP 大日本印刷 トピックス
<http://www.dnp.co.jp/rss_cms/topics_jp.xml>

![screencapture11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/0825241b-278a-5e87-e4e0-2facbcfdd008.png)

DNPトピックスも登録が完了したら、2つのデータが登録されていることを確認します。  

![screencapture18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/488e79f9-727f-484d-d5fa-ab0015ed3b8f.png)

これでデータの準備ができました。

## 画面の作成

画面は、designタブを選択して作成してきます。ツールバーからDataProviderを選択します。

![screencapture19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/11a46cf9-6507-f904-1d1e-bca511afb6f9.png)

DataProviderと、先ほど作成したRESTデータを紐づけます。

![screencapture20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/241d71a6-e032-caf5-ff8a-874a5fa2a380.png)

DataProviderの下に繰り返しとなるRepeaterを追加します。

![screencapture21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/1c8dcb47-e94b-7065-8299-b8c983d66d59.png)

Repeaterの下にCardを追加します。Cardは、タイトル、画像、サブタイトル、説明、リンクがセットになったようなコンポーネントです。

![screencapture22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/f3776402-3673-ab07-4fde-dae6631d67a2.png)

Cardのタイトルに、データのタイトルを紐づけます。

![screencapture23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/8ed4e8aa-54ef-8931-9caa-7ae39848918c.png)

そのほかの項目SubTitleに記事の日時を紐づけます。

![screencapture24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/2d718bcd-d663-d53e-5284-b8b47a6200bc.png)

記事のページにリンクするボタンを追加します。

![screencapture25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/2cfa2456-05c2-9ca9-8379-faa12764621b.png)

レイアウトを軽く調整します。

![screencapture26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/34a4e646-2579-11fd-c8a6-4edc19cbb021.png)

プレビューボタンで確認してみましょう。

![screencapture27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/855c21cc-873a-dc06-a164-eaa3f2f24a1d.png)

## ページの追加

ニュースページが作成できましたので、次にトピックページを追加します。  
まずはメニューを追加するため、Layoutsを開き、Configure Linksをクリックします。

![screencapture28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/40a4c498-e438-8305-b407-1efd78b228a5.png)

リンクを追加し、URLのパスを仮に/topicとして設定し保存します。

![screencapture29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/3129f991-51bb-8a06-8867-9b549a1192a4.png)

Screenタブに戻り、先ほど作成したニュースのスクリーンを複製します。

![screencapture30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/0a795a93-d82b-295d-dc2e-3dd816f80986.png)

先ほど仮に設定したパスを入力しDuplicateをクリックします。

![screencapture31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/1b2d06e8-4776-df9c-5352-eab2409b1893.png)

複製されたスクリーンの、DataProviderのデータを変更すると、下位のコンポーネントへもある程度自動的に反映されます。ついでに各コンポーネントの名称もそれっぽく変更します。

![screencapture32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/99bc18e4-239d-d0f6-8d34-d712099150e6.png)

いったんプレビューしてみましょう。

![screencapture33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/327971f2-6b5f-d128-7bb2-e3ed620833ce.png)

<sub><sup>※RSSおよびRSSのリンク先に掲載している個々の文章、写真、その他一切の著作物の著作権は、DNPグループまたは原著作者その他の権利者に帰属します。</sup></sub>

## デプロイ

動作に問題がないようであれば、右上のPublishボタンを押してデプロイします。

![screencapture34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/807d1ee5-21cc-4026-4397-c4c29205619a.png)

発行先のリンクを確認します。

![screencapture35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/c92517f3-492d-348c-0199-df6c12848407.png)

ニュースリーダーが完成しました。

![screencapture36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/86adfd61-99bd-dda6-196a-24ab8c4ebba4.png)

<sub><sup>※RSSおよびRSSのリンク先に掲載している個々の文章、写真、その他一切の著作物の著作権は、DNPグループまたは原著作者その他の権利者に帰属します。</sup></sub>

## 認証 / アクセス権限

作成したアプリケーションに外部や、別のブラウザでアクセスすると認証画面が表示されます。  
これは、アプリケーションを作成したスクリーンや、データプロバイダが、認証付きの設定になっているためです。

認証を外すには、各データソースのAccessLevelをPublicに変更し、再デプロイします。

![screencapture37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/a1d9c747-fbad-c3af-8e71-b504601385d5.png)

![screencapture38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/892dff92-f287-4b4b-cff0-9655a16a240a.png)

認証をそのままにアカウントを追加したい場合は、BudibaseのUsersメニューからユーザを追加します。

![screencapture39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/e638057f-7d5d-00ca-1c85-7f7008343c78.png)

## 運用

実際の運用を想定すると、任意のドメインを設定したリバースプロキシ、またはロードバランサをフロントに構え  <http://localhost:10000/app/my-rss> へつなぐように構成するなどが検討されます。  
またスケーリングまで想定すると、Kubernetesによる構成での運用が必要になると思います。  
詳細は公式ドキュメントが充実していますので、興味ある方はチェックしてみてください。

<https://docs.budibase.com/docs>

## さいごに

商用/クラウドサービスのローコードプラットフォームもいろいろあるので、ツール選びには苦労するかと思いますが開発を始める場合のポイントとしては、

* ある程度簡単に使えるか
  * UIがわかりづらい、設定が多いなどは、本末転倒

* 要件をそのプラットフォームで満たすことができるか
  * ドキュメントをよく読み、機能や操作感を覚える
  * なるべく簡単なチュートリアルからはじめて、徐々にやれることを覚えていく
  * コーディングによって拡張することができる範囲を理解しておく

機会があれば他のツールなども試していきたいと思います。
こっちのほうが人気だよとかあれば教えてくれると嬉しいです。