VSCode、GitHub Copilot Chat で Web アプリを開発してみよう - 3

5.8K Views

September 23, 23

スライド概要

.NETラボ 勉強会 2023年9月
https://dotnetlab.connpass.com/event/294666/

引き続き OpenAI のモデルの一つとしてのコード生成専用モデルである Codex を使い対話で話を進められる GitHub Copliot Chat と、他の適切なツールを使って、プロトタイプ作成をやってみたいと思います。今回は UI にもフォーカスします。

profile-image

ヴイエムウェア株式会社 ソリューションアーキテクト本部 プリンシパルエンタープライズアーキテクト。 Microsoft で13年間、テクニカルエバンジェリストとして .NET、Visual Studio、Windows、iOS、Android、Microsoft Azure 等の開発者向け最新技術啓発活動を実施。その後、Dell、Accenture、Elastic で開発者向け技術啓発活動等を経て現職。 モダンアプリケーション開発、マルチクラウド対応、アーキテクチャ策定等を中心に、技術者向けに最新技術の啓発活動を実施中。 2019年4月〜2021年8月迄、内閣官房 IT 総合戦略室 政府 CIO 補佐官を兼務、2021年9月〜2024年3月迄、デジタル庁 PjM ユニット ソリューションアーキテクトを兼務。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

VSCode、GitHub Copilot Chat で Web アプリを開発してみよう - 3 鈴⽊ 章太郎 主席エンタープライズアーキテクト ヴイエムウェア株式会社 戦略ビジネス推進本部 © 2023 VMware, Inc.

2.

鈴⽊ 章太郎 X (Twitter) : @shosuz ヴイエムウェア株式会社 戦略ビジネス推進本部 主席エンタープライズアーキテクト Microsoft で13年間、テクニカルエバンジェリストとして .NET、Visual Studio、Windows、iOS、Android、 Microsoft Azure 等の開発者向け技術啓発活動を実施。 その後 Dell、Accenture、Elastic での開発者向け技術 啓発活動等を経て現職。 モダンアプリケーション開発、マルチクラウド対応、アーキテクチャ 策定等を中⼼に、開発者に最新技術の啓発活動を実施中。 2019年4⽉より2021年8⽉まで、内閣官房 IT 総合戦略室 政府 CIO 補佐官を兼務。 2021年9⽉より、デジタル庁プロジェクトマネージャーユニット & AI チームのソリューションアーキテクトを兼務。 ©2023 VMware, Inc.

3.

Agenda l 今回の実⾏環境、プロトタイピングの⽅針決定 l プロトタイピングの実施 1 – API の準備 l プロトタイピングの実施 2 – UI デザイン l プロトタイピングの実施 3 – UI コーディング & API 連携 l まとめ ©2023 VMware, Inc. 3

4.

今回の実⾏環境、 プロトタイピングの⽅針決定 © 2023 VMware, Inc. 4

5.

OpenAI AI モデルの機能 OpenAI AI モデルの機能 は主に3 つの カテゴリ © 2023 VMware, Inc. 機能 例 ⾃然⾔語の⽣成 GPT さまざまな読み取りレベルの複雑なテキストの 要約、⽂章の⽂⾔の代替の提案など コードの⽣成 Codex プログラミング⾔語間でのコードの翻訳、コード 内のバグの特定とトラブルシューティングなど イメージの⽣成 DALL-E テキスト説明からのパブリケーション⽤イメージ の⽣成など 5

6.

今回の実⾏環境 2023年9⽉23⽇時点での最新版 • Visual Studio Code 1.82.2 • GitHub Copilot v.1.111.404 • GitHub Copilot Chat v.0.7.1 preview • Billing 有効、GPT-4 有効(前回資料参照 ※) © 2023 VMware, Inc. ※ https://www.docswell.com/s/shosuz/ZGXNWL-2023-08-26-162303 https://github.blog/2023-07-20-github-copilot-chat-beta-now-available-for-every-organization/ 6

7.

Markdown Preview Mermaid Support https://marketplace.visualstudio.com/items?itemName=bierner.markdown-mermaid • Mermaid 記法は、テキストのみ で、ガントチャートや円グラフなど のチャートや、クラス図やシーケン ス図のような UML で⽤いられる システム可視化表現を⾏える • ダイアグラム・チャート作成ツール とフローチャートのサポートを、VS Code の組み込み Markdown プレビューとノートブックの Markdown セルに追加 • 現在、Mermaid バージョン 10.2.3 をサポート © 2023 VMware, Inc. 7

8.

GitHub Copilot Chat beta now available for all individuals https://github.blog/2023-09-20-github-copilot-chat-beta-now-available-for-all-individuals/ © 2023 VMware, Inc. 8

9.

プロトタイピングのスコープと⽅針の指⽰ 具体的なツール等を含めつつ指⽰してプロトタイピングの実施⼿順を整理して決めてもらう shosuz 1 – API の準備をします。クイズアプリのバックエンドのようなもの、あるいは EC モバイルアプリのバックエンドのようなもの、を作ります。 データベースは今ある Azure SQL Database を使いコンテキストとモデルを作成し、Swagger で API ドキュメントを作ります。 2 – UI モックツール Uizard を利⽤してモバイルアプリのデザインを⽣成し、何度か試⾏錯誤した後に、7−8画⾯分のデザインを .JPG 等でエクスポートします。 3 – Figma を使って画像をリソースとして読み込み、画⾯の UI をデザインして完成させます。 4 – その画⾯を UI 側コード⽣成ツールの Locofy.ai 等を使って Figma から読み込み、React UI のソースコードを作ります。 5 – Figma for VSCode を使って VSCode からそれを読み込み、API と連携させて完成させます。 これで実施⼿順を決めてください。ツールの機能の重複や問題点があれば直してください。 GitHub Copilot 以下の⼿順でプロトタイピングを実施することができます。 API の準備 • Azure SQL Database を使⽤して、API のバックエンドを作成します。 • コンテキストを使⽤して、API のエンドポイントに対応するモデルを作成 • モデルクラスを使⽤してコントローラーを作成 • サービスクラスを作成してコントローラーを追加 • Swagger を使⽤して、API ドキュメントを作成します。 UI デザイン • Uizard を使⽤して、モバイルアプリのデザインを作成します。 • 画⾯の UI をデザインして完成させます。 • Figma を使⽤して、Uizard で作成したデザインをインポートし、必要に 応じて修正します。 © 2023 VMware, Inc. UI コーディング • Figma for VSCode を使⽤して、VSCode で Figma のデザインを 表⽰します。 • React コンポーネントを使⽤して、API と連携させて UI を完成させます。 • Locofy.ai を使⽤して、Figma で作成したデザインから React コンポー ネントを作成します。 この⼿順では、Uizard を使⽤してデザインを作成し、Figma を使⽤して修正 することで、より効率的なデザインプロセスを実現することができます。 また、Locofy.ai を使⽤して、Figma で作成したデザインから React コンポー ネントを作成することで、UI コーディングの効率を向上させることができます。 以上の⼿順で、プロトタイピングを実施することができます。 ・類似したツールの機能重複や使い分けなどを指摘 ・Locofy.ai は今回はデザインができないため次回以降 9

10.

プロトタイピングの実施 - 1 API の準備 • Azure SQL Database を使⽤して、API のバックエンドを作成 • Context クラスを使⽤して、データベースにアクセスするためのコンテキストを作成 • コンテキストを使⽤して、API のエンドポイントに対応するモデルを作成 • モデルクラスを使⽤してコントローラーを作成 • サービスクラスを作成してコントローラーを追加 • Swagger を使⽤して、API ドキュメントを作成 © 2023 VMware, Inc. 10

11.

Visual Studio Code で API を開発しはじめる 随時おかしなところを指摘する shosuz それでは順番にやっていきます。 Visual Studio Code で .NET 7 で新しい ASP.NET Core Web API プロジェクトを作成します。 新しいインスタンスを⽴ち上 げてからの⼿順を教えてください。プロジェクト名は、LegalAPI です。 GitHub Copilot shosuz 以下の⼿順で作成することができます。 1. Visual Studio Code を開きます。 2. Ctrl+Shift+P を押して、コマンドパレットを開きます。 3. ASP.NET Core Web API と⼊⼒し、Enter を押します。 4. Select a folder to create a new ASP.NET Core Web API project というメッセージが表⽰されたら、プロジェクトを作成するフォルダを選択 します。 5. LegalAPI という名前を⼊⼒し、Enter を押します。 6. Target Framework というメッセージが表⽰されたら、.NET 7.0 を選択 します。 7. Configure for HTTPS というメッセージが表⽰されたら、No を選択します。 8. プロジェクトが作成されたら、Explorer パネルで LegalAPI フォルダを展開 し、Controllers フォルダを右クリックして、New File を選択します。 10. QaController.cs という名前を⼊⼒し、Enter を押します。 これで、.NET 7.0 で新しい ASP.NET Core Web API プロジェクトが作成 され、QaController.cs ファイルが作成されました。次に、必要なモデル、コン トローラ、およびエンドポイントを作成していきます。 なぜ QaController だけなのですか︖最初に、Qa、Subject、Scope、 Issue のモデルを作って、それから Scaffolding でそれぞれのコントローラーを 作るのではないのですか︖ © 2023 VMware, Inc. GitHub Copilot 申し訳ありません、私の前回の回答が不⼗分でした。Qa、Subject、Scope、 Issue のモデルを作成し、それぞれのコントローラーを作成することができます。こ れにより、それぞれのテーブルに対応する API エンドポイントを作成することがで きます。 以下は、モデルとコントローラーを作成する⼿順です。 1.Models フォルダを右クリックして、New File を選択します。 2.Qa.cs という名前を⼊⼒し、Enter を押します。 3.Qa.cs ファイルを開き、以下のコードを追加します。 --- ・ 若⼲おかしな流れになっているので指摘する 11

12.

.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 1 ソースコードを⽣成させる GitHub Copilot // Qa (Model) using System.ComponentModel.DataAnnotations; namespace LegalAPI.Models { public class Qa { public int Id { get; set; } [Required] public string Question { get; set; } public string Explanation { get; set; } public int SubjectId { get; set; } public int ScopeId { get; set; } public int IssueId { get; set; } public Subject Subject { get; set; } public Scope Scope { get; set; } public Issue Issue { get; set; } } } // Subject (Model) 4. Modelsフォルダを右クリックして、New Fileを選択します。 5. Subject.csという名前を⼊⼒し、Enterを押します。 6. Subject.csファイルを開き、以下のコードを追加します。 © 2023 VMware, Inc. --- namespace LegalAPI.Models { public class Subject { public int Id { get; set; } public string Name { get; set; } } } 7. Modelsフォルダを右クリックして、New Fileを選択します。 8. Scope.csという名前を⼊⼒し、Enterを押します。 9. Scope.csファイルを開き、以下のコードを追加します。 // Scope (Model) namespace LegalAPI.Models { public class Scope { public int Id { get; set; } public string Name { get; set; } } } 10. Modelsフォルダを右クリックして、New Fileを選択します。 11. Issue.csという名前を⼊⼒し、Enterを押します。 12. Issue.csファイルを開き、以下のコードを追加します。 12

13.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 2
ソースコードを⽣成させる
GitHub Copilot

// Issue (Model)
namespace LegalAPI.Models
{
public class Issue
{
public int Id { get; set; }
public string Name { get; set; }
}
}
13. Controllers フォルダを右クリックして、New File を選択します。
14. QaController.cs という名前を⼊⼒し、Enter を押します。
15. QaController.cs ファイルを開き、以下のコードを追加します。
using System.Collections.Generic;
using System.Linq;
using LegalAPI.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
--© 2023 VMware, Inc.

namespace LegalAPI.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class QaController : ControllerBase // QaController
{
private readonly LegalQuizContext _context;
public QaController(LegalQuizContext context)
{
_context = context;
}
[HttpGet]
public ActionResult<IEnumerable<Qa>> GetQas()
{
return _context.Qas.Include(q => q.Subject).Include(q =>
q.Scope).Include(q => q.Issue).ToList();
}
[HttpGet("{id}")]
public ActionResult<Qa> GetQa(int id)
{
var qa = _context.Qas.Include(q => q.Subject).Include(q =>
q.Scope).Include(q => q.Issue).FirstOrDefault(q => q.Id == id);
if (qa == null)
{
return NotFound();
}
return qa;
}

13

14.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 2
ソースコードを⽣成させる
GitHub Copilot
--[HttpPost] // QaController

--[HttpDelete("{id}")] // QaController
public IActionResult DeleteQa(int id)
{
var qa = _context.Qas.Find(id);

public ActionResult<Qa> PostQa(Qa qa)
{
_context.Qas.Add(qa);
_context.SaveChanges();

if (qa == null)
{
return NotFound();
}

return CreatedAtAction(nameof(GetQa), new { id = qa.Id }, qa);
}
[HttpPut("{id}")]
public IActionResult PutQa(int id, Qa qa)
{
if (id != qa.Id)
{
return BadRequest();
}

_context.Qas.Remove(qa);
_context.SaveChanges();
return NoContent();
}
}
}

_context.Entry(qa).State = EntityState.Modified;
_context.SaveChanges();
return NoContent();
}
---

© 2023 VMware, Inc.

14

15.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 2
ソースコードを⽣成させる
GitHub Copilot

16. 同様に、SubjectController.cs、ScopeController.cs、IssueController.cs
ファイルを作成し、以下のコードを追加します。
// SubjectController

--- // SubjectController
[HttpGet]
public ActionResult<IEnumerable<Subject>> GetSubjects()
{
return _context.Subjects.ToList();
}

using System.Collections.Generic;
using System.Linq;
using LegalAPI.Models;
using Microsoft.AspNetCore.Mvc;

[HttpGet("{id}")]
public ActionResult<Subject> GetSubject(int id)
{
var subject = _context.Subjects.Find(id);

namespace LegalAPI.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class SubjectController : ControllerBase
{
private readonly LegalQuizContext _context;

if (subject == null)
{
return NotFound();
}
return subject;
}

public SubjectController(LegalQuizContext context)
{
_context = context;
}

[HttpPost]
public ActionResult<Subject> PostSubject(Subject subject)
{
_context.Subjects.Add(subject);
_context.SaveChanges();

--return CreatedAtAction(nameof(GetSubject),
new { id = subject.Id }, subject);
}
© 2023 VMware, Inc.

---

15

16.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 3
ソースコードを⽣成させる
GitHub Copilot
--- // SubjectController
[HttpPut("{id}")]
public IActionResult PutSubject(int id, Subject subject)
{
if (id != subject.Id)
{
return BadRequest();
}
_context.Entry(subject).State = EntityState.Modified;
_context.SaveChanges();

return NoContent();
}

// ScopeController
using System.Collections.Generic;
using System.Linq;
using LegalAPI.Models;
using Microsoft.AspNetCore.Mvc;
namespace LegalAPI.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class ScopeController : ControllerBase
{
private readonly LegalQuizContext _context;

[HttpDelete("{id}")]
public IActionResult DeleteSubject(int id)
{
var subject = _context.Subjects.Find(id);
if (subject == null)
{
return NotFound();
}
_context.Subjects.Remove(subject);
_context.SaveChanges();
return NoContent();

public ScopeController(LegalQuizContext context)
{
_context = context;
}
[HttpGet]
public ActionResult<IEnumerable<Scope>> GetScopes()
{
return _context.Scopes.ToList();
}
---

}
}
}

© 2023 VMware, Inc.

16

17.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 4
ソースコードを⽣成させる
GitHub Copilot
---// ScopeController

---// ScopeController
[HttpPut("{id}")]
public IActionResult PutScope(int id, Scope scope)
{
if (id != scope.Id)
{
return BadRequest();
}
_context.Entry(scope).State = EntityState.Modified;
_context.SaveChanges();
return NoContent();
}

[HttpGet("{id}")]
public ActionResult<Scope> GetScope(int id)
{
var scope = _context.Scopes.Find(id);
if (scope == null)
{
return NotFound();
}
return scope;
}

[HttpDelete("{id}")]
public IActionResult DeleteScope(int id)
{
var scope = _context.Scopes.Find(id);

[HttpPost]
public ActionResult<Scope> PostScope(Scope scope)
{
_context.Scopes.Add(scope);
_context.SaveChanges();

if (scope == null)
{
return NotFound();
}
_context.Scopes.Remove(scope);
_context.SaveChanges();

return CreatedAtAction(nameof(GetScope), new { id =
scope.Id }, scope);
}

return NoContent();
---

}
}
© 2023 VMware, Inc.

}

17

18.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 5
ソースコードを⽣成させる
--// IssueController

GitHub Copilot
--// IssueController

[HttpGet("{id}")]
public ActionResult<Issue> GetIssue(int id)
{
var issue = _context.Issues.Find(id);

using System.Collections.Generic;
using System.Linq;
using LegalAPI.Models;
using Microsoft.AspNetCore.Mvc;

if (issue == null)
{
return NotFound();
}

namespace LegalAPI.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class IssueController : ControllerBase
{
private readonly LegalQuizContext _context;

return issue;
}
[HttpPost]
public ActionResult<Issue> PostIssue(Issue issue)
{
_context.Issues.Add(issue);
_context.SaveChanges();

public IssueController(LegalQuizContext context)
{
_context = context;
}
[HttpGet]
public ActionResult<IEnumerable<Issue>> GetIssues()
{
return _context.Issues.ToList();
}

return CreatedAtAction(nameof(GetIssue), new { id = issue.Id }, issue);
}
---

--© 2023 VMware, Inc.

18

19.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 5
ソースコードを⽣成させる
GitHub Copilot
--- // IssueController
[HttpPut("{id}")]
public IActionResult PutIssue(int id, Issue issue)
{
if (id != issue.Id)
{
return BadRequest();
}
_context.Entry(issue).State = EntityState.Modified;
_context.SaveChanges();

return NoContent();
}
[HttpDelete("{id}")]
public IActionResult DeleteIssue(int id)
{
var issue = _context.Issues.Find(id);
if (issue == null)
{
return NotFound();
}
_context.Issues.Remove(issue);
_context.SaveChanges();
return NoContent();
}
}
}
© 2023 VMware, Inc.
これで、Qa、Subject、Scope、Issue の API エンドポイントが作成されました。

shosuz
appsettings.json も書き換えますよね︖
GitHub Copilot
はい、appsettings.json ファイルは書き換える必要があります。ConnectionStrings セク
ションには、データベース接続⽂字列が含まれています。この接続⽂字列は、Azure SQL デー
タベースに接続するために使⽤されます。以下は、書き換えた appsettings.json ファイルの例
です。
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection":
"Server=<server_name>.database.windows.net;Database=<database_name>;User
ID=<user_id>;Password=<password>;Encrypt=true;Connection Timeout=30;"
}
}

<server_name>、<database_name>、<user_id>、および <password> は、Azure
SQL データベースの詳細に置き換える必要があります。また、接続⽂字列には、
Encrypt=true および Connection Timeout =30のパラメーターが含まれていることに注意
してください。これらは、接続を暗号化し、接続タイムアウトを30秒に設定するために使⽤されま
19
す。

20.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 6
ソースコードを⽣成させる
shosuz
同じく QaTrial, SubjectTrial, ScopeTrial, IssueTrial, の4つのエンドポイントも追加してください。

--// SubjectTrialController

GitHub Copilot
以下は、QaTrial、SubjectTrial、ScopeTrial、IssueTrial の API エンドポイントを作成するための
例です。
--using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

[ApiController]
[Route("[controller]")]
public class SubjectTrialController : ControllerBase
{
private readonly LegalQuizContext _context;

namespace LegalAPI.Controllers
{
[ApiController]
[Route("[controller]")] // QaTrialController
public class QaTrialController : ControllerBase
{
private readonly LegalQuizContext _context;
public QaTrialController(LegalQuizContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Qa>>> GetQaTrial()
{
var random = new Random();
var qaList = await _context.Qa.OrderBy(q =>
random.Next()).Take(20).ToListAsync();
return qaList;
}
© 2023 VMware, Inc.
}

public SubjectTrialController(LegalQuizContext context)
{
_context = context;
}
[HttpGet("{subjectId}")]
public async Task<ActionResult<IEnumerable<Qa>>>
GetSubjectTrial(int subjectId)
{
var random = new Random();
var qaList = await _context.Qa.Where(q => q.SubjectId ==
subjectId).OrderBy(q =>
random.Next()).Take(1).ToListAsync();
return qaList;
}
}
---

・ Random は Id を取れなくなる可能性が⾼いので、修正後のソースコードでは
20
NewGuid で対応

21.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 7
ソースコードを⽣成させる
--// ScopeTrialController
[ApiController]
[Route("[controller]")]
public class ScopeTrialController : ControllerBase
{
private readonly LegalQuizContext _context;

--// IssueTrialController
[ApiController]
[Route("[controller]")]
public class IssueTrialController : ControllerBase
{
private readonly LegalQuizContext _context;
public IssueTrialController(LegalQuizContext context)
{
_context = context;
}

public ScopeTrialController(LegalQuizContext context)
{
_context = context;
}
[HttpGet("{scopeId}")]
public async Task<ActionResult<IEnumerable<Qa>>>
GetScopeTrial(int scopeId)
{
var random = new Random();
var qaList = await _context.Qa.Where(q => q.ScopeId ==
scopeId).OrderBy(q =>
random.Next()).Take(1).ToListAsync();
return qaList;
}

[HttpGet("{issueId}")]
public async Task<ActionResult<IEnumerable<Qa>>>
GetIssueTrial(int issueId)
{
var random = new Random();
var qaList = await _context.Qa.Where(q => q.IssueId ==
issueId).OrderBy(q =>
random.Next()).Take(1).ToListAsync();
return qaList;
}
}
}

}
---

© 2023 VMware, Inc.

これらのエンドポイントは、それぞれ Qa、Subject、Scope、Issue のテーブルからランダムに
データを取得し、JSON形式で返します。QaTrial エンドポイントは20件のデータを取得し、
SubjectTrial、ScopeTrial、IssueTrial エンドポイントは1件のデータを取得します。
それぞれのエンドポイントには、GET メソッドが含まれています。また、それぞれのエンドポイントに
は、必要なデータベースコンテキストが含まれています。
21

22.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 – 8
ソースコードを⽣成させる
shosuz

---

Swashbuckle はインストールしなくていいのですか︖

Configureメソッドに以下のコードを追加します。

GitHub Copilot

app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json",
"LegalAPI v1");
});

先程の回答で Swashbuckle のインストールについて⾔及していなかったことをお
詫び申し上げます。Swashbuckle は、Swagger を使⽤するための
ASP.NET Core ライブラリです。Swagger を使⽤する場合は、
Swashbuckle をインストールする必要があります。
以下は、Swashbuckle を使⽤して Swagger を設定するための⼿順です。
1.

Swashbuckle.AspNetCore パッケージをインストールします。

dotnet add package Swashbuckle.AspNetCore

これにより、Swagger UI が有効になり、API のドキュメントを表⽰することができ
ます。
以上の⼿順を実⾏することで、Swashbuckle を使⽤して Swagger を設定す
ることができます。

2. Startup.cs ファイルを開き、ConfigureServices メソッドに以下のコードを
追加します。
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "LegalAPI",
Version = "v1" });
});
これにより、Swaggerの設定が追加されます。
--© 2023 VMware, Inc.

・ Swashbuckle など忘れている点を指摘しながら指⽰する
・ 再び .NET 7 を忘れているので 2. は次の指⽰で対応
22

23.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 9
ソースコードを⽣成させる
shosuz
以上で API 部分は完成でしょうか︖このあと、.NET 7 なので Server/Program.cs 内に
Swagger を記述するのでしょうか︖
GitHub Copilot
.NET 7 での Program.cs ファイルの例です。この例では、Swagger を使⽤して API の
ドキュメントを⽣成しています。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using System;
namespace LegalAPI
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
© 2023 VMware, Inc.
---

--public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{ Title = "LegalAPI", Version = "v1" });
});
}
---

・ .NET 7であることをすぐ忘れるので指摘しながら指⽰する
23

24.
[beta]
.NET 7 の ASP.NET Core Web API プロジェクトを作成 - 10
ソースコードを⽣成させる
GitHub Copilot
--public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json",
"LegalAPI v1");
});
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}

【ここまでのソースコード⽣成のやり取りの概括】
・ Context クラス、Model クラス
→ 作成がアバウトなので修正指⽰
・ Controller クラスもランダムに20件データを取得するエンド
ポイントはともかく、他は1件だけとってくる仕様
→ Scope(Range)=範囲、Issue=論点は良いが、
Subject=科⽬は厳しい。その辺りも修正指⽰
・ appsettings.json を Program.cs から読み込む形に
修正し、Context クラスを Data フォルダに再作成させる
・ Context クラスを使⽤して Azure SQL Database に
アクセスし Model クラス を scaffolding で再作成
・ 各 Table の CRUD ⽤の Controller クラス と API の
エンドポイントを指⽰を貰いながら再作成

}
Startup.cs ファイルが存在しないため、Program.cs ファイルで Swagger の設定を⾏っていま
す。ConfigureServices メソッドで Swagger を設定し、Configure メソッドで Swagger UI
を有効にしています。また、UseRouting メソッドでルーティングを有効にし、UseEndpoints メ
ソッドでエンドポイントをマップしています。
© 2023 VMware, Inc.

・ Services フォルダ内にランダム20問、範囲ごと演習、論点
ごと演習、等々、様々な Controller クラス と API の
エンドポイントを指⽰を貰いながら再作成
24

25.

.NET 7 の ASP.NET Core Web API プロジェクト完成 Swagger UI を表⽰して確認する (https://localhost:(port 番号)/Swagger/index.html) ・ Visual Studio 2022 の発⾏ウイザードで、このまま Azure API Management にデプロイすると簡単 © 2023 VMware, Inc. 25

26.

プロトタイピングの実施 - 2 UI デザイン • Uizard を使⽤してモバイルアプリのデザインを作成 • 画⾯の UI をデザインして完成させる • (Figma で Uizard で作成したデザインをインポートし必要に応じて修正) © 2023 VMware, Inc. 26

27.

Uizard https://uizard.io/ • Uizard は2018年に設⽴された デンマークの企業 • AI を使ったアプリデザインツール • プロのデザイナーでなくてもプログラ ミングができなくても、簡単に UI が作れる • • • • • • • • • • 基本機能 Magic (AI を使った機能) Scan Wireframe Sketch Wireframe Mode Scan Screenshot Smart Themes Attention Heatmap Text Assistant 保存ファイル形式は、SVG, PNG, JPEG, PDF の4種類 無料トライアル、有料プラン © 2023 VMware, Inc. 27

28.

Uizard でプロトタイピングしイメージをエクスポートする https://uizard.io/ • Magic(テキストプロンプトによる ⾃動⽣成) • 実画⾯イメージの取り込み • ⼿書き画⾯イメージの取り込み • その他の⽅法により画⾯遷移等 設定可能(ムービーなど) • JPEG 等で画⾯毎にエクスポート © 2023 VMware, Inc. 28

29.

エクスポートされたイメージ (.JPG の例) https://uizard.io/ © 2023 VMware, Inc. 29

30.

Figma for VSCode https://marketplace.visualstudio.com/items?itemName=figma.figma-vscode-extension テキストエディタを離れることなく、デザインファイルの移動と検査、 デザイナーとの共同作業、変更の追跡、実装のスピードアップ可能 • Figma ファイルを VSCode 内で 開いて編集をすることができる拡張 機能 • この拡張機能を使⽤して、Figma ファイルからコードを⽣成することは できない • ただし、Figma ファイルから CSS スタイルをエクスポートして、React コンポーネントに適⽤できる • また、Figma ファイルからデザインの アイデアを得て、⼿動で React の コンポーネントを作成できる © 2023 VMware, Inc. 30

31.

Figma for VSCode https://marketplace.visualstudio.com/items?itemName=figma.figma-vscode-extension © 2023 VMware, Inc. 31

32.

プロトタイピングの実施 - 3 UI コーディング & API 連携 • Figma for VSCode を使⽤して Figma のデザインを表⽰ • React コンポーネントを使⽤して API と UI を連携させてアプリを完成させる • (Locofy.ai を使⽤して Figma で作成したデザインから React コンポーネントを作成) © 2023 VMware, Inc. 32

33.

参考 : Locofy.ai https://www.locofy.ai/ • Figma で作成した UI デザイン から React.js のコードを⾃動 ⽣成するサービス • デザインと開発の間のギャップが 埋まり、効率的な開発が可能に • デザインの構造を読み取り、適切 なコンポーネントを⾃動⽣成 • ⼿動でコンポーネントを作成する ⼿間が省け、効率的な開発が 可能 © 2023 VMware, Inc. 33

34.

参考︓Figma の Locofy.ai プラグイン & Figma to Code プラグイン Figma プラグインを使ってソースコードを⽣成できる • これは画像 • Figma デザインから⽣成 する必要がある • Figma to Code プラグイン • • • Flutter Optimized Layout Full App に設定した例 個⼈的にはこれから使い込む 予定 © 2023 VMware, Inc. 34

35.

React コンポーネントを使⽤して API と UI を連携させてアプリを完成させる イメージを参照しながら指⽰内容を⼩出しにしつつ明確なプロンプトで指⽰を⾏う © 2023 VMware, Inc. • 普通に実装 • ●✖ ボタン配置 • Next ボタン実装 • ロジック実装 • ダークテーマに変更 • ⾃分の回答表⽰ • ロジック実装 35

36.
[beta]
React プロジェクトを作成 – 1
最初はランダムに出題する API を普通に呼ぶ
shosuz

このプロジェクトに、Reactクライアントを追加したいと思います。 QaTrial
をもとに表⽰する画⾯を⼀枚⽣成したいです。 コマンドとソースコード等、
⼿順を⽰してください。

--4. React アプリケーションの src ディレクトリに、QaTrial コンポーネントを作成し
ます。以下のコードを src/QaTrial.js として保存してください。
import React, { useState, useEffect } from 'react';
import axios from 'axios';

GitHub Copilot

React クライアントを追加する⼿順は以下の通りです。
1.

React アプリケーションを作成します。以下のコマンドを実⾏してくだ
さい。
npx create-react-app my-app

2.

React アプリケーションのルートディレクトリに移動します。
cd my-app

3. React アプリケーションから、ASP.NET Core Web API にアクセス
するために、axios ライブラリをインストールします。以下のコマンドを実
⾏してください。

function QaTrial() {
const [qas, setQas] = useState([]);
useEffect(() => {
axios.get('/api/qa-trial')
.then(response => {
setQas(response.data);
})
.catch(error => {
console.log(error);
});
}, []);
---

npm install axios
--© 2023 VMware, Inc.

36

37.
[beta]
React プロジェクトを作成 – 2
最初はランダムに出題する API を普通に呼ぶ
--return (
<div>
<h1>LegalAPI QaTrial</h1>
<ul>
{qas.map(qa => (
<li key={qa.id}>
<h2>{qa.question}</h2>
<p>{qa.answer}</p>
</li>
))}
</ul>
</div>
);
}
export default QaTrial;
5. App.js ファイルを編集して、QaTrial コンポーネントを表⽰するようにします。以下のコード

--import React from 'react';
import QaTrial from './QaTrial';
function App() {
return (
<div className="App">
<QaTrial />
</div>
);
}
export default App;
6. React アプリケーションを起動します。以下のコマンドを実⾏してください。
npm start
これで、React アプリケーションが起動し、QaTrial コンポーネントが表⽰されます。ただし、
ASP.NET Core Web API が localhost:5000 でリッスンしている必要があります。
また、React アプリケーションと ASP.NET Core Web API が同じドメインで実⾏されてい
る場合は、axios の URL を変更する必要があります。

を App.js に追加してください。

---

・ とりあえず雛形的なコードを⽣成してもらい、これをベースに
指⽰を与えていく
© 2023 VMware, Inc.

37

38.
[beta]
React プロジェクトを作成 – 3
ランダム出題する API を呼ぶ画⾯の修正を⾏っていく
shosuz

QaTrial.js、エンドポイントは、https://localhost:7105/qa-trial です。

GitHub Copilot

了解です。URL を https://localhost:7105/qa-trial に変更します。
以下のように、QaTrial.js ファイルを編集してください。
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function QaTrial() {
const [qas, setQas] = useState([]);
useEffect(() => {
axios.get('https://localhost:7105/qa-trial')
.then(response => {
setQas(response.data);
})
.catch(error => {
console.log(error);
});
}, []);
--© 2023 VMware, Inc.

--return (
<div>
<h1>LegalAPI QaTrial</h1>
<ul>
{qas.map(qa => (
<li key={qa.id}>
<h2>{qa.question}</h2>
<p>{qa.answer}</p>
</li>
))}
</ul>
</div>
);
}
export default QaTrial;
これで、QaTrial コンポーネントが https://localhost:7105/api/qatrial にアクセスするようになります。ただし、Web API が正しく構成されている
ことを確認してください。また、Web API が CORS を許可していない場合
は、ブラウザでエラーが発⽣する可能性があります。

・ とりあえず雛形的なコードを⽣成してもらい、これをベースに
指⽰を与えていく

38

39.
[beta]
React プロジェクトを作成 – 4
ランダム出題する API を呼ぶ画⾯の修正を⾏っていく
shosuz

Figma for VSCode で画⾯を開いています。 まずは、Individual
Problem と⾔う画⾯で QaTrial サービスの中の qa.id、qa.subject、
qa.range、qa.issue、qa.question、をそれぞれの適切な場所(ラベ
ルまたはテキストボックス)に表⽰します。 Answer and Explanation
と⾔う画⾯に遷移します。 この画⾯では QaTrial サービスの中の 、
qa.id、qa.subject、qa.range、qa.issue、qa.question、
qa.answer. qa.description をそれぞれの適切な場所(ラベルまたは
テキストボックス)に表⽰します。 コードを⽣成できますか︖

GitHub Copilot

はい、以下は React コンポーネントの例です。このコンポーネントは、
individual Problem 画⾯と Answer and Explanation 画⾯の両
⽅で使⽤できます。このコンポーネントは、props として qa オブジェクトを
受け取り、qa.id、qa.subject、qa.range、qa.issue、qa.quesion、
qa.answer. qa.description をそれぞれの適切な場所に表⽰します。
---

© 2023 VMware, Inc.

--- // QaDisplay.js
import React from 'react';
function QaDisplay(props) {
const { qa } = props;
return (
<div>
<label>ID:</label>
<span>{qa.id}</span>
<br />
<label>Subject:</label>
<span>{qa.subject}</span>
<br />
<label>Range:</label>
<span>{qa.range}</span>
<br />
<label>Issue:</label>
<span>{qa.issue}</span>
<br />
<label>Question:</label>
<span>{qa.question}</span>
<br />
<label>Answer:</label>
<span>{qa.answer}</span>
<br />
<label>Description:</label>
<span>{qa.description}</span>
<br />
</div>
);
}
export default QaDisplay;
39

40.
[beta]
React プロジェクトを作成 – 5
ランダム出題する API を呼ぶ画⾯の修正を⾏っていく
GitHub Copilot

このコンポーネントを使⽤するには、以下のようにします。

--function AnswerAndExplanation(props) {
const { qa } = props;

import React from 'react';
import QaDisplay from './QaDisplay';

return (
<div>
<h2>Answer and Explanation</h2>
<QaDisplay qa={qa} />
</div>
);

function IndividualProblem(props) {
const { qa } = props;
return (
<div>
<h2>Individual Problem</h2>
<QaDisplay qa={qa} />
<button onClick={goToAnswerAndExplanation}>Answer
and Explanation</button>
</div>
);
}
---

© 2023 VMware, Inc.

}
export { IndividualProblem, AnswerAndExplanation };

・ 初期の画⾯の状態を⽰させ、ここから随時修正を加えていく

40

41.
[beta]
React プロジェクトを作成 – 6
何度か試⾏錯誤した後の現在の React コンポーネント他実装
// App.js

// App.css
---

import React from "react";
import { BrowserRouter as Router, Routes, Route } from "reactrouter-dom";
import IndividualProblem from "./IndividualProblem";
import AnswerAndExplanation from "./AnswerAndExplanation";
import "./App.css"; // App.css ファイルをインポート

//最終⾏に追加
--body {
background-color: #333;
color: #fff;
}

function App() {
return (
<Router>
<Routes>
<Route path="/" element={<IndividualProblem />} />
<Route path="/individual-problem"
element={<IndividualProblem />} />
<Route
path="/answer-and-explanation/:id"
element={<AnswerAndExplanation />}
/>
</Routes>
</Router>
);
}
export default App;

© 2023 VMware, Inc.

41

42.
[beta]
React プロジェクトを作成 – 7
何度か試⾏錯誤した後の現在の React コンポーネント他実装
// QaDisplay.js
import React from "react";
function QaDisplay(props) {
const { qa } = props;
return (
<div>
<label>ID:</label>
<span>{qa.id || ""}</span>
<br />
<label>Subject:</label>
<span>{qa.subject}</span>
<br />
<label>Range:</label>
<span>{qa.range}</span>
<br />
<label>Issue:</label>
<span>{qa.issue}</span>
<br />
<label>Question:</label>
<span>{qa.question}</span>
<br />
<label>Answer:</label>
<span>{qa.answer}</span>
<br />
<label>Description:</label>
<span>{qa.description}</span>
</div>
);
}
© 2023 VMware, Inc.
export default QaDisplay;

// IndividualProblem.js
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./IndividualProblem.css"; // ダークモードのスタイルをインポート
function IndividualProblem() {
const [qaList, setQaList] = useState([]);
const [selectedQa, setSelectedQa] = useState(null);
const [error, setError] = useState(false);
const [showAnswer, setShowAnswer] = useState(false);
const [isCorrect, setIsCorrect] = useState(null);
const [subjectName, setSubjectName] = useState("");
const [rangeName, setRangeName] = useState("");
const [issueName, setIssueName] = useState("");
const [myAnswer, setMyAnswer] = useState(null);
useEffect(() => {
axios
.get("https://localhost:7105/qa-trial")
.then((response) => {
setQaList(response.data);
})
.catch((error) => {
console.log(error);
setError(true);
});
}, []);
---

42

43.
[beta]
React プロジェクトを作成 – 8
何度か試⾏錯誤した後の現在の React コンポーネント他実装
// IndividualProblem.js

// IndividualProblem.js

--useEffect(() => {
if (qaList.length > 0) {
const randomIndex = Math.floor(Math.random() * qaList.length);
setSelectedQa(qaList[randomIndex]);
}
}, [qaList]);

---

useEffect(() => {
if (selectedQa) {
axios
.get(`https://localhost:7105/api/subject/${selectedQa.subjectId}`)
.then((response) => {
setSubjectName(response.data.name);
})
.catch((error) => {
console.log(error);
});
axios
.get(`https://localhost:7105/api/range/${selectedQa.rangeId}`)
.then((response) => {
setRangeName(response.data.name);
})
.catch((error) => {
console.log(error);
});

---

© 2023 VMware, Inc.

axios
.get(`https://localhost:7105/api/issue/${selectedQa.issueId}`)
.then((response) => {
setIssueName(response.data.name);
})
.catch((error) => {
console.log(error);
});
}
}, [selectedQa]);
const handleNextClick = () => {
const randomIndex = Math.floor(Math.random() * qaList.length);
setSelectedQa(qaList[randomIndex]);
setShowAnswer(false);
setIsCorrect(null);
setMyAnswer(null);
};
const handleCorrectClick = () => {
setIsCorrect(true);
setShowAnswer(true);
setSelectedQa((prevQa) => ({ ...prevQa, myAnswer: true }));
setMyAnswer(true);
};
---

43

44.
[beta]
React プロジェクトを作成 – 9
何度か試⾏錯誤した後の現在の React コンポーネント他実装
// IndividualProblem.css

// IndividualProblem.js
--<div>
<label>あなたの回答: </label>
{myAnswer === true ? (
<span>●</span>
) : myAnswer === false ? (
<span>❌</span>
):(
<span>-</span>
)}
</div>
{showAnswer && (
<>
<p>
{isCorrect ? "正解" : "不正解"}: {selectedQa.answer}
</p>
<p>{selectedQa.description}</p>
</>
)}
<button onClick={handleCorrectClick}>●</button>
<button onClick={handleIncorrectClick}>❌</button>
<button onClick={handleNextClick}>Next</button>
</>
):(
<p>Loading...</p>
)}
</div>
);

.individual-problem-container {
background-color: #333;
color: #fff;
}

// IndividualProblem.js
--const handleIncorrectClick = () => {
setIsCorrect(false);
setShowAnswer(true);
setSelectedQa((prevQa) => ({ ...prevQa, myAnswer: false }));
setMyAnswer(false);
};
return (
<div className="individual-problem-container">
{" "}
{/* ダークモードのスタイルを適⽤ */}
<h2>Individual Problem</h2>
{error ? (
<p>Failed to load data.</p>
) : selectedQa ? (
<>
<p>ID: {selectedQa.id}</p>
<p>科⽬: {subjectName}</p>
<p>範囲: {rangeName}</p>
<p>論点: {issueName}</p>
<p>問題: {selectedQa.question}</p>
--© 2023 VMware, Inc.

}
export default IndividualProblem;
--44

45.
[beta]
React プロジェクトを作成 – 10
何度か試⾏錯誤した後の現在の React コンポーネント他実装
// AnswerAndExplanation.js

--const handleBackClick = () => {
const randomIndex = Math.floor(Math.random() * qaList.length);
setQa(qaList[randomIndex]);
};

import React, { useState, useEffect } from "react";
import axios from "axios";
import { Link, useParams } from "react-router-dom";
function AnswerAndExplanation() {
const { id } = useParams();
const [qa, setQa] = useState({});
const [error, setError] = useState(false);
const [qaList, setQaList] = useState([]);

return (
<div>
<h2>Answer and Explanation</h2>
{error ? (
<p>Failed to load data.</p>
):(
<>
<p>ID: {qa.id}</p>
<p>Subject: {qa.subject}</p>
<p>Range: {qa.range}</p>
<p>Issue: {qa.issue}</p>
<p>Answer: {qa.answer}</p>
<p>Description: {qa.description}</p>
<p>Question: {qa.question}</p>
<Link to="/" onClick={handleBackClick}>
Back to Individual Problem
</Link>
</>
)}
</div>
);

useEffect(() => {
axios
.get(`https://localhost:7105/api/qa/${id}`)
.then((response) => {
setQa(response.data);
})
.catch((error) => {
console.log(error);
setError(true);
});
}, [id]);
useEffect(() => {
axios
.get("https://localhost:7105/qa-trial")
.then((response) => {
setQaList(response.data);
})
.catch((error) => {
console.log(error);
setError(true);
});
}, []);

---

© 2023 VMware, Inc.

}
export default AnswerAndExplanation;

45

46.

まとめ © 2023 VMware, Inc. 46

47.

Agenda まとめ l 今回の実⾏環境、プロトタイピングの⽅針決定 l プロトタイピングの実施 1 – API の準備 l プロトタイピングの実施 2 – UI デザイン l プロトタイピングの実施 3 – UI コーディング & API 連携 l まとめ ©2023 VMware, Inc. 47

48.

9/19 より登録開始中 Multi Cloud、Private AI、Spring One コンテンツも網羅 開催⽇の 11/14, 15⽇は Ignite(オンライン)の前⽇︕ (例) EPXXXXX

49.

Thank you for your attention! © 2023 VMware, Inc.