RAPでお気に入りレシピ集を開発してみた

# はじめに
この記事では、[RAP（ABAP RESTful Application Programming Model）](https://help.sap.com/docs/abap-cloud/abap-rap/abap-restful-application-programming-model)を用いたアプリケーション開発をご紹介します。RAPはSAPでODataサービスを効率的に開発するための最新アーキテクチャで、Cloud時代のABAPプロコード開発における中核技術といえます。今回は、RAPアプリケーションに必要なオブジェクトを自動生成してくれるRAP Generatorを用いて開発をし、サンプルデータを登録するところまでの開発手順をお見せします。

ところで、毎日の食事作りって、大変ですよね。自炊以外の選択肢も広げていきたいところではありますが、我が家は夫と娘２人の４人家族ですので、コスパ面においては圧倒的に自炊が優れています。冷蔵庫の残り物を確認し、感覚的な味付けでパパっと作れるセンスがあれば良いのですが、私にはないので、ちょうどいいレシピを常に探しています。数をこなしていくと定番レシピができてくるようになるのですが、日々業務で開発に携わっているFiori画面がレシピ管理にも最適では！？と思い立ち、今回はお気に入りレシピを一覧管理するアプリを開発してみることにしました。

### 対象読者
* RAP開発にこれから取り組みたい方
* 従来のABAP開発と最新ABAP開発の違いを掴みたい方
* （毎日の献立に悩んでいるSAP技術者の方）

### 環境準備
 今回はSAP BTPのTrial環境を用いてABAP開発をします。
 開発環境のセットアップ方法は以下のチュートリアルを参考にしてください。
 [Create an SAP BTP ABAP Environment Trial User](https://developers.sap.com/tutorials/abap-environment-trial-onboarding.html)


# 開発手順

### 1. パッケージの登録
まずは今回作成するオブジェクトを紐づけるためのサブパッケージを登録します。

① 任意のパッケージ（※）上で右クリック -> New -> ABAP Package
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/4a7ee98c-3f4f-ae7d-4ec4-da8a77c055ad.png)
※ 表示されている上位パッケージは事前に「ZLOCAL」配下に作成しておいたパッケージです。

② 必要情報を入力し、「Next」を２回押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/65ee0633-3fb5-ce52-d36c-d03c10cd91c0.png" width=60%>

③ 既存の移送依頼を選択（既存の移送依頼がない場合は「Create a new request」より登録）し、「Finish」を押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/4bea42a9-557b-dd76-a45f-d6ac5b15606c.png" width=60%>

### 2. アドオンテーブルの登録
レシピデータを格納しておくためのアドオンテーブルを登録します。

① 1.で作成したパッケージ上にて右クリック -> New -> Other ABAP Repository Object
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/8b73307a-7d7a-ec05-bed9-d60f57117236.png)

② 「Database Table」を選択し、「Next」を押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/3969a387-1694-da76-f5ff-bd9114a97445.png" width=60%>

③ 必要情報を入力し、「Next」を２回押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/d6ee57e1-f345-ab41-de37-f044f38c2a20.png" width=60%>

④ 既存の移送依頼を選択し、「Finish」を押下

⑤ テーブル定義の内容を記述し、保存（Ctrl+S）・有効化（Ctrl+F3）
~~~ABAP
@EndUserText.label : 'レシピ管理テーブル'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table yrecipe001 {

  key client      : abap.clnt not null;
  key recipeno    : yerecipeno not null;
  title           : yetitle;
  ingredients     : yeingredient;
  steps           : yestep;
  url             : yeurl;
  created_by      : abp_creation_user;
  created_at      : abp_creation_tstmpl;
  last_changed_by : abp_locinst_lastchange_user;
  last_changed_at : abp_lastchange_tstmpl;

}
~~~
#### テーブル定義補足
* 「:」の右に定義されているデータエレメントのうち、「y」始まりのものは事前定義済みです。以下のような形で同様にADTから登録することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/697b21f1-9024-3115-9e8c-2324ab45c8e1.png)
* 「abp」始まりのデータエレメントはSAP標準のものです。規定のデータエレメントを設定しておくことで、後続手順にてRAP Generatorを実行する際にこれらの項目は登録・更新時に自動的に値が更新される作りになります。

### 3. RAP Generatorの実行

いよいよRAP Generatorの実行です。ポップアップに従い操作するだけで、2.で作成したアドオンテーブルをもとに、CRUD操作やOData UIの機能を備えたアプリケーションが作成できます。

① 2.で作成したアドオンテーブル上にて右クリック -> Generate ABAP Repository Objects...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/6611e523-3e0a-a4b1-4634-1b13210cbd20.png)

② 「OData UI サービス」を選択し、「Next」を押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/3668fd04-1475-6c67-0514-85e602033020.png" width=60%>

③ 1.で登録したパッケージの値を入力し、「Next」を押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/6c9b98e2-d927-67f5-3f99-da37e315eb03.png" width=60%>

④ 生成されるオブジェクト名称等の情報が続いて表示されるので、「Next」を２回押下

⑤ 既存の移送依頼を選択し、「Finish」を押下

⑥ 自動的に起動するService Bindingの編集画面にて「Publish」を押下（しばらく待機）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/4d26d2c6-2a5a-f356-9637-f9b0906171fa.png)

⑦ Publish完了後、「Preview」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/ddd045bc-0d36-180d-368f-7cc62f85d1e8.png)

⑧ プレビュー画面の確認
ブラウザが起動し、プレビュー画面が表示されました！
「作成」ボタンよりデータを登録してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/11e8571b-b29c-fbd4-219c-914b03e72fbf.png)

登録画面が表示されます。各項目値を入力し、「登録」ボタンでデータを保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/791f9078-4682-2c92-c098-07991eefc925.png)

一覧画面に戻ります。一覧での表示イメージも良い感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/15799f22-61cc-12b9-4c3d-f4dcc0f17672.png)

#### プレビュー画面補足
ここで表示されたプレビュー画面ですが、あくまでもプレビュー用の位置付けなので、本番利用する際にはFioriアプリケーションとしてBAS（SAP Business Application Studio）等を用いたフロントエンド開発が必要です。開発とはいっても、RAP Generatorによりレイアウト定義に必要なオブジェクトも生成された状態ですので、主にはSAP標準のUIテンプレート（SAP Fiori Elements）との接続設定のみです。また別の機会にご紹介できればと思います。ただ、上記のプレビュー画面もデータの登録・編集まででき、サンプル用としては非常に優れていますので、今回は引き続きプレビュー画面で確認を進めます。

### 4. データ登録用プログラム開発
3.で生成されたプレビュー画面でもデータ登録は可能ですが、１件ずつの登録画面なので、複数レコードを一括で登録したい場合には少し不便です。そこで最後に、簡単なプログラムを作成し、そこからデータを登録してみます。

① 1.で作成したパッケージ上にて右クリック -> New -> ABAP Class
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/df8f06d6-2590-a0f5-3e54-1aaa2cce8ffd.png)

② 必要情報を入力し、「Next」を押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/35cfd82d-85d5-40df-5020-8ab7ce1d4da9.png" width=60%>

#### 「IF_OO_ADT_CLASSRUN」補足
この手順ではインターフェースとして「IF_OO_ADT_CLASSRUN」を設定しています。このインターフェースを用いると、mainメソッドをADTから起動でき、任意のデータをADTのコンソールに出力するプログラムを作成できます。

③ 既存の移送依頼を選択し、「Finish」を押下

④ ソースコードを編集し、保存（Ctrl+S）・有効化（Ctrl+F3）

編集前↓
~~~ABAP
CLASS ycl_add_recipe001 DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES if_oo_adt_classrun .
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS ycl_add_recipe001 IMPLEMENTATION.


  METHOD if_oo_adt_classrun~main.
  ENDMETHOD.
ENDCLASS.
~~~

編集後（mainメソッドに実行したい処理を記述）↓
~~~ABAP
CLASS ycl_add_recipe001 DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES if_oo_adt_classrun .
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS ycl_add_recipe001 IMPLEMENTATION.


  METHOD if_oo_adt_classrun~main.

    DATA:
      lt_recipes TYPE TABLE FOR CREATE zc_yrecipe001.

    lt_recipes = VALUE #( ( %cid        = 'recipe2'
                            recipeno    = '2'
                            title       = '串なし塩焼き鳥'
                            ingredients = '鶏もも肉：2枚、長ねぎ：1本、酒：大さじ1、砂糖：小さじ1、塩：小さじ1、チューブにんにく：約1cm、サラダ油：適量'
                            steps       = '鶏もも肉を１口大に切って袋に入れ、酒、砂糖、塩を加えて揉みこみ、しばらく置く。白ねぎも別の袋に入れ、塩適量を振りかけて混ぜ、しばらく置く。フライパンを熱してサラダ油を入れ、下味をつけた鶏もも肉と白ねぎを入れ、蓋をして両面焼く。'
                            url         = 'クックパッドアレンジ'          )
                          ( %cid        = 'recipe3'
                            recipeno    = '3'
                            title       = '卵とわかめの中華スープ'
                            ingredients = '卵：2個、乾燥わかめ：大さじ1半、片栗粉大さじ1、ダシダ：小さじ1半、ごま油：大さじ1、醤油：適量、塩こしょう：適量、白ごま：適量'
                            steps       = '水1Lを沸騰させ、ダシダを加えて混ぜる。乾燥わかめを加え、大さじ2の水で溶いた片栗粉を加えてとろみをつける。煮立ったら溶き卵を少しずつ加え、蓋をしてすぐに火を止める。1分程置いてから卵をほぐし、ごま油を加え、味見をしながら醤油と塩こしょうで塩味を調整する。最後に白ごま適量を振って混ぜる。'
                            url         = 'オリジナル'               ) ).

    MODIFY ENTITIES OF zc_yrecipe001    "RAP Generatorで自動生成されるCDS ViewやBehavior DefinitionsのID
        ENTITY ZcYrecipe001             "RAP Generatorで自動生成されるBehavior Definitions内のAlias名
        CREATE SET FIELDS
        WITH lt_recipes
        REPORTED DATA(ls_reported)
        MAPPED DATA(ls_mapped)
        FAILED DATA(ls_failed).

    COMMIT ENTITIES
        RESPONSE OF zc_yrecipe000
            FAILED DATA(ls_failed_commit)
            REPORTED DATA(ls_reported_commit).

    out->write( '処理が終了しました' ).

  ENDMETHOD.
ENDCLASS.
~~~

#### ソースコード補足
今回登録したいのはアドオンテーブルのデータなので、従来のようにINSERT文でデータを登録することも可能です。（今回のように単にサンプルデータを登録する場合、INSERT文のほうが簡単に記述できるので、むしろ適していることも多いはずです。）ですが、今回はRAP特有の記述方式をご紹介するために、[EML（Entity Manipulation Language）](https://help.sap.com/docs/ABAP_PLATFORM_NEW/fc4c71aa50014fd1b43721701471913d/af7782de6b9140e29a24eae607bf4138.html)によるデータ操作を取り入れたソースコードとしました。EMLを用いてデータ操作をすることで、標準のランタイム（参考：[Create時のランタイム](https://help.sap.com/docs/abap-cloud/abap-rap/create-operation-runtime?locale=en-US&source=redirect)）に沿ってデータ操作を実行することができます。大まかにどういうことかというと、起動方法（Fiori画面、プログラム、WebAPI etc）に関わらず、RAPで実装しているチェック処理や値設定処理、排他制御等を、CRUD操作と合わせて実行することができます。今回はRAP Generatorで生成されたオブジェクトにはとくに手を加えていないのですが、チェック処理（Validation）の追加や値設定処理（Determination）の追加等、拡張実装を加えることも可能です。

⑤ プログラム実行（Run -> Run As -> 1 ABAP Application (Console)）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/f83cc2ae-e7f9-aa3b-c5c2-3031979b0e6a.png)

⑥ コンソール（ABAP Console）への出力を確認、登録確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/364f8b22-a90a-4fa9-afc5-b5d2f54d9183.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/1c75713d-c109-c7f1-7857-0a373448b5ed.png)


#### データ登録のおまけ：ChatGPTで検索したレシピを登録してみた
今回はさらに、ChatGPTでの検索レシピを追加で登録してみます。
こんな感じで依頼します。
~~~
時短レシピを主菜と副菜で5品ずつ提案してください。
その際、ABAPの内部テーブルに格納し、プログラムからシステムに登録したいので、
以下のようなフォーマットで作成してください。
「recipeno」は4からスタートしてカウントアップしてください。 
また、「url」には'ChatGPT'と設定してください。

    DATA:
      lt_recipes TYPE TABLE FOR CREATE zc_yrecipe001.

    lt_recipes = VALUE #( ( %cid        = 'recipe2'
                            recipeno    = '2'
                            title       = '串なし塩焼き鳥'
                            ingredients = '鶏もも肉：2枚、長ねぎ：1本、酒：大さじ1、砂糖：小さじ1、塩：小さじ1、チューブにんにく：約1cm、サラダ油：適量'
                            steps       = '鶏もも肉を１口大に切って袋に入れ、酒、砂糖、塩を加えて揉みこみ、しばらく置く。白ねぎも別の袋に入れ、塩適量を振りかけて混ぜ、しばらく置く。フライパンを熱してサラダ油を入れ、下味をつけた鶏もも肉と白ねぎを入れ、蓋をして両面焼く。'
                            url         = 'クックパッドアレンジ'          )
                          ( %cid        = 'recipe3'
                            recipeno    = '3'
                            title       = '卵とわかめの中華スープ'
                            ingredients = '卵：2個、乾燥わかめ：大さじ1半、片栗粉大さじ1、ダシダ：小さじ1半、ごま油：大さじ1、醤油：適量、塩こしょう：適量、白ごま：適量'
                            steps       = '水1Lを沸騰させ、ダシダを加えて混ぜる。乾燥わかめを加え、大さじ2の水で溶いた片栗粉を加えてとろみをつける。煮立ったら溶き卵を少しずつ加え、蓋をしてすぐに火を止める。1分程置いてから卵をほぐし、ごま油を加え、味見をしながら醤油と塩こしょうで塩味を調整する。最後に白ごま適量を振って混ぜる。'
                            url         = 'オリジナル'               ) ).
~~~

ChatGPTの返答：
~~~
以下は、リクエストに基づいて作成したABAP内部テーブルのフォーマットです。
主菜と副菜をそれぞれ5品ずつ、recipenoを4から開始してカウントアップしています。

DATA:
  lt_recipes TYPE TABLE FOR CREATE zc_yrecipe001.

lt_recipes = VALUE #( ( %cid        = 'recipe4'
                        recipeno    = '4'
                        title       = '照り焼きチキン'
                        ingredients = '鶏もも肉：2枚、醤油：大さじ3、砂糖：大さじ2、みりん：大さじ1、酒：大さじ1'
                        steps       = '鶏もも肉を一口大に切る。フライパンを熱して鶏肉を皮目から焼き、両面がこんがりするまで焼く。調味料を全て混ぜてフライパンに加え、煮詰めながら鶏肉に絡める。'
                        url         = 'ChatGPT'               )
                      ( %cid        = 'recipe5'
                        recipeno    = '5'
                        title       = '簡単麻婆豆腐'
                        ingredients = '絹ごし豆腐：1丁、豚ひき肉：150g、麻婆豆腐の素：1パック、長ねぎ：1本、サラダ油：大さじ1'
                        steps       = '豆腐を1.5cm角に切り、長ねぎをみじん切りにする。フライパンで油を熱し、豚ひき肉を炒める。麻婆豆腐の素を加え、豆腐を投入して優しく混ぜながら加熱する。仕上げに長ねぎを散らす。'
                        url         = 'ChatGPT'               )
                      ( %cid        = 'recipe6'
                        recipeno    = '6'
                        title       = '鮭のホイル焼き'
                        ingredients = '生鮭：2切れ、玉ねぎ：1個、しめじ：1/2パック、バター：20g、塩こしょう：適量、アルミホイル：適量'
                        steps       = '鮭に塩こしょうを振る。アルミホイルにスライスした玉ねぎ、ほぐしたしめじ、鮭を乗せ、バターを置いて包む。180℃のオーブンで20分焼く。'
                        url         = 'ChatGPT'               )
                      ( %cid        = 'recipe7'
                        recipeno    = '7'
                        title       = '豚肉の生姜焼き'
                        ingredients = '豚ロース薄切り：200g、醤油：大さじ2、みりん：大さじ1、砂糖：小さじ1、しょうが：1片'
                        steps       = '豚肉に調味料を混ぜ合わせたタレを絡めて10分置く。フライパンで豚肉を焼き、タレを加えて全体に絡める。'
                        url         = 'ChatGPT'               )
                      ( %cid        = 'recipe8'
                        recipeno    = '8'
                        title       = '鶏のから揚げ'
                        ingredients = '鶏もも肉：300g、醤油：大さじ2、酒：大さじ1、しょうが：1片、片栗粉：適量、サラダ油：適量'
                        steps       = '鶏肉を一口大に切り、醤油、酒、すりおろしたしょうがを絡めて20分ほど置く。片栗粉をまぶし、中温の油で揚げる。'
                        url         = 'ChatGPT'               )
                      ( %cid        = 'recipe9'
                        recipeno    = '9'
                        title       = 'ほうれん草のおひたし'
                        ingredients = 'ほうれん草：1束、醤油：小さじ2、かつお節：適量'
                        steps       = 'ほうれん草を茹でて冷水にとり、水気を絞る。食べやすい長さに切り、醤油をかけ、かつお節を乗せる。'
                        url         = 'ChatGPT'               )
                      ( %cid        = 'recipe10'
                        recipeno    = '10'
                        title       = 'きゅうりとわかめの酢の物'
                        ingredients = 'きゅうり：1本、乾燥わかめ：大さじ1、酢：大さじ2、砂糖：小さじ1、塩：少々'
                        steps       = 'きゅうりを薄切りにし、塩でもんで水気を絞る。戻したわかめと一緒に酢、砂糖で和える。'
                        url         = 'ChatGPT'               )
                      ( %cid        = 'recipe11'
                        recipeno    = '11'
                        title       = '大根の梅和え'
                        ingredients = '大根：200g、梅干し：1個、砂糖：小さじ1、白ごま：適量'
                        steps       = '大根を細切りにして塩をふり、水気を絞る。梅干しを叩いて砂糖と混ぜ、大根と和える。最後に白ごまを振る。'
                        url         = 'ChatGPT'               )
                      ( %cid        = 'recipe12'
                        recipeno    = '12'
                        title       = 'にんじんとツナのサラダ'
                        ingredients = 'にんじん：1本、ツナ缶：1缶、マヨネーズ：大さじ2、塩こしょう：適量'
                        steps       = 'にんじんを千切りにして軽く塩もみし、水気を絞る。ツナとマヨネーズで和え、塩こしょうで味を調える。'
                        url         = 'ChatGPT'               )
                      ( %cid        = 'recipe13'
                        recipeno    = '13'
                        title       = 'ポテトサラダ'
                        ingredients = 'じゃがいも：3個、きゅうり：1本、ハム：3枚、マヨネーズ：大さじ4、塩こしょう：適量'
                        steps       = 'じゃがいもを茹でてつぶし、薄切りにしたきゅうりと細切りのハムを加える。マヨネーズで和え、塩こしょうで味を調える。'
                        url         = 'ChatGPT'               ) ).
~~~

今回は事前にソースコードの形を作っておいたので、同じフォーマットに変換してもらうように指示をすれば、とても簡単です。あとは先ほどのプログラムに貼り付けて実行します。この方法は実際のプロジェクトにおけるテストデータ登録時にも応用できるかと思います。

レシピ集が充実してきました...！最高ですね。
週明けに備えて買い物に行きましょう。
後ほどChatGPTとクリスマスメニューについても相談します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939002/0394ecae-4755-cbf0-128a-86dc58a95856.png)


# おわりに
今回は、RAPの中でも最も基本的といえる、RAP Generatorを用いた開発と、サンプルデータの登録方法についてご紹介しました。開発ツールとしては、ADT（ABAP Development Tools ※Eclipseのプラグイン）のみを使用しました。GUIが使えないBTPやS/4HANA Cloud Public Editionでの開発の際、とくに参考にしていただければと思います。テーブル登録のTr-cd：SE11、アドオンテーブルのデータ編集のTr-cd：SE16~、プログラム開発のTr-cd：SE38、、、これらの代替手段となるのが今回ご紹介した内容です。

また、途中でも少し触れた通り、作成したODataサービスは様々な方法で起動することができますし、RAP Generatorで自動生成したオブジェクトに拡張を加えることも可能です。次の機会があれば、以下のような拡張にもトライしていこうと思います。
* Fioriアプリとして完成させ、モバイル対応する
* レシピNo.は自動採番させる
* 生成AIによるレシピ検索結果取り込みを自動化する