Search results for 'Delphi/C++Builder'

  1. 2019.06.20 -- [개발환경] 깃허브 PR을 이용한 코드리뷰 환경 구성(4)
  2. 2019.06.19 -- [개발환경] 깃허브에 저장소 생성 및 연동하기(3)
  3. 2019.06.19 -- [개발환경] RAD 스튜디오에서 Git 설정 및 불러오기(2)
  4. 2019.06.18 -- [개발환경] Git 설치와 저장소 구성(1)
  5. 2019.05.30 -- 델파이 코드 주석 추가 및 문서화 방안
  6. 2019.05.23 -- [VCL] 용량이 큰 JPEG 파일 다루기 - JPEG 라이브러리 조사
  7. 2019.01.30 -- 델파이 코드 작성 규칙
  8. 2019.01.23 -- 이더넷 어댑터 정보((MacAddress, IP 등) 목록 알아오기
  9. 2017.11.22 -- [튜토리얼] 메일 전송(IdSMTP 이용) (2)
  10. 2017.11.22 -- [튜토리얼] FTP 업로드(TIdFTP 이용) (1)
  11. 2017.10.30 -- 안면인식(Face Detection) 라이브러리(안드로이드, iOS)
  12. 2017.10.30 -- TTS(Text-to-Speech) 라이브러리(윈도우, 맥OS, iOS, 안드로이드)
  13. 2017.10.30 -- 델파이로 빅데이터 데이터베이스 연동하기(Cassandra, Couchbase, MongoDB)
  14. 2017.09.18 -- [REST API] 다음 Kakao > 로컬 > 주소검색 연동하기
  15. 2017.05.25 -- 프로세스 메모리 사용량 로그 기록 - 성능 모니터 이용
  16. 2017.05.24 -- [REST API][실습] 데이터셋 기반 REST API 개발하기
  17. 2017.05.19 -- [REST API][실습] REST API 클라이언트 개발하기(REST Client 이용) (1)
  18. 2017.05.17 -- [REST API][실습] REST API 서버 개발하기(엔드포인트 구현, RAD 서버 이용)
  19. 2017.05.11 -- [REST API] REST API 이해하기 (1)
  20. 2017.04.27 -- [RAD서버] EMS 패키지 프로젝트 시작하기

[개발환경] 깃허브 PR을 이용한 코드리뷰 환경 구성(4)

2019.06.20 11:31

이전 글에서는 깃허브에 여러분의 저장소를 만들고 연동하는 내용을 살펴봤습니다.

 

이 글에서는마스터 저장소와 개발용 저장소를 나누고, 깃허브 Pull Request을 이용 코드리뷰 환경을 구성합니다.

이 글에서 다음 내용을 설명합니다.

  1. 코드리뷰를 위한 깃허브 저장소 구성 전략
  2. Fork로 개발용 저장소 복사하기
  3. 변경내역 적용 요청(PR) 및 코드리뷰

 

이 시리즈에서는 깃과 깃허브를 이용하는 기본적인 방법과 깃허브를 이용한 코드리뷰 방법을 설명합니다.

 

코드리뷰를 위한 깃허브 저장소 구성 전략

Pull Request 활용

깃허브에서 코드리뷰는 깃허브의 Pull Request(이하 PR) 기능을 이용합니다.

PR은 원격 저장소간 변경된 내역을 적용(당겨가길) 요청하는 기능입니다.

 

다음 그림은 데브기어 교유과정에서 발생한 PR 예시입니다.

PR 작성 시 작업내용에 대한 코멘트와 여러건의 커밋을 포함합니다.

 

PR의 하단에는 PR에 대한 전반적은 의견을 남길 수 있습니다.

공동작업자(관리자)의 경우 적용요청(PR)을 병합(Merge)하거나 종료(Close)할 수 있습니다.

또한, 커밋 로그에서는 소스코드 줄 단위로 의견을 남기는 것도 가능합니다.

 

Fork - 원격저장소 복사

PR을 활용하려면 원격 저장소가 분리되어 있어야 합니다. 원격 저장소를 분리는 Fork 기능을 이용합니다.

원격 저장소를 분리하면 다음의 잇점이 생깁니다.

  • 마스터(출시용: Release) 저장소와 개발용 저장소가 분리되 관리자와 개발자 작업 공간 분리
  • 여러 개발자(또는 개발팀) 별로 저장소 사용 가능
  • 각 개발자가 작업한 결과물을 관리자 및 팀원들이 검토 후 마스터 저장소에 적용(또는 중단)

 

위 구성을 활용해 다양한 저장소 구성 전략을 새울 수 있습니다.

 

소규모 개발팀에서는 팀장과 운영팀에서 마스터 저장소를 관리합니다. 개발자들은 개인 개발용 저장소에서 작업합니다.

개발작업 완료 후 개발용 저장소에 작업한 내용을 마스터 저장소에 반영요청(PR)합니다. 팀장과 다른 팀원은 PR에 대한 코드리뷰 후 적용 여부를 판단합니다.

 

Fork로 개발용 저장소 복사하기

마스터 저장소를 Fork해 개발용 저장소를 생성하고, 개발용 저장소를 이용하는 방법을 실습합니다.

 

마스터 저장소 다음 링크의 데브기어의 교육용 저장소로 실습을 진행합니다.

 

위 링크 방문 후 상단 우측의 [Fork]를 클릭합니다.

 

잠시후 여러분의 계정에 SetupText 저장소가 생성될 것입니다.

이제 마스터 저장소는 devgeredu/SetupTest로 개발용 저장소는 (여러분 아이디)/SetupTest로 진행합니다.

 

 

이제 앞으로 여러분들은 개발용 저장소에서 작업을 진행해야 합니다.

 

이전 글에서 여러분들이 만든 저장소를 RAD 스튜디오로 불러오고 Commit 및 Push 했던 작업을 개발용 저장소를 대상으로 진행합니다.

 

간단한 과정은

  1. 저장소 URL 복사
  2. RAD 스튜디오에서 File > Open From Version Control...
  3. Git 선택 > 저장소 주소와 저장 경로 지정 후 프로젝트 열기
  4. 프로젝트 소스코드 수정(에디트 컴포넌트 추가)
  5. Project 팬에서 프로젝트 팝업 메뉴 Git > Commit > From Repository Root
  6. 커밋 메시지 입력(Edit 추가) 및 Commit 버튼 클릭
  7. Project 팬에서 프로젝트 팝업 메뉴 Git > Push > From Repository Root
  8. 깃허브 계정으로 로그인
  9. 깃허브 페이지에서 변경내역 확인

 

변경내역 적용 요청(PR) 및 코드리뷰

개발용 저장소에서 개발이 완료(여러차례의 Commit과 Push)되면, 그 내용을 마스터 저장소에 적용해야 합니다.

여러분들은 마스터 저장소에 대한 쓰기 권한이 없기 때문에 마스터 저장소의 작업자에게 내가 작성한 코드를 적용하길 요청하는 Pull Request를 작성해야 합니다.

 

개발용 저장소 페이지의 상단에 Pull requests 탭을 선택합니다.

그리고, [New pull request] 버튼을 클릭합니다.

 

페이지가 이동되면 마스터 저장소로 이동되고, PR을 생성할 수 있습니다.

먼저 두개의 브랜치를 대상을 확인합니다. 커밋 로그를 확인합니다. 하단에 변경된 파일 정보를 확인할 수 있습니다.

확인 후 [Create pull request] 버튼을 클릭해 PR을 생성합니다.

PR의 제목과 내용 입력 후 [Create pull request] 버튼을 클릭합니다.

 

다음과 같이 PR이 등록되었습니다. 

PR 상세화면에서는 추가 코멘트를 달거나, 본인이 작성한 PR을 닫을 수 있습니다.

 

Pull Requests 탭을 다시 선택하면 PR 목록이 표시됩니다.

이 목록은 마스터 저장소 관리자 뿐아니라 누구에게나 공개됩니다.

 

마스터 저장소 관리자의 PR 상세 페이지에는 PR에 대한 정보와 함께, 변경사항을 병합(Merge)가능합니다.

관리자는 다른 코드리뷰어의 PR에 대한 코멘트와 소스코드에 대한 코멘트를 참고해서 병합 여부를 판단할 수 있습니다.

 

PR의 변경사항 병합을 결정했다면, [Merge pull request] 버튼을 클릭해 병합하면, 해당 PR의 상태가 Open에서 Merged로 변경되어 닫힙니다.

소스코드를 확인해보면 PR에서 변경된 "Edit 추가" 커밋 메시지가 표시됨을 확인할 수 있습니다.

 

정리

깃 설치부터 RAD 스튜디오의 깃 설정, 생성한 저자소와 연동 및 코드리뷰를 위한 저장소 방안까지 다음 시리즈를 통해 살펴봤습니다.

 

 

 

 

사실 이 글은 가장 기본적인 내용으로만 구성했습니다. 깃과 깃허브에는 더 다양한 기능들이 있습니다.

여러분들의 조직과 환경에 맞춰 그 기능을 추가 학습해 개발조직에 가장 중요한 소스코드를 효과적으로 관리 운영하시기 바랍니다.

 

험프리.김현수 Delphi/C++Builder fork, git, github, PR, pull request, RAD스튜디오, , 깃허브, 저장소구성, 코드리뷰

[개발환경] 깃허브에 저장소 생성 및 연동하기(3)

2019.06.19 17:37

이전 글에서 RAD 스튜디오에서 Git 설정 및 불러오기를 진행했습니다.

 

이 글에서는 깃허브에 여러분의 저장소를 생성하고, RAD 스튜디오로 열고, 변경사항을 저장소에 반영하는 내용을 진행합니다.

이 글에서는 다음 내용을 설명합니다.

  1. 깃허브에 저장소 생성
  2. RAD 스튜디오에서 생성한 저장소 열기
  3. 소스코드 변경 후 커밋 및 저장소에 반영

 

이 시리즈에서는 깃과 깃허브를 이용하는 기본적인 방법과 깃허브를 이용한 코드리뷰 방법을 설명합니다.

 

깃허브에 저장소 생성

깃허브에 여러분의 저장소를 생성하는 내용을 설명합니다.

 

깃허브에서 새로운 저장소를 생성합니다.

저장소 이름을 입력하고, .gitignore를 선택합니다.(.gitignore는 버전관리 제외 대상 포맷 파일입니다.)

[Create repository] 버튼을 눌러 저장소를 생성합니다.

생성된 저장소에서 [Clone or download] 버튼을 누르고, 클립보드로 복사 버튼을 클릭합니다.

 

RAD 스튜디오에서 생성한 저장소 열기

RAD 스튜디오를 열고, File > Open From Version Controll... 메뉴를 선택합니다.

Git 선택 후 [OK] 버튼을 클릭합니다.

Source 항목은 깃 허브에서 클립보드로 복사한 주소를 붙여넣기(Ctrl + V) 후 Destination 항목에 저장할 로컬 경로 선택 후 [OK] 버튼을 클릭합니다.

 

소스코드 변경 후 커밋 및 저장소 반영

위에서 불러온 저장소에 프로젝트 파일을 만들고 커밋하는 절차를 설명합니다.

 

프로젝트 생성 및 저장

위의 로컬 경로에 프로젝트 파일을 저장합니다.

File > New > WIndows VCL Application

File > Savle All

 

이제 프로젝트 팬에서 프로젝트 팝업 메뉴 중 Git 메뉴가 표시됩니다.
(프로젝트 파일의 디렉토리에 깃 정보가 있으면 Git 메뉴 표시)

 

Commit - 로컬 저장소에 소스코드 반영

Git > Commit > From Repository Root 메뉴를 선택합니다.

Commit 화면에서 [Show unversioned files] 체크박스를 선택합니다.

파일 중 커밋할 대상을 선택합니다.(Check or uncheck all 선택)

커밋 메시지(Comment)를 입력 합니다.

[Commit] 버튼을 클릭합니다.

Push - 원격 저장소에 로컬저장소의 내용 반영

Git > Push > From Repository Root 메뉴를 선택합니다.

Git Login 창에서 깃허브의 계정으로 로그인합니다.

원격 저장소 확인

깃허브에서 여러분의 저장소에 반영된 목록을 확인합니다.

이후 작업

소스코드를 수정하고, 커밋(Commit)을 합니다. 커밋된 변경내역을 원격저장소에 반영이 필요한 경우 푸시(Push)합니다.

 

커밋 작업은 자주하는 것이 좋지만, 의미있는 단위(작은 기능 추가, 함수 추가, 코드 변경 등)로 커밋하는 것이 좋습니다.

향후 커밋된 작업으로 소스코드를 되돌려야 할 수 있습니다.

 

참고자료

다음 링크에서 협업을 위한 깃허브 구성과 코드리뷰 환경 구성하는 내용을 확인할 수 있습니다.

험프리.김현수 Delphi/C++Builder commit, git, github, , 깃허브

[개발환경] RAD 스튜디오에서 Git 설정 및 불러오기(2)

2019.06.19 16:21

이전 글에서 깃을 설치하고, 저장소의 구성을 살펴봤습니다.

 

이 글에서는 RAD 스튜디오에서 깃을 설정하고 깃허브 소스코드를 RAD 스튜디오에서 여는 방법을 설명합니다.

 

이 글에서는 다음 내용을 설명합니다.

  1. RAD 스튜디오에서 깃 설정
  2. RAD 스튜디오에서 깃허브 저장소의 소스코드 열기
  3. 써드파티 깃 클라이언트 소개

 

이 시리즈에서는 깃과 깃허브를 이용하는 기본적인 방법과 깃허브를 이용한 코드리뷰 방법을 설명합니다.

 

RAD 스튜디오에서 깃 설정

RAD 스튜디오(델파이, C++빌더) 10.3 기준으로 설명합니다. 다른 버전의 경우 옵션 등의 경로가 다를 수 있습니다.

 

툴 옵션(Tools > Options...) 표시 후 Version Control > Git 화면을 표시합니다.

 - Git Executable : 깃 설치 프로그램을 설치한 경로 하위의 bin\git.exe 파일을 선택합니다.

 - Authorization(User Name, Email) : 소스코드 저장 시 적용할 이름과 이메일을 기록합니다.

 

깃허브의 소스코드 열기

깃허브에 저장된 소스코드를 RAD 스튜디오로 여는 과정을 설명합니다.

 

다음 링크는 데브기어 교육용 저장소입니다. 이 저장소의 소스코드를 통해 설명합니다.

(여러분들은 이 저장소의 쓰기권한이 없으므로, 소스코드를 가져올 수 있지만 저장할 수는 없습니다.

가져온 소스를 저장하려면 저장소를 생성하거나 복사(Fork)한 저장소여야 합니다.)

 

다음 링크를 방문합니다.

페이지 중간 우측의 [Clone or download] 버튼 클릭 후 클립보드로 복사 버튼을 클릭합니다.

 

RAD 스튜디오를 열고, File > Open From Version Control... 메뉴를 선택합니다.

Git 선택 후 [OK] 버튼을 클릭합니다.

Source 항목은 깃 허브에서 클립보드로 복사한 주소를 붙여넣기(Ctrl + V) 후 Destination 항목에 저장할 로컬 경로 선택 후 [OK] 버튼을 클릭합니다.

로컬로 복사(Clone)가 완료되면 [OK] 버튼 클릭. 지정된 경로에 소스코드가 복사되었습니다.

 

RAD 스튜디오에 프로젝트를 열수 있는 화면이 표시되면, 프로젝트를 선택 후 [OK] 버튼을 클릭해 프로젝트를 엽니다.

 

이후, 프로젝트 패널에서 프로젝트 팝업 메뉴 중 Git 메뉴를 통해 "Commit, Pull, Push" 등의 작업이 가능합니다.

 

다음 글에서는 위 기능을 이용해 변경(추가/수정/삭제)된 소스코드를 저장소에 반영하는 기능등을 살펴봅니다.

 

써드파티 깃 클라이언트로 소개

RAD 스튜디오의 깃 연동은 가장 중요한 기능(Commit, Pull, Push, Clean, Show Log) 위주로 제공합니다.

깃에는 위 기능 외에 매우 많은 기능(Branch, Merge, Tag 등)을 명령어로 제공합니다. 

 

이 기능들을 UI기반으로 사용할 수 있는 써드파티 깃 클라이언트를 이용할 수 있습니다.

많은 써드파티 깃 클라이언트가 있지만, 이 글에서는 SourceTree와 TortoiseGit을 소개합니다.

 

SourceTree

SourceTree는 저장소의 내용을 시각적으로 표현하고 관리할 수 있는 깃 GUI입니다.

현재 가장 인기있는 깃 클라이언트 중 하나입니다.

TortoiseGit

탐색기 기반으로 동작하는 깃 클라이언트입니다.

개인적으로 예전부터 사용하던 TortoiseSVN이 익숙해 사용하고 있습니다.

참고자료

다음 링크에서 깃허브에 저장소를 생성하고 연동(불러오기, 저장히기)하는 내용을 확인할 수 있습니다.

 

참고링크

 

험프리.김현수 Delphi/C++Builder git, github, RAD스튜디오, , 깃허브

[개발환경] Git 설치와 저장소 구성(1)

2019.06.18 17:59

깃(Git)은 컴퓨터 파일의 변경사항을 추적하고 여러명의 사용자들 간에 해당 파일들의 작업을 조율하기 위한 분산 버전 관리 시스템이다. - 위키백과

깃허브(Github)는 분산 버전관리 툴인 깃을 사용하는 프로젝트를 지원하는 웹호스팅 서비스입니다. - 위키백과

 

버전관리 시스템은 소스코드의 중요한 변화를 기록하는 작업으로 개인 및 팀 작업에 반드시 필요한 요소입니다.

깃허브는 주로 오픈소스등 공개된 저장소로 사용되지만, 개인용 저장소를 생성해 비공개 저장소로 이용가능합니다.

 

이 시리즈에서는 깃과 깃허브를 이용하는 기본적인 방법과 깃허브를 이용한 코드리뷰 방법을 설명합니다.

 

이 글에서는 다음 내용을 설명합니다.

  1. 깃 설치하기
  2. 깃 저장소와 소스코드의 구성
  3. 기타 - 깃의 기능(명령어) 소개

깃 설치

깃의 명령어를 사용하기 위해 깃 설치 프로그램을 설치합니다.

(깃허브 계정이 없다면)앞으로 깃허브에서의 실습을 위해 깃허브 계정을 생성합니다.

깃 저장소와 소스코드의 구성

기본 구성

깃 저장소는 위 그림과 같이 원격(Remote-Github) 저장소와 로컬(Local) 저장소로 분산되어 운용됩니다.

 

깃 허브에서 저장소를 생성 후, 로컬에서 Clone 명령을 통해 로컬로 소스코드를 복사합니다.

이후 변경된 내용은 Pull 명령을 통해 로컬에 반영합니다.

로컬의 소스코드를 편집 후 로컬 저장소에 Commit해 반영합니다.

로컬 저장소의 변경된 내역은 Push 명령을 통해 원격 저장소에 반영합니다.

 

마스터, 개발용 저장소 구성

위 그림과 같이 마스터 저장소(Master Rep.)와 개발용 저장소(Dev. Rep.)를 분리해 운영할 수 있습니다.

 

마스터 저장소를 Fork해 개발용 저장소로 복사해 병행 운용합니다.

마스터 저장소는 관리자가 운용, 개발용 저장소는 개발자가 운용합니다.

개발자는 개발용 저장소에서 소스코드를 Clone해 개발을 진행합니다.

개발용 저장소의 변경된 내역은 Pull Request로 마스터 저장소에 적용을 요청합니다.

관리자는 요청(Pull Request)을 확인 후 마스터 저장소에 적용합니다.

 

Fork는 깃 허브에서 제공하는 기능입니다. 또한 깃 허브에서는 Pull Request에시 커멘트를 추가, 답변할 수 있는 기능을 제공합니다. 이 기능을 이용해 코드리뷰 가능합니다.

 

기타 - 깃의 기능(명령어) 소개

깃은 명령줄 도구로 명령어를 통해 제어할 수 있습니다. 개발 도구나 써드파티 깃 클라이언트는 이 명령어 기반으로 UI를 제공합니다.

 

이 시리즈에서 사용하는 기능 들

  • Commit - 소스코드(및 기타 파일)의 변경(추가,수정,삭제) 내역을 로컬 저장소에 적용
  • Clone - 원격 저장소의 파일을 로컬로 복사해 로컬 저장소 생성
  • Pull - 원격 저장소의 변경된 내역을 로컬 저장소에 반영
  • Push - 로컬 저장소의 변경된 내역을 원격 저장소에 반영
  • Fork - 타인의 원격 저장소를 내 소유의 원격 저장소로 복사
  • Pull Request - Fork한 저장소의 변경내역을 소유자의 저장소에 적용을 요청

기타 자주사용하는 기능 들

  • Branch - 소스코드를 독립적으로 작업 진행하기 위한 분계(가지치기)
  • Checkout - Branch한 소스코드로 전환
  • Merge - Branch한 소스코드를 병합
  • Tag - 특정 시점에 알기 쉬운 이름을 부여(보통 릴리즈 시 사용. v1.0 등)

기타 다른 명령어 및 기능은 깃의 참고문서를 참고하시기 바랍니다.

 

참고 자료

다음 링크에서 RAD 스튜디오에서 Git 설정 및 불러오기 내용을 확인할 수 있습니다.

 

깃에 대해 추가 학습을 원한다면 다음 링크를 참고하시기 바랍니다.

 

험프리.김현수 Delphi/C++Builder git, github, SCM, , 깃허브

델파이 코드 주석 추가 및 문서화 방안

2019.05.30 17:09

주석은 코드를 더 읽기 쉽고, 유지보수하기 쉽게 할 수 있는 가장 기본적인 요소 중 하나입니다.

특히 팀단위로 개발하거나, 오랫동안 유지보수해야 하는 경우 진가를 발휘합니다.

 

이 글에서는 주석을 좀 더 효과적으로 달고, 내용을 문서화하는 방법을 소개합니다.

XMLDoc과 JavaDoc 주석의 특징과 추가 방법, 문서화 하는 방법을 알아봅니다.

 

XMLDoc과 JavaDoc 주석 추가

XMLDoc 주석

XMLDoc 주석의 특징

  • 3 중 슬래시(///)로 시작
  • XML 태그로 작성
  • 코드 에디터의 헬프 인사이트에 표시
  • XML 태그로 가독성이 다소 떨어짐

XML 주요 항목

  • <summary> 함수 또는 클래스에 대한 설명
  • <param name="파라메터 이름"> 파라메터에 대한 설명
  • <returns> 함수의 반환 값 설명
  • < exception cref="예외 유형"> 메소드에서 전달되는 예외

예시

XMLDoc의 특징

XML Doc 주석 추가 시 코드 에디터의 헬프 인사이트에 표시됩니다.

단, 선언부(interface 영역)에 XML Doc 추가 시에만 표시됩니다.

한가지 팁으로, 코드 템플릿에 템플릿을 추가하면 필요시 코드에디터에 주석을 쉽게 추가 할 수 있습니다.

(Ctrl + J > 키워드 입력 또는 키워드 입력 > Ctrl + J)

 

코드 템플릿 추가방법

View > Tool Windows > Templates 메뉴 선택

New Code Template 버튼 클릭

아래 코드 참고해 XML 태그 수정 후 저장(예> xmldoc.summary.xml)

xmldoc.summary.xml
0.00MB

 

또는 위 XML 태그로 xml 파일 생성(별도의 텍스트 에디터에서) 및 저장

템플릿 디렉토리에 xml 파일 복사

(10.3 기준 템플릿 디렉토리 : C:\Program Files (x86)\Embarcadero\Studio\20.0\ObjRepos\en\Code_Templates\Delphi)

 

JavaDoc 주석

자바의 주석 형식으로 주석을 작성하면, 별도 프로그램을 이용 문서화(HTML, CHM, PDF 등)가 가능합니다.

JavaDoc 주석의 특징

  • 블록 주성({** 시작 *}로 끝) 또는 한줄 주석(3 중 슬래시(///)로 시작)
  • 주석의 속성(태그)은 @으로 시작
  • XMLDoc에 비해 주석 가독성이 높음(짧음)

JavaDoc 주요 태그

  • 태그 없는 경우 함수에 대한 설명
  • @author 작성자
  • @version 버전
  • @param 메소드 파라메터 설명
  • @return 반환 값 설명
  • @throws 메소드에서 전달되는 예외

예시

 

주석 문서화

추가한 주석을 문서화(문서로 내보내기)하는 방법을 알아봅니다.

XMLDoc 주석 문서화

XMLDoc을 문서화 하기 위해서는 Model을 생성해야 합니다.

Projects 팬에서 Model View 탭을 선택 후 모델을 생성합니다.

Model View에서 문서화할 대상(프로젝트 또는 유닛) 선택 후 팝업메뉴에서 "Generate Documentation..." 메뉴를 선택 합니다.

문서화 범위(Scope) 및 옵션(Options)를 선택 후 [OK] 버튼을 클릭 합니다.

 

결과 예시

다음과 같이 XMLDoc 주석을 추가했습니다.

 

생성된 HTML은 다음과 같습니다.

JavaDoc 주석 문서화

JavaDoc 포맷의 주석을 문서화 하기 위해서는 별도의 프로그램을 이용해야 합니다.

이 글에서는 DelphiCodeToDoc를 이용해 문서화합니다.

 

DelphiCodeToDoc은 델파이로 제작된 오픈소스(GPL)로 자유롭게 설치하고 필요한 기능을 수정해 기여할 수 있습니다.

문서화 포맷으로 CHM, HTML, PDF를 지원합니다.(Configuration 화면의 Output options > Output Format에서 지정)

결과물이 썩 이쁘지는 않지만, 그렇게 나쁘지도 않습니다.

 

DelphiCodeToDoc(DCTD) 설치

DelphiCodeToDoc(DCTD) 실행

DelphiCodeToDoc.exe 실행 후 [New] 버튼 클릭(또는 File > New 메뉴 선택)

마법사 페이지에서 옵션 설정 및 대상 파일(또는 디렉토리) 선택 및 추가 후 [Finish]

메인화면에서 [Check and Build] 버튼 클릭(또는 Project > Check and Build 메뉴 선택)

빌드 시 CHM 도움말이 표시되고, 지정된 경로(Ouput Folder)에 지정된 포맷

 

결과 예시

DCTD에서 설정한 프로젝트 관련 내용 표시

프로젝트 이름을 한글로 설정 시 좌측 내용트리에 한글깨짐 현상이 있으나, 문서내에서는 정상출력 확인

 

프로시저에 대한 문서

@author, @version 태그 추가했지만, 문서에 표시되지 않음

웹으로 내보내기한 Unit에 대한 문서

총평

XMLDoc과 JavaDoc 주석을 추가하고 문서화 하는 내용을 살펴봤습니다.

 

XMLDoc은 주석에 XML 태그가 있어 코드내의 가독성은 떨어지지만, 헬프 인사이트에 표시된다는 장점이 있습니다.(단, 선언부에 주석을 달아야 합니다.

JavaDoc은 코드내 주석에 대한 가독성이 상대적으로 높지만, 헬프 인사이트 등으로 표시되지 않습니다.

 

문서의 결과물은 개인적으로 JavaDoc의 결과물이 더 다양하고 깔끔하다고 생각합니다.

또한 오픈소스여서 필요한 경우 직접 수정해 필요한 기능을 확장할 수 있습니다.(물론 쉽지 않습니다.)

 

위 내용을 종합적으로 판단한다면 저는 개인적으로 JavaDoc을 선호합니다. 이유는 XMLDoc은 선언부에 주석을 달아야 하기 때문에 구현부를 전체적으로 살펴볼때 JavaDoc의 주석 형식이 더 유용할 것으로 판단됩니다.

(또는 2개의 방식을 번갈아가며 사용해도 좋을 것 같습니다. 선언부는 XMLDoc, 구현부는 JavaDoc)

 

여러분들도 여러분들의 환경에 맞는 방식을 선택 해보시기 바랍니다.

 

참고로 위 방법 외에도 doxygen 등과 같은 주석 문서화하는 방법이 많습니다.

그리고 JavaDoc 주석을 문서화 하는 프로그램도 많을 것입니다.

혹시 아는 주석 문서화 방법이나 문서화 프로그램이 있다면 댓글로 알려주시면 감사하겠습니다.

 

참고 링크

험프리.김현수 Delphi/C++Builder DCTD, DelphiCodeToDoc, Javadoc, XMLDoc, 주석

[VCL] 용량이 큰 JPEG 파일 다루기 - JPEG 라이브러리 조사

2019.05.23 17:05

프로젝트 중 큰 용량의 JPEG 파일을 다룰 필요가 있어, 64-bit를 지원하는 JPEG 라이브러리를 조사한 내용 공유합니다.

 

고객사에서는 카메라에서 제공하는 이미지의 해상도가 높아짐(16384 x 29300)에 따라 64-bit 애플리케이션으로 마이그레이션을 계획했고, 성공적으로 완료했습니다.

JPEG 라이브러리

그 과정 중 검토한 JPEG 라이브러리는 다음과 같습니다.

  • TJPEGImage(VCL 내장 JPEG 라이브러리)
  • libJPEG-Turbo
  • Intel IJL / IPP(IJL 64-bit 미지원, IPP 상용)

고객사의 기존 프로젝트에서는 IJL을 이용해 JPEG을 다뤘지만, IJL은 개발이 중단되었고 64-bit를 지원하지 않아 검토 대상에서 제외되었습니다.(IPP로 통합되어 상용으로 판매 중)

 

TJPEGImage

TJPEGImage는 VCL에 내장된 라이브러리로 32-bit, 64-bit를 모두 지원합니다.

별도의 라이브러리 파일(*.dll 등)을 배포할 필요가 없고, 클래스 단위로 제공되고 매우 익숙합니다.

(단, 성능이 좋지 않다는 평가를 검색을 통해 확인하였습니다. 내부적으로 libJPEG으로 구현된 것으로 알고 있습니다.)

 

libJPEG-Turbo

libJPEG-Turbo는 SIMD 명령어를 사용해 JPEG 압축과 해제를 가속화 하는 JPEG 이미지 코덱입니다.

공식 웹사이트에서는 libJPEG 보다 2~6배 이상 빠르다고 합니다.

(크롬, 리눅스, 안드로이드 등에서 libJPEG 대신 libJPEG-Turbo를 사용)

 

델파이 연동은 아래 오픈소스들을 참고했습니다.

JPEG 라이브러리 성능 테스트

테스트 대상은 JPEG 파일 크기별 3종으로 진행했습니다.

  • 작은 사이즈(1600x1200)
  • 큰 사이즈(16384x12200)
  • 매우 큰 사이즈(16384x29300)

 

32-bit와 64-bit 애플리케이션으로 진행했습니다.(32-bit 애플리케이션에서 매우 큰 사이즈는 메모리 부족으로 진행할 수 없었습니다.)

기존 라이브러리와 비교하기 위해 32-bit에서 IJL도 진행했습니다.

 

테스트 코드는 JPEG 파일을 TBitmap으로 불러오거나 반대로 저장하도록 작성했습니다.(고객사에서 픽셀단위로 이미지 프로세싱 진행)

 

참고로, 

TJPEGImage의 Performace 속성을 jpBestSpeed로 설정했습니다. jpBestQuality로 설정 시 3~4배의 성능 차이가 발생합니다.)

JPEG 품질은 모두 75로 설정 했습니다.

테스트 환경

  • 개발도구 : 델파이 10.3.1
  • OS : 윈도우 10 64bit(MacOS의 VM위에서 운용)
  • 메모리 : 8GB

테스트 결과

JPEG 불러오기(Load)

Load 과정에서는 예상외로, TJPEGImage의 성능이 좋다는 결과를 확인했습니다.

 

32-bit 큰 이미지의 경우 libJPEG-Turbo 대비 40%(2028 : 1137) 성능향상을 확인 했습니다.

IJL과 libJPEG-Turbo은 약 10%의 성능차이를 확인할 수 있습니다.

 

64-bit 환경에서도 TJPEGImage가 libJPET-Turbo 대비 큰 이미지의 경우 30%, 매우 큰 이미지의 경우 약 17% 가량 성능이 좋은 것으로 확인했습니다.

 

JPEG 저장(Save)

저장하는 과정은 libJPEG-Turbo가 TJPEGImage 보다 속도가 빨랐습니다.

 

특히 32-bit의 큰 이미지의 경우, 유독 TJPEGImage의 성능이 매우 좋지 않은 결과가 나왔습니다.(libJPEG-Turbo 대비 약 5배의 시간 소요)

TJPEGImage의 내부 로직을 살펴본 결과 이미지의 행(Row)의 메모리를 한번에 복사하는 과정에서 시간을 많이 소요했습니다.(해결방법은 찾지 못했습니다.)

 

64-bit에서 저장은 libJPEG-Turbo가 TJPEGImage 대비 20~30% 속도가 빨랐습니다.

 

총평

JPEG 불러오기에서는 TJPEGImage가 JPEG 저장에서는 libJPEG-Turbo가 앞선 성능을 확인할 수 있었습니다.

 

문제는 32-bit 큰 이미지 저장 시 TJPEGImage가 매우 좋지 않은 성능을 보여, 최종 선택은 libJPEG-Turbo로 진행했습니다.

해당 이슈만 없다면, TJPEGImage도 좋은 선택일 것 같습니다.

 

만약, JPEG을 빠르게 다룰 필요가 있다면, 위 테스트 내용과 첨부된 테스트 코드를 이용해 여러분 환경에 맞도록 테스트 진행 후 선정해 보시기 바랍니다.

 

테스트 코드

JPEGPerformanceTest.zip
2.44MB

 

험프리.김현수 Delphi/C++Builder Delphi, JPEG, libJPEG-Turbo, TJpegImage

델파이 코드 작성 규칙

2019.01.30 13:37

데브기어에서 진행 중인 프로젝트 과정에서 사용 중인 코드작성 규칙을 공유합니다.

https://docs.google.com/document/d/1eYWWv_YJRl-FYw3FkcIaBRSzaHsL0V-zRjA2rzJsPZM



험프리.김현수 Delphi/C++Builder

이더넷 어댑터 정보((MacAddress, IP 등) 목록 알아오기

2019.01.23 16:08

윈도우에 설치된 네트워크(이더넷 어댑터) 정보를 알아오는 방법입니다.(10.3 리오에서 구현했습니다.)


uses 절에 Winapi.IPTypes, Winapi.IPHlpAPi 추가해야 합니다.

var
  I: integer;
  NumInterfaces: DWORD;
  AdapterInfo: array of TIpAdapterInfo;  // uses Winapi.IpTypes
  OutBufLen: ULONG;
begin
  GetNumberOfInterfaces(NumInterfaces); // uses Winapi.IpHlpApi
  SetLength(AdapterInfo, NumInterfaces);
  OutBufLen := NumInterfaces * SizeOf(TIpAdapterInfo);
  GetAdaptersInfo(@AdapterInfo[0], OutBufLen);

  Memo1.Lines.Clear;
  for I := 0 to NumInterfaces - 1 do begin
    if AdapterInfo[I].Description = '' then
      Continue;
    Memo1.Lines.Add(AdapterInfo[I].Description);
    Memo1.Lines.Add(AdapterInfo[I].IpAddressList.IpAddress.S);
    Memo1.Lines.Add(Format('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x',
      [AdapterInfo[I].Address[0], AdapterInfo[I].Address[1],
       AdapterInfo[I].Address[2], AdapterInfo[I].Address[3],
       AdapterInfo[I].Address[4], AdapterInfo[I].Address[5]]));
  end;

기타 정보도 TIpAdapterInfo 구조체를 통해 알아올 수 있습니다.


메모에 출력된 결과 화면


참고


험프리.김현수 Delphi/C++Builder

[튜토리얼] 메일 전송(IdSMTP 이용)

2017.11.22 14:27

IdSMTP, IdMessage를 이용 메일 전송 예제


참고코드

procedure TForm2.Button1Click(Sender: TObject);
begin
  SMTP.Host := ''; // host address
  SMTP.Port := 25;

  MailMessage.From.Address := ''; // From email address
  MailMessage.Recipients.EMailAddresses := Edit2.Text;//'hskim@embarcadero.kr';

  MailMessage.Subject := Edit1.Text;
  MailMessage.Body.Text := Memo1.Lines.Text;
  MailMessage.CharSet := 'UTF-8';
  SMTP.Connect;
  SMTP.Send(MailMessage);
  if SMTP.Connected then
    SMTP.Disconnect;

  ShowMessage('');
end;

샘플 프로젝트

SendMail.zip


문단제목




험프리.김현수 Delphi/C++Builder

  1. 파일 첨부
    // uses IdAttachmentFile;
    MailMessage.MessageParts.Clear;
    TIdAttachmentFile.Create(MailMessage.MessageParts, Filename);

  2. 감사합니다 ~~~

[튜토리얼] FTP 업로드(TIdFTP 이용)

2017.11.22 14:24

IdFTP를 이용 로컬 파일을 서버로 업로드하는 예제

  • 로컬파일 선택
  • 업로드 시 프로그레스바로 진행률 표시

참고 코드

procedure TForm2.Button1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
    Edit1.Text := OpenDialog1.FileName;
end;

procedure TForm2.Button2Click(Sender: TObject);
var
  LocalPath, RemotePath: string;
begin
  LocalPath := Edit1.Text;
  RemotePath := 'test/' + ExtractFileName(LocalPath);

  IdFTP1.Host := 'hjf.pe.kr';
  IdFTP1.Port := 21;
  IdFTP1.Passive := True;
  IdFTP1.Username := '';  // FTP user
  IdFTP1.Password := '';  // FTP password
  IdFTP1.Connect;

  IdFTP1.Put(LocalPath, RemotePath);

  IdFTP1.Disconnect;
end;

procedure TForm2.IdFTP1Work(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCount: Int64);
begin
  ProgressBar1.Position := AWorkCount;
end;

procedure TForm2.IdFTP1WorkBegin(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCountMax: Int64);
begin
  ProgressBar1.Max := AWorkCountMax;
end;

샘플 프로젝트

IdFTPUpload.zip


문단제목





험프리.김현수 Delphi/C++Builder

  1. Blog Icon
    SquareRoot

    Put으로 파일 전송할 경우 ftp에서 내려 받았을때 파일이 깨지는데 어떡게 해야될까요.

    zip 파일 업로드 해봤는데 받아보니 손상된 파일이라네요.

안면인식(Face Detection) 라이브러리(안드로이드, iOS)

2017.10.30 15:02

델파이 개발 그룹인 grijjy 팀(블로그: https://blog.grijjy.com/)에서 안면인식(Face Detection) 라이브러리를 공개했습니다.


이 라이브러리리는 안드로이드와 iOS에 내장된 사진에서 얼굴을 감지하는 기능을 이용해, 하나의 라이브러리로 제공합니다.


안면인식 기술 개발이 필요하거나, 여러 플랫폼 기능을 하나의 라이브러리로 개발하고자 하는 경우 참고하면 아주 좋습니다.


안면인식(안드로이드, iOS)

  • https://blog.grijjy.com/2017/09/11/face-detection-on-android-and-ios/


험프리.김현수 Delphi/C++Builder

TTS(Text-to-Speech) 라이브러리(윈도우, 맥OS, iOS, 안드로이드)

2017.10.30 14:52

델파이 개발 그룹인 grijjy 팀(블로그: https://blog.grijjy.com/)에서 문자를 읽어주는 TTS(Text-to-speech) 라이브러리를 공개했습니다.


이 라이브러리는 윈도우, 맥OS, iOS, 안드로이드를 지원합니다.

(grijjy 팀에서 크로스 플랫폼 추상화 레이어 설계를 연습하기 위해 제작했으며, 각 플랫폼 API TTS 기능을 하나의 라이브러리(컴포넌트)로 제공합니다.)


해당 기능이 필요하거나, 공통된 여러 플랫폼의 API를 하나의 라이브러리(컴포넌트)로 제작하는 방법을 참고하면 아주 좋겠습니다.


Cross Platform Text-to-Speech

참고




험프리.김현수 Delphi/C++Builder

델파이로 빅데이터 데이터베이스 연동하기(Cassandra, Couchbase, MongoDB)

2017.10.30 14:32

델파이 개발 그룹인 grijjy 팀(블로그: https://blog.grijjy.com/)에서 빅데이터 데이터베이스에 직접 연동해 작업할 수 있는 델파이 라이브러리를 오픈소스로 공개하였습니다.


카산드라(Cassandra), 카우치베이스(Couchbase), 몽고DB(MongoDB) 총 3개의 빅데이터 데이터베이스 접근용 라이브러리이며, 해당 글에서는 친절하게 설치방법과 샘플 코드등을 자세히 설명합니다.


빅데이터 연동에 이슈가 있거나 관심이 있는 분들에게 큰 도움이 될 것으로 보입니다.

자세한 내용은 아래 링크를 통해 (영문으로)자세히 볼수 있습니다.


참고로, 몽고DB의 경우 델파이에 기본 내장된 FireDAC을 이용해 직접 접속할 수도 있습니다.

(하단에 관련 링크를 추가합니다.)


카산드라(Cassandra)

카산드라는 구글의 BigTable 컬럼 기반의 데이타 모델과 FaceBook에서 만든 Dynamo의 분산 모델을 기반으로 하여 제작되어 Facebook에 의해 2008년에 아파치 오픈소스로 공개된 분산 데이타 베이스 입니다. 
출처: http://bcho.tistory.com/440 [조대협의 블로그]

카우치베이스(Couchbase)

카우치베이스 서버(Couchbase Server)는 유연한 JSON 모델로 고정 데이터베이스 스키마의 제약 없이 쉽게 애플리케이션을 수정할 수 있으며, submilisecond (1/1000 ms 이하)의 초고속 데이터 입출력 처리의 높은 성능을 보장합니다. 또한, 간편한 스케일 아웃(scale-out)으로 다운타임 없이 시스템 구성 변경 및 확장을 지원합니다.

몽고DB(MongoDB)

몽고DB(MongoDB←HUMONGOUS)는 크로스 플랫폼 도큐먼트 지향 데이터베이스 시스템이다. NoSQL 데이터베이스로 분류되는 몽고DB는 JSON과 같은 동적 스키마형 문서들(몽고DB는 이러한 포맷을 BSON이라 부름)을 선호함에 따라 전통적인 테이블 기반 관계형 데이터베이스 구조의 사용을 삼간다. 이로써 특정한 종류의 애플리케이션을 더 쉽고 더 빠르게 데이터 통합을 가능케 한다.


참고로, 

몽고DB는 델파이에 기본 내장된 FireDAC을 통해 직접 연동할 수 있습니다.


험프리.김현수 Delphi/C++Builder

[REST API] 다음 Kakao > 로컬 > 주소검색 연동하기

2017.09.18 15:06

다음 등의 포털 사에서는 자사 데이터 일부를 Open API로 공개하고 있습니다.

특히 지도나 주소, 검색 등은 직접 데이터를 수집하는 것보다 포털의 데이터를 활용하는 것이 개발 및 유지보수에 유리할 수 있습니다.


오늘은 데브기어 테크게시판을 통해 다음 카카오의 주소검색 API 연동을 문의주셔서 해당 내용을 공유합니다.


아래 샘플을 REST API를 이용해 카카오 주소 검색 Open API와 연동하는 내용입니다.

(카카오 Open API의 대부분은 REST API를 제공합니다. )


해당 내용을 잘 익혀서 다양한 Open API를 여러분의 앱에서 활용하실 수 있습니다.


카카오 개발자 > 로컬 : https://developers.kakao.com/docs/restapi/local


카카오 Open API를 연동하기 위해서는 앱을 등록하고, 앱 키를 받아야 합니다.(해당 내용의 설명은 생략합니다.)

카카오 개발자 > 내 애플리케이션 : https://developers.kakao.com/apps


위 링크를 참고해 개발했으며, 제일 문제가 됐던 부분은 HTTP 해더에 Authorization 값을 추가하는 부분입니다.


연동한 결과는 아래와 같습니다.


주요 코드는 아래와 같습니다.

uses
  REST.TYpes;

const
  API_KEY = '';
{
  https://developers.kakao.com/ 등록 > 앱 생성 > 앱키(REST API 키)를 위(API_KEY)에 입력
}

procedure TForm2.Button1Click(Sender: TObject);
begin
  RESTRequest1.Params.ParameterByName('query').Value := Edit1.Text;

  RESTRequest1.Execute;
end;

procedure TForm2.FormCreate(Sender: TObject);
var
  Param: TRESTRequestParameter;
begin
  RESTClient1.BaseURL := 'https://dapi.kakao.com';
  RESTClient1.Accept := 'application/json, text/plain; q=0.9, text/html;q=0.8,';
  RESTClient1.AcceptCharset := 'UTF-8, *;q=0.8';

  RESTRequest1.Resource := 'v2/local/search/address.json?query={query}';
  Param := RESTRequest1.Params.AddHeader('Authorization', 'KakaoAK ' + API_KEY);
  Param.Options := [TRESTRequestParameterOption.poDoNotEncode];

  RESTResponseDataSetAdapter1.RootElement := 'documents';
end;

샘플 프로젝트

KakaoLocalLocation.zip


문단제목



험프리.김현수 Delphi/C++Builder

프로세스 메모리 사용량 로그 기록 - 성능 모니터 이용

2017.05.25 11:31

개발한 프로세스에서 메모리 누수(Leak)이 발생된다 예상되면, 메모리 사용량 추적을 통해 메모리 누수 여부를 검증해야 합니다. 성능 모니터를 이용하면 프로세스의 메모리 사용량을 추적 및 로그 기록할 수 있습니다.


만약, 메모리 누수가 확인된다면, 테스트용 실행파일 등으로, 메모리 누수가 발생할 수 있는 코드의 범위를 줄여가며 반복적으로 테스트 해야 합니다.

만약, 특정 기능 수행 시 메모리 누수가 의심된다면 특정 기능을 반복적으로 실행할 수 있는 테스트 프로그램을 만들어 점검할 코드의 범위를 줄여가며 추적하기 바랍니다.


델파이로 개발된 프로젝트라면 메모리 누수 보고 기능을 켜서 메모리 누수 여부를 확인할 수 있습니다.


프로세스 메모리 사용량 추적

윈도우즈 성능 모니터를 이용해 프로세스가 사용 중인 메모리 사용량을 로그파일로 기록하는 방법을 소개합니다.


모니터링 대상 프로세스 실행

메모리 사용량 추적할 프로세스를 실행합니다. 저는 MemoryLeakTest.exe라는 실행파일을 만들어 실행했습니다.


성능 모니터에서 프로세스 메모리 사용량 기록

성능 모니터를 실행하고, 성능 > 데이터 수집기 집합 > 사용자 정의 메뉴를 선택합니다.


목록 창에서 우측 마우스를 누르고, 새로 만들기 > 데이터 수집기 집합 메뉴를 선택합니다.


이름을 지정하고, 수동으로 만들기(고급) 항목 선택 합니다.


성능 카운터 항목을 선택합니다.


[추가] 버튼을 누릅니다.

데이터 수집 가격을 지정합니다.


사용 가능한 카운터에서 Process 항목을 펼치고, Working Set 항목을 선택합니다.

인스턴스로는 추적할 프로세스를 선택합니다.(현재 실행된 프로세스 목록이 표시됩니다.)

[추가] 버튼을 눌러 추가합니다.

(Handle Count, Private Bytes 등 추적하고 싶은 카운터들도 함께 선택해도 됩니다.)

(주요 카운터에 대한 설명은 하단 참고링크 참고)


데이터 저장 경로를 지정합니다.



작업을 마칩니다.


추가한 데이터 수집기 집합의 속성에 들어가 로그 형식을 "쉼표로 구분"으로 변경합니다.(로그를 엑셀로 활용할 수 있습니다.)


성능 모니터링을 시작합니다.(데이터 수집기 집합의 속성에서 예약등을 이용해 자동 시작할 수 있습니다.)


로그파일 확인

지정한 경로에 csv 파일이 생성됩니다.


csv 파일을 엑셀로 열고, 데이터를 분석하거나, 차트를 만들어 시각적으로 메모리 사용량(Working Set) 추이를 관찰 할 수 있습니다.


참고링크


험프리.김현수 Delphi/C++Builder

[REST API][실습] 데이터셋 기반 REST API 개발하기

2017.05.24 13:31

이 글에서는 데이터셋 기반으로 일괄 데이터 처리하는 REST API 엔드포인트를 구현하고, 연동하는 내용을 설명합니다.


데이터셋 기반 REST API

데이터셋(TDataSet)은 데이터들의 집합으로, FireDAC의 데이터 셋(TFDDataSet)은 데이터셋의 내용을 JSON 포맷으로 저장하고, 불러오는 기능을 제공합니다. 


이 기능을 활용해 REST API의 JSON 포맷을 손쉽게 개발할 수 있습니다.


데이터셋 기반 REST API의 특징(장/단점)은 다음과 같습니다.

1) (장점) 매우 신속하고, 손쉽게 REST API 서버, 클라이언트를 개발할 수 있습니다.

데이터를 JSON 포맷으로 변환하는 코드가 대단히 짧아 집니다.


2) (단점)JSON 포맷을 직접 설정할 수 없습니다.

FireDAC의 JSON 저장 기능을 이용하기 때문에 FireDAC의 JSON 포맷을 그대로 사용합니다.

필요한 항목을 추가, 변경하기 쉽지 않습니다.

또한, REST 아키텍처의 규칙과 일부 다르게 구현해야 합니다.(GET과 POST 메소드만 사용합니다.)

(개인적으로 델파이 클라이언트-서버 환경으로 개발하는 경우 활용하는 것이 좋다는 의견입니다.)


이 글에 앞서 다음 내용을 선행학습하시기 바랍니다.


이 글에서는 다음 내용을 다룹니다.

  • [이론] 데이터셋과 JSON
    • JSON 포맷 저장/불러오기
    • CachedUpdates와 TFDSchemaAdapter
  • [실습] 데이터셋 기반 REST API 개발하기
    • 데이터셋 기반 REST API 서버 개발하기
    • 데이터셋 기반 REST API 클라이언트 개발하기

이 글의 실습에서는 도서대여 프로그램 만들기에서 사용한 데이터베이스를 사용합니다. 다음 링크에서 데이터베이스 구조를 확인하고, DB 파일을 다운로드 받으시기 바랍니다.

데이터셋과 JSON

FireDAC의 데이터셋(TFDDataSet)은 JSON 포맷으로 데이터 저장하고, JSON 포맷의 데이터를 불러오는 기능을 제공합니다.


JSON 포맷 저장/불러오기

FireDAC 데이터셋(TFDDataSet)은 SaveToStream, LoadFromStream 메소드를 이용해 데이터를 저장하고 불러오는 기능을 제공합니다. 파라메터로 스트림(TStream)과 데이터포맷을 지정할 수 있으며, 데이터포맷으로는 XML, JSON, Binary 중 선택할 수 있습니다.


아래와 같은 코드로 데이터셋의 데이터를 JSON 포맷으로 저장하고, 불러올 수 있습니다.

var
  Stream: TMemoryStream;
begin
  Stream := TMemoryStream.Create;
  try
    FDQuery1.SaveToStream(Stream, TFDStorageFormat.sfJSON);

    Stream.Position := 0;
    FDQuery1.LoadFromStream(Stream, TFDStorageFormat.sfJSON);
    FDQuery1.ApplyUpdates;
  finally
    Stream.Free;
  end;

단, 데이터를 로드(LoadFromStream)의 경우 데이터셋의 CachedUpdates 속성이 True로 설정되어 있어야 합니다.


참고: 위 코드를 사용하기 위해서는 TFDStanStorageJSONLink 컴포넌트를 화면(또는 데이터모듈)에 올려놓거나, "FireDAC.Stan.StorageJSON" 유닛을 유즈절에 추가해야 합니다.


알아야 하는 주요 컴포넌트, 속성

캐쉬 업데이트 속성(CachedUpdates)

데이터셋의 CachedUpdates 속성을 사용하면 데이터셋의 Post 메소드 호출 시 데이터셋의 캐쉬(메모리)에 임시로 저장되고, ApplyUpdates 메소드 호출 시 캐쉬 데이터가 실제 DBMS에 변경된 데이터가 적용됩니다. 즉, 캐쉬 기반으로 데이터 조작 후 일괄 적용할 수 있습니다.


스키마어댑터 컴포넌트(TFDSchemaAdapter)

스키마어댑터(TFDSchemaAdapter) 컴포넌트는 중앙 캐쉬 업데이트를 지원합니다. 스키마어댑터 컴포넌트(TFDSchemaAdapter) 추가 후 데이터셋의 SchemaAdapter 속성에 할당하면, 스키마어댑터 컴포넌트를 통해 여러 데이터셋의 데이터 변경을 순차적으로 처리할 수 있습니다.


스키마어댑터 컴포넌트는 Open, Close, SaveToStream, LoadFromStream, ApplyUpdates 등의 메소드를 제공합니다. 이 메소드를 호출하면 스키마어댑터 컴포넌트와 연결된 여러개의 데이터셋의 데이터를 열기/닫기, 저장/불러오기, 일괄적용 할 수 있습니다.


메모리 기반 데이터셋 컴포넌트(TFDMemTable)

메모리 상에서 데이터 처리를 지원합니다. 이번 실습의 클라이언트는 메모리 기반 데이터셋 컴포넌트에 서버에서 받은 데이터를 보관하고, 조작(추가, 수정, 삭제) 후 변경된 내용을 서버에 저장 요청합니다.


EMS FireDAC 클라이언트 컴포넌트(TEMSFireDACClient)

EMS 서버에 데이터셋 기반 REST End-point와 연동하는 컴포넌트입니다. EMS 프로바이더, 리소스, 스키마어댑터 속성을 제공합니다.

  • EMS 프로바이더 : 접속할 EMS 서버 정보 설정
  • 리소스 : 연결할 리소스 설정
  • 스키마어댑터 : 데이터를 처리 위임
GetDatas, PostUpdates 메소드를 제공합니다.
  • GetDatas : 서버에서 데이터를 요청합니다.
  • PostUpdates : 클라이언트에서 변경된 데이터를 서버에 저장 요청합니다.


[실습] 데이터셋 기반 REST API 개발하기

이 실습에서는 도서대여 프로그램의 도서정보와 사용자정보를 제공하는 REST API 서버를 개발하고, REST API 서버에서 받은 도서 정보를 편집 후 저장하는 클라이언트 프로그램 개발을 실습합니다.


REST API 자료 구조는 FireDAC 데이터셋의 JSON 포맷으로 저장 기능을 사용합니다.

데이터셋 기반 REST API 서버 개발하기

이 실습에서는 "도서대여 프로그램 만들기"의 도서(BOOK)와 사용자(USERS) 테이블 데이터를 제공하는 REST API 서버 개발을 실습합니다.


다음 순서로 진행합니다.

1) EMS 패키지 프로젝트를 생성합니다.

2) 데이터 제공하기 위해 컴포넌트 추가 및 설정합니다.

3) GET 메소드를 구현해 데이터 제공 기능을 개발합니다.

4) POST 메소드를 구현해 데이터 저장 기능을 개발합니다.


EMS 패키지 프로젝트 생성

EMS 패키지 프로젝트를 생성(File > New > Other > Delphi Projects > EMS > EMS Package) 합니다.


리소스 이름을 "datasets"로 지정합니다.



엔드포인트는 Get과 Post를 선택합니다.


프로젝트와 소스코드를 저장합니다.


데이터 제공을 위한 컴포넌트 추가 및 설정


아래 목록을 참고해 데이터 연결을 위한 컴포넌트 추가 및 설정합니다.

  • conBookRental: TFDConnection
    • 도서대여 프로그램 데이터베이스 연결
  • scmAdtBookRental: TFDSchemaAdapter
  • qryBook: TFDQuery
    • CachedUpdates = True
    • Connection = conBookRental
    • SQL = "SELECT BOOK_SEQ, BOOK_TITLE, BOOK_AUTHOR, BOOK_ISBN, BOOK_PRICE, BOOK_LINK FROM BOOK"
    • SchemaAdapter = scmAdtBookRental
    • UpdateOptions.AutoIncFields = BOOK_SEQ
  • qryUser: TFDQuery
    • CachedUpdates = True
    • Connection = conBookRental
    • SQL = "SELECT USER_SEQ, USER_NAME, USER_BIRTH, USER_SEX, USER_PHONE, USER_MAIL FROM USERS"
    • SchemaAdapter = scmAdtBookRental
    • UpdateOptions.AutoIncFields = USER_SEQ
  • FDStanStroageJSONLink1: TFDStanStorageJSONLink


엔드포인트 추가

기본으로 생성한 엔드포인트에는 전체 데이터를 제공, 저장하는 용도로 사용합니다.

"/books/" 엔드포인트를 추가해 도서 정보만 제공, 저장하는 과정도 소개합니다.(이 엔드포인트는 클라이언트 실습에서 사용하지 않습니다.)

published procedure Get(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); procedure Post(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); [ResourceSuffix('/books/')] procedure GetItemBooks(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); [ResourceSuffix('/books/')] procedure PostBooks(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); end;


Get / GetItemBooks

procedure TDatasetResource1.Get(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
var
  Stream: TMemoryStream;
begin
  Stream := TMemoryStream.Create;
  try
    scmAdtBookRental.SaveToStream(Stream, TFDStorageFormat.sfJSON);

    AResponse.Body.SetStream(Stream, 'application/json', True);
  except
    Stream.DisposeOf;
  end;
end;

procedure TDatasetResource1.GetItemBooks(const AContext: TEndpointContext;
  const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
var
  Stream: TMemoryStream;
begin
  Stream := TMemoryStream.Create;
  try
    qryBook.SaveToStream(Stream, TFDStorageFormat.sfJSON);

    AResponse.Body.SetStream(Stream, 'application/json', True);
  except
    Stream.DisposeOf;
  end;
end;

Get과 GetItemBooks 메소드는 데이터셋의 데이터를 스트림으로 JSON 포맷으로 저장 후 응답합니다.


Get은 스키마 어댑터와 연결된 데이터셋 들의 데이터(도서, 사용자)를 일괄 제공합니다.

GetItemBooks는 도서 쿼리(데이터셋)의 데이터만 제공합니다.


Post / PostBooks

procedure TDatasetResource1.Post(const AContext: TEndpointContext;
  const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
var
  Stream: TStream;
begin
  if not SameText(ARequest.Body.ContentType, 'application/json') then
    AResponse.RaiseBadRequest('content type');
  if not ARequest.Body.TryGetStream(Stream) then
    AResponse.RaiseBadRequest('Invailed stream');

  Stream.Position := 0;
  scmAdtBookRental.LoadFromStream(Stream, TFDStorageFormat.sfJSON);
  scmAdtBookRental.ApplyUpdates;
end;

procedure TDatasetResource1.PostBooks(const AContext: TEndpointContext;
  const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
var
  Stream: TStream;
begin
  if not SameText(ARequest.Body.ContentType, 'application/json') then
    AResponse.RaiseBadRequest('content type');
  if not ARequest.Body.TryGetStream(Stream) then
    AResponse.RaiseBadRequest('Invailed stream');

  Stream.Position := 0;
  qryBook.LoadFromStream(Stream, TFDStorageFormat.sfJSON);
  qryBook.ApplyUpdates;
end;

Post와 PostBooks 메소드는 요청 바디의 컨텐트타입을 확인하고, 바디의 컨텐트를 스트림으로 가져옵니다.(TryGetStream) 


Post 메소드는 스키마 어댑터로 데이터가 담긴 스트림의 데이터를 읽고, DB에 적용(ApplyUpdates)합니다.

PostBooks 메소드는 도서 쿼리에서 데이터가 담긴 스트림의 데이터를 읽고, DB에 적용(ApplyUpdates)합니다.


데이터셋 기반 REST API 클라이언트 개발하기

이 실습에서는 위에서 개발한 데이터셋 기반 REST API 서버와 연결해 데이터를 불러오고, 데이터 변경(추가, 수정, 삭제) 후 서버에 저장 요청합니다.


멀티-디바이스 애플리케이션(파이어몽키) 프로젝트로 진행합니다.(VCL 폼 애플리케이션에서도 같은 방법으로 개발할 수 있습니다.)


다음 순서로 진행합니다.

1) 프로젝트 생성 및 화면 개발

2) 데이터 연결 기능 개발

3) UI 컨트롤과 데이터 연결

4) 각 버튼 이벤트 개발


프로젝트 생성 및 화면 개발

멀티-디바이스 애플리케이션 프로젝트를 생성(File > New > Multi-Device Application)합니다.

(앞에서 만든 REST API 서버와 프로젝트 그룹으로 묶어 놓으면 편리합니다. Project Group > Add New Project)


아래 그림을 참고해 화면을 개발합니다.


에디트(TEdit)의 이름을 각각 "edtTitle, edtAuthor, edtISBN, edtPrice, edtLink"로 변경합니다.

버튼(TButton)의 이름을 각각 "btnSearch, btnDelete, btnAppend, btnSave, btnCancel"로 변경합니다.


데이터 연결 기능 구현

프로젝트에 데이터 모듈 추가 후 EMS 서버와 연결할 컴포넌트를 추가하겠습니다.


프로젝트에 데이터 모듈을 추가(File > New > Other > Delphi Files > Data Module)합니다.

데이터 모듈의 이름을 변경하고, 파일을 저장합니다.(저는 이름은 dmData, 파일이름은 DataAccessModule.pas로 했습니다.)


아래 그림과 표를 참고해 컴포넌트를 추가합니다.


 상위 오브젝트

 오브젝트

 속성

 값(또는 설명)

 dmData

 (데이터 모듈)

 EMSProvider1

 URLHost

 localhost(EMS 서버 주소)

 URLPort 8080

 FDSchemaAdapter1

 

 

 EMSFireDACClient1 Provider

 EMSProvider1

 Resource

 datasets

 SchemaAdapter FDSchemaAdapter1

 tblAdtBook

 (TFDTableAdapter)

 DatSTableName

 qryBook

 Name

 tblAdtBook

 SchemaAdapter FDSchemaAdapter1

 qryBook
 (TFDMemTable)

 Adapter

 tblAdtBook

 CachedUpdates True

 tblAdtUser

 (TFDTableAdapter)

 DatSTableName

 qryUser

 Name tblAdtUser
 SchemaAdapter FDSchemaAdapter1

 qryUser

 (TFDMemTable)

 Adapter

 tblAdtUser

 CachedUpdates

 True

 FDGUIxWaitCursor1

  


UI 컨트롤과 데이터 연결

라이브 바인딩 기술을 이용해 UI 컨트롤에 데이터를 표현합니다.


메모리 테이블에 필드 정보 추가하기

에디트(TEdit) 등의 UI 컨트롤과 데이터 연결 시 데이터셋의 필드 정보를 이용합니다. 메모리 테이블의 경우 자체적으로 필드 정보를 생성할 수 없어 아래 절차를 통해 메모리 테이블에 필드 정보를 추가합니다.


1) REST API 서버 프로젝트를 열고, 쿼리 컴포넌트(TFDQuery)의 Field Editor 메뉴를 선택합니다.


2) Field Editor 창의 팝업 메뉴에서 Add all fields 메뉴를 선택해 필드 정보를 추가합니다.


3) 추가된 필드 정보를 모두 선택 후 (클립보드로)복사 합니다.


4) 현재 프로젝트의 데이터 모듈로 돌아와 메모리 테이블 팝업 메뉴에서 Field Editor 메뉴를 선택합니다.


5) Field Editor 창에 붙여넣기 합니다.


위 과정을 메모리 테이블 별로 진행합니다.


라이브 바인딩으로 연결

폼 화면 유닛의 유즈(uses) 절에 데이터 모듈 유닛을 추가합니다.


폼 화면에서 라이브 바인딩 디자이너를 표시(View > Tool Windows > LiveBindings Designer)합니다.


아래 그림을 참고해 UI 컨트롤과 데이터를 연결(Linking)합니다.


버튼 기능 구현

각 버튼의 클릭 이벤트를 아래 코드를 참조해 입력합니다.

procedure TForm1.btnSearchClick(Sender: TObject);
begin
  dmData.EMSFireDACClient1.GetData;
end;

procedure TForm1.btnDeleteClick(Sender: TObject);
begin
  dmData.qryBook.Delete;
end;

procedure TForm1.btnAppendClick(Sender: TObject);
begin
  dmData.qryBook.Append;
end;

procedure TForm1.btnSaveClick(Sender: TObject);
begin
  dmData.EMSFireDACClient1.PostUpdates;
end;

procedure TForm1.btnCancelClick(Sender: TObject);
begin
  dmData.qryBook.Cancel;
end;

조회와 저장은 서버의 데이터를 다뤄야 하기 때문에 EMSFireDACClient를

추가, 삭제, 취소는 로컬의 메모리 테이블(qryBook)을 다루도록 구현했습니다.


테스트

REST API 서버와 클라이언트 구현이 완료되었습니다. 간단한(?) 작업으로 REST API 서버를 제작하고, 클라이언트에서 데이터 조회, 추가, 편집, 삭제 기능을 개발할 수 있었습니다.


테스트는 다음 단계로 진행합니다.

1) REST API 서버 실행(EMS 패키지 프로젝트를 실행합니다.)

2) REST API 클라이언트 실행

3) [조회] 버튼으로 데이터 출력

4) 데이터 추가, 수정 후 [저장] 버튼 클릭


참고/관련 자료



험프리.김현수 Delphi/C++Builder

[REST API][실습] REST API 클라이언트 개발하기(REST Client 이용)

2017.05.19 18:24

이 글에서는 델파이를 이용해 REST API 서버와 연동하는 클라이언트 기술을 실습합니다.

REST 클라이언트 라이브러리 기반으로 실습합니다.

REST API 엔드포인트 연동


이 글에서는 REST API 서버의 REST API를 분석하고, 클라이언트에 표시 및 입력데이터를 서버에 저장하는 내용을 실습 위주로 진행합니다.

이 글에서는 데이터 처리하는 내용에 집중합니다. 이 글을 참고해 여러분이 만든 멋진 화면과 REST API를 연동하는 기술을 습득하시기 바랍니다.


이 글에 앞서 다음 내용의 이해가 필요합니다. 미리 선행 학습하시기 바랍니다.


    이 글에서는 다음 내용을 다룹니다.

    • REST API 분석
    • [실습] REST API 연동
      • Get
      • GetItem
      • GetItem - 이미지 수신
      • Post / PutItem / DeleteItem
    • 추가 학습할 내용

    REST API 분석

    이 글에서는 아래 링크에서 제작한 도서정보 REST API 서버를 대상으로 분석 및 연동합니다.


    도서정보 REST API 서버에서 제공하는 엔드포인트는 아래와 같습니다. {item}에는 도서정보 아이디로 치환해야 합니다.

     엔드포인트

     역할

      데이터 포맷

     GET http://localhost:8080/books/

     도서정보 목록 조회

     응답: application/json

     GET http://localhost:8080/books/{item}/

     도서정보 상세 조회

     응답: application/json

     GET http://localhost:8080/books/{Item}/photo/

     도서정보 사진 조회

     응답: image/jpg

     POST http://localhost:8080/books/

     도서정보 생성

     요청 : application/json(Body)

     PUT http://localhost:8080/books/{item}/

     도서정보 수정

     요청 : application/json(Body)

     DELETE http://localhost:8080/books/{item}/

     도서정보 삭제 


    REST API 분석은 REST Debugger(실행: Tools > REST Debugger 메뉴)를 이용합니다.

    REST Debugger 상세정보 - http://docwiki.embarcadero.com/RADStudio/en/REST_Debugger_Tool (자동변역)

    [실습] REST API 연동

    실습에서는 도서대여 REST API 서버와 연동하는 클라이언트 프로그램을 제작합니다.


    실습을 위해 도서대여 패키지를 포함한 EMS 서버를 실행합니다.


    사전 준비사항

    프로젝트 생성

    클라이언트 프로그램은 델파이 멀티-디바이스 애플리케이션(Multi-Device Application)으로 진행합니다.


    멀티-디바이스 애플리케이션 프로젝트를 생성(File > New > Multi-Device Application)합니다. 


    프로젝트에 델파이 데이터 모듈을 추가(File > New > Other > Delphi Projects > Delphi Files > Data Module)합니다.


    프로젝트를 저장합니다.(저는 아래와 같은 이름으로 저장했지만 다른 이름으로 저장해도 됩니다.)


    데이터 모듈 이름을 "dmDataAccess"로 변경합니다. 폼 유닛(MobileForm)에서 데이터 모듈 유닛(DataAccessModule)을 사용할 수 있도록 uses 절에 추가합니다.


    화면 구성(폼 디자인)

    아래 그림을 참고해 화면을 구성합니다.

    다음을 참고해 컴포넌트 이름을 지정합니다.

    • 버튼(TButton)
      • btnLoadData : 데이터 로드
      • btnNewData :  신규
      • btnDeleteData : 삭제
      • btnSaveData : 저장
    • 에디트(TEdit)
      • edtTtile : 제목
      • edtAuthor : 저자
      • edtISBN : ISBN
      • edtPrice : 가격
      • edtLink : 관련링크
    • 메모(TMemo)
      • mmoDescription : 설명

    Get

    Get 엔드포인트를 통해 도서정보 목록을 조회합니다.

    REST API 분석

    REST Debugger에서 아래와 같이 입력합니다.

    • Request 탭
      • Method : Get
      • URL : http://localhost:8080
      • Content-type : application/json
    • Parameters 탭
      • Resource : books
    [Send Request] 버튼을 누릅니다.

    위 이미지와 같이 200 : OK 메시지가 Response 영역에 표시되야 합니다.(200이 아닌 응답 상태 코드를 수신한 경우 EMS 서버 실행여부 또는 URL 등을 확인하시기 바랍니다.)


    Response 영역의 Headers 탭과 Body탭을 통해 데이터 수신을 확인합니다.

    JSON 데이터를 확인해, JSON 배열([])로 구성된 속성을 확인해 JSON Root Element에 입력 후 [Apply] 버튼을 클릭(또는 엔터)합니다.


    Tabular Data 탭에 배열의 데이터가 테이블 형식으로 표시됩니다.


    [Copy Components] 버튼을 눌러 분석한 데이터를 클립보드로 복사합니다.(이 컴포넌트는 개발에 직접 사용합니다.)


    REST API 연동 구현

    데이터 모듈에 붙여넣기(Ctrl + V) 후 아래 그림을 참고해 이름을 변경합니다.


    각 컴포넌트의 역할과 주요 속성

    • TRESTClient - 서버 정보 설정
      • BaseURL : 서버 기본 URL
    • TRESTRequest - 요청할 정보 설정 및 요청 작업 수행
      • Client : TRESTClient 지정
      • Method : 요청 시 HTTP 메소드 종류
      • Resource : REST API 리소스 지정(URI에서 BaseURL 제외한 영역), 파라메터는 중괄호({})로 지정
      • Params : Resource에 포함된 파라메터 값 정
      • Response : 응답 객체(TRESTResponse) 지정
    • TRESTResponse - 요청의 응답 정보 보관
      • Content : 응답받은 데이터(string)
      • RootElement : 응답 데이터 중 필요한 항목 지정
    • TRESTResponseDataSetAdapter - 응답 데이터를 데이터셋으로 변환
      • Response : 변환 대상 응답데이터
      • Dataset : 변환한 데이터를 기록할 데이터 셋(TDataSet을 상속받은 메모리 테이블, TFDMemTable 또는 TClientDataSet 등)
      • RootElement : 응답 데이터 중 변환할 항목 지정
    • TFDMemTable - 메모리 테이블

    reqList 컴포넌트 팝업메뉴에서 Execute 메뉴를 눌러 연결을 확인하고 데이터를 가져옵니다.

    이 작업은 REST API 서버의 데이터를 받아 메모리테이블(TFDMemTable)에 데이터를 로드합니다. 이 데이터를 기반으로 메모리 테이블의 필드 정보를 표시하고, UI 컨트롤에 데이터를 표시합니다. 델파이에서 프로젝트를 새로 열었다면, 위 작업을 다시 시도해 데이터를 메모리 테이블에 로드해야 합니다.

    폼의 [데이터 로드] 버튼 클릭 이벤트에 아래 코드를 구현합니다.

      dmDataAccess.reqList.Execute;


    도서목록 데이터를 그리드에 표시하기 위해 라이브 바인딩 디자이너 표시(View > Tool Windows > LiveBindings Designer) 후 아래 그림을 참고해 데이터와 UI컨트롤을 바인딩 합니다.


    프로젝트를 실행하고, [데이터 로드] 버튼을 눌러 그리드에 정보가 표시되는 것을 확인합니다.

    GetItem

    GetItem 엔드포인트를 통해 도서정보 목록을 조회합니다.

    REST API 분석

    REST Debugger에서 아래와 같이 입력합니다.

    • Request 탭
      • Method : Get
      • URL : http://localhost:8080
      • Content-type : application/json
    • Parameters 탭
      • Resource : books/{item}/
      • Request parameters : item 항목에 도서정보 아이디 값 입력
    [Send Request] 버튼을 누릅니다.

    응답 데이터 확인 후 JSON Root Element에 "book" 입력 후 [Apply] 버튼을 누르고, Tabular Data 탭에서 데이터 표시를 확인합니다.

    [Copy Components] 버튼을 누릅니다.

    REST API 연동 구현

    데이터 모듈에 붙여넣기 후 아래와 같이 이름을 변경합니다.


     TRESTClient는 재사용합니다. RESTClient2 컴포넌트를 제거합니다. reqDetail.Client 항목을 RESTClient1으로 지정합니다.


    reqDetail 컴포넌트 팝업메뉴에서 Execute 메뉴를 눌러 데이터를 가져옵니다.


    폼에서 라이브 바인딩 디자이너를 표시하고, 아래 그림을 참고해 바인딩합니다.


    private 영역에 아래 변수와 메소드 추가 후 자동 완성(Shift + Ctrl + C)으로 구현부를 생성합니다.

      private
        FSelectedSeq: Integer;
        procedure RequestDetail(ASeq: Integer);
        procedure LoadPhoto(ASeq: Integer);
        procedure ClearControls;


    그리드의 OnSelChanged 이벤트(그리드 셀 변경)를 추가후 아래 코드를 구현합니다.

    procedure TForm1.Grid1SelChanged(Sender: TObject);
    var
      Seq: Integer;
    begin
      if dmDataAccess.memBookList.RecordCount = 0 then
        Exit;
    
      Seq := dmDataAccess.memBookList.FieldByName('BOOK_SEQ').AsInteger;
      RequestDetail(Seq);
    end;
    
    procedure TForm1.ClearControls;
    begin
      dmDataAccess.memBookDetail.EmptyDataSet;
      ImageControl1.Bitmap.Assign(nil);
    end;
    
    procedure TForm1.RequestDetail(ASeq: Integer);
    begin
      FSelectedSeq := ASeq;
    
      ClearControls;
    
      dmDataAccess.reqDetail.Params.ParameterByName('item').Value := ASeq.ToString;
      BindSourceDB2.DataSource.Enabled := False;
      dmDataAccess.reqDetail.ExecuteAsync(procedure
      begin
        BindSourceDB2.DataSource.Enabled := True;
      end);
    
      LoadPhoto(ASeq);
    end;
    
    procedure TForm1.LoadPhoto(ASeq: Integer);
    begin
    end;

    LoadPhoto 메소드는 아래에서 구현합니다.

    GetItem - 이미지 수신

    REST API 연동 구현

    이미지 수신, 생성, 수정, 삭제에 공통으로 사용할 컴포넌트를 데이터 모듈에 추가합니다.


    RESTRequest의 Client 항목을 RESTClient1으로 Reponse 항목을 RESTResponse로 지정합니다.


    LoadPhoto 메소드에 아래와 같이 구현합니다.
    procedure TForm1.LoadPhoto(ASeq: Integer);
    var
      Stream: TMemoryStream;
    begin
      dmDataAccess.RESTRequest.Method := TRESTRequestMethod.rmGET;
      dmDataAccess.RESTRequest.Resource := '/books/{item}/photo/';
      dmDataAccess.RESTRequest.Params.ParameterByName('item').Value := ASeq.ToString;
      dmDataAccess.RESTRequest.ExecuteAsync(procedure
        begin
          if dmDataAccess.RESTResponse.StatusCode = 404 then
            Exit;
          Stream := TMemoryStream.Create;
          try
            Stream.WriteData(dmDataAccess.RESTResponse.RawBytes, dmDataAccess.RESTResponse.ContentLength);
            ImageControl1.Bitmap.LoadFromStream(Stream);
          finally
            Stream.Free;
          end;
        end);
    
    end;
    프로젝트를 실행하고, 그리드를 변경해 상세 데이터 및 이미지 표현을 확인합니다.

    Post / PutItem / DeleteItem

    신규, 저장, 삭제 기능을 구현합니다.

    REST API 연동 구현

    데이터 모듈에서 데이터셋의 데이터를 JSON으로 반환하는 메소드를 작성합니다. 이 메소드는 Post, PutItem 엔드포인트 호출 시 사용합니다.


    데이터 모듈의 uses 절에 "System.JSON, System.JSON.Writers"을 추가합니다.


    아래 코드를 참고해, GetBookData 메소드를 정의하고, 구현합니다.

    function TdmDataAccess.GetBookData: TJSONObject;
    var
      Writer: TJsonObjectWriter;
    begin
      Writer := TJsonObjectWriter.Create(False);
      try
        Writer.WriteStartObject;  // start resource
        Writer.WritePropertyName('book');
    
        Writer.WriteStartObject;  // start item
        Writer.WritePropertyName('BOOK_TITLE');
        Writer.WriteValue(memBookDetail.FieldByName('BOOK_TITLE').AsString);
    
        Writer.WritePropertyName('BOOK_ISBN');
        Writer.WriteValue(memBookDetail.FieldByName('BOOK_ISBN').AsString);
    
        Writer.WritePropertyName('BOOK_AUTHOR');
        Writer.WriteValue(memBookDetail.FieldByName('BOOK_AUTHOR').AsString);
    
        Writer.WritePropertyName('BOOK_PRICE');
        Writer.WriteValue(memBookDetail.FieldByName('BOOK_PRICE').AsString);
    
        Writer.WritePropertyName('BOOK_LINK');
        Writer.WriteValue(memBookDetail.FieldByName('BOOK_LINK').AsString);
    
        Writer.WritePropertyName('BOOK_DESCRIPTION');
        Writer.WriteValue(memBookDetail.FieldByName('BOOK_DESCRIPTION').AsString);
    
        Writer.WriteEndObject;  // end item
        Writer.WriteEndObject;  // end resource
    
        Result := Writer.JSON as TJSONObject;
      finally
        Writer.Free;
      end;
    end;

    [신규], [삭제], [저장] 버튼의 이벤트에 아래 코드를 작성합니다.

    procedure TForm1.btnNewDataClick(Sender: TObject);
    begin
      FSelectedSeq := -1;
      ClearControls;
    end;
    
    procedure TForm1.btnSaveDataClick(Sender: TObject);
    var
      Data: TJSONObject;
    begin
      if FSelectedSeq = -1 then
      begin
        dmDataAccess.RESTRequest.Method := TRESTRequestMethod.rmPOST;
        dmDataAccess.RESTRequest.Resource := '/books/';
      end
      else
      begin
        dmDataAccess.RESTRequest.Method := TRESTRequestMethod.rmPUT;
        dmDataAccess.RESTRequest.Resource := '/books/{item}/';
        dmDataAccess.RESTRequest.Params.ParameterByName('item').Value := FSelectedSeq.ToString;
      end;
      dmDataAccess.RESTRequest.ClearBody;
      Data := dmDataAccess.GetBookData;
      dmDataAccess.RESTRequest.Body.Add(Data);
      dmDataAccess.RESTRequest.Execute;
    
      ShowMessage('저장');
    end;
    
    procedure TForm1.btnDeleteDataClick(Sender: TObject);
    begin
      dmDataAccess.RESTRequest.Method := TRESTRequestMethod.rmDELETE;
      dmDataAccess.RESTRequest.Resource := '/books/{item}/';
      dmDataAccess.RESTRequest.Params.ParameterByName('item').Value := FSelectedSeq.ToString;
      dmDataAccess.RESTRequest.Execute;
    
      ShowMessage('삭제');
    end;

    위 코드와 같이 단순한 요청, 응답의 경우 컴포넌트를 재사용 하는 것도 좋은 방법입니다.



    완성된 프로젝트 파일

    RESTAPI_Client.zip


    험프리.김현수 Delphi/C++Builder

    1. Blog Icon

      비밀댓글입니다

    [REST API][실습] REST API 서버 개발하기(엔드포인트 구현, RAD 서버 이용)

    2017.05.17 11:31

    이 글에서는 델파이를 이용해 REST API 엔드포인트를 제공하는 서버 제작 기술을 학습합니다.

    RAD 서버의 EMS 패키지 프로젝트로 진행합니다.

    REST API 엔드포인트

    리소스에 HTTP 메소드 별로 구현해 놓은 것을 REST API 엔드포인트라 합니다.


    REST는 GET, POST, PUT, DELETE 4개의 HTTP 메소드 지원을 원칙으로하며, 그 중 지원할 HTTP 메소드를 지정 및 구현해 REST API를 제공합니다. 즉 리소스에 따라 필요한 HTTP 메소드에 한해 엔드포인트를 제공할 수 있습니다.


    이 글에서는 RAD 서버를 이용해 리소스를 생성하고, 엔드포인트를 작성하는 실습을 진행합니다.

    실습의 주제는 도서정보를 제공하는 REST API를 개발합니다.


    이 글에 앞서 다음 내용을 이해하고 있어야 합니다. 미리 선행 학습하시기 바랍니다.


    이 글에서는 다음 내용을 다룹니다.

    • EMS 패키지 프로젝트 시작하기
    • [실습] REST API 엔드포인트 개발하기
      • Get / GetItem
        • REST Debugger 소개
      • Post / PutItem / DeleteItem
      • GetItem - 이미지 제공
    • 추가 학습할 내용


    이 글의 실습에서는 "[따라하기] 도서대여 프로그램 만들기"에서 사용한 데이터베이스(Interbase)를 사용합니다.


    EMS 패키지 프로젝트 시작하기

    EMS 패키지 프로젝트를 이용해 REST API 리소스와 엔드포인트를 개발할 수 있습니다.


    EMS 패키지를 생성하고, 실행하는 내용은 다음 링크를 통해 선행 학습하시기 바랍니다.

    EMS 패키지 프로젝트 생성

    "books" 이름으로 리소스 이름을 지정하고 파일유형으로 Data Module을 선택 합니다.


    엔드포인트를 모두 선택 합니다.


    프로젝트를 생성하면 아래와 같은 코드가 자동 생성됩니다.


    [ResourceName('books')]

    리소스 이름을 지정하는 특성 구문으로, 아래의 클래스(TBooksResource1)의 리소스 이름을 지정합니다.

    이 이름은 URI에 사용되며, URI(http://localhost:8080/books/) 요청 시 리소스 이름이 지정된 클래스의 엔드포인트 프로시저를 실행합니다. 이 이름은 코드 상에서 수정할 수 있습니다.


    [ResourceSuffix('{item}')]

    리소스 뒤에 붙는 리소스접미사를 정의하는 특성(Attribute) 구문입니다.

    URI(http://localhost:8080/books/100/)에서 리소스 이름 뒤의 영역을 지정합니다.

    중괄호({..})로 정의된 항목은 파라메터로 지정되어, 코드로 읽어 올 수 있습니다.


    예를들어 "http://localhost:8080/books/100/"으로 호출하는 경우, "100"이 접미사이며, 중괄호로 파라메터로 지정된 경우 다음 코드로 값을 가져올 수 있습니다.

    ARequest.Params.Values['item'] // 100

    리소스접미사는 여러 단계로 정의할 수 있습니다. 

    [ResourceSuffix('{item}/photo/')]
    procedure GetItemPhoto(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    [ResourceSuffix('{item}/{subitem}/')]
    procedure GetItemSub(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);


    HTTP 메소드 프로시저

    EMS 패키지에서는 Get, GetItem, Post, PutItem, DeleteItem 총 5개의 엔드포인트를 제공합니다.

     엔드포인트

     HTTP 메소드

     리소스 접미사

     Get

     GET

     

     GetItem

     GET

     {item}

     Post

     POST

     

     PutItem

     PUT

     {item}

     DeleteItem

     DELETE

     {item}


    위 표와 같이, 엔드포인트는 HTTP 메소드, 리소스 접미사와 매핑됩니다. 

    Get 을 예로 들면, GET으로 리소스에 요청하면 엔드포인트 Get 프로시저가 호출되고, {item}이 포함되어 GET으로 요청하면 GetItem 프로시저가 호출됩니다.


    각 엔드포인트의 프로시저는 엔드포인트 이름으로 시작되도록 정의해야합니다. 만약, 같은 엔드포인트가 프로시저가 2개이상 구현된 경우 실행 시 오류가 발생합니다.


    [실습] REST API 엔드포인트 개발하기

    이 장에서는 엔드포인트 별로 기능을 구현하고 실습하는 방법을 안내합니다.

    실습에서는 도서대여 프로그램의 데이터베이스를 사용 합니다. 데이터 포맷으로는 JSON을 사용합니다.


    사전 준비사항

    다음 디렉토리 구조로 진행합니다.

    도서대여 프로그램 데이터베이스 파일을 DB 디렉토리에 저장합니다.


    위에서 생성한 EMS 패키지 프로젝트 Source 디렉토리에 저장합니다.


    프로젝트 옵션에서 Output 디렉토리를 지정합니다.


    BookResource 데이터 모듈에 아래와 같이 TFDConnection, TFDQuery 컴포넌트를 추가하고 이름을 변경합니다.


    conBookRental(TFDConnection)의 OnBeforeConnect 이벤트 핸들러 생성 후 아래 코드(데이터베이스 파일 경로를 지정)를 추가합니다. uses 절에 System.IOUtils를 추가합니다.

    procedure TBooksResource1.conBookRentalBeforeConnect(Sender: TObject);
    var
      Path: string;
    begin
      Path := TPath.GetFullPath('..\DB\BOOKRENTAL.IB');
      if not TFile.Exists(Path) then
      begin
        raise Exception.Create('Not found database.');
      end;
    
      conBookRental.Params.Values['Database'] := Path;
    end;


    Get / GetItem

    리소스에 GET 메소드로 요청하면 Get 또는 GetItem(접미사가 있을 경우)이 호출됩니다. GET 메소드는 조회 역할을 하면 각 엔드포인트는 다음 역할을 구현합니다.

    • Get - 리소스의 목록 정보 조회
    • GetItem - 리소스의 상세 정보 조회

    Get - 리소스 목록

    Get 엔드포인트는 리소스 목록을 조회하는 역할을 합니다. 실습에서는 도서정보 리소스를 구현하므로, 도서 정보 목록을 제공하도록 구현합니다.


    GET http://localhost:8080/books/

    {
      "books":
      {
        "total":6,
        "book":
        [
          {
            "BOOK_SEQ":15,
            "BOOK_TITLE":"델파이 Begin...End",
            "BOOK_AUTHOR":"김원경"
          },      
          {
            "BOOK_SEQ":16,
            "BOOK_TITLE":"한 번에 개발하는 안드로이드 iOS앱 with 델파이. 1편",
            "BOOK_AUTHOR":"김원경 , 김현수, 오상현"
          }
        ]
      }
    }

    Get 엔드포인트에 아래와 같이 구현합니다. JSON 데이터 작성은 TJsonObjectWriter를 이용했습니다. 다른 JSON 라이브러리를 사용해 작성해도 무관합니다.

    procedure TBooksResource1.Get(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    const
      SQL_LIST ='SELECT BOOK_SEQ, BOOK_TITLE, BOOK_AUTHOR, BOOK_PRICE FROM BOOK';
    var
      Writer: TJsonObjectWriter;
    begin
      qryBook.Close;
      qryBook.SQL.Text := SQL_LIST;
      qryBook.Open;
    
      Writer := TJsonObjectWriter.Create;
      try
        Writer.WriteStartObject; // start resource
        Writer.WritePropertyName('books');
    
        Writer.WriteStartObject; // start item
        Writer.WritePropertyName('total');
        Writer.WriteValue(qryBook.RecordCount);
    
        Writer.WritePropertyName('book');
        Writer.WriteStartArray;
    
        qryBook.First;
        while not qryBook.Eof do
        begin
          Writer.WriteStartObject;
          Writer.WritePropertyName('BOOK_SEQ');
          Writer.WriteValue(qryBook.FieldByName('BOOK_SEQ').AsInteger);
    
          Writer.WritePropertyName('BOOK_TITLE');
          Writer.WriteValue(qryBook.FieldByName('BOOK_TITLE').AsString);
    
          Writer.WritePropertyName('BOOK_AUTHOR');
          Writer.WriteValue(qryBook.FieldByName('BOOK_AUTHOR').AsString);
    
          Writer.WritePropertyName('BOOK_PRICE');
          Writer.WriteValue(qryBook.FieldByName('BOOK_PRICE').AsString);
    
          Writer.WriteEndObject;
          qryBook.Next;
        end;
    
        Writer.WriteEndArray;
    
        Writer.WriteEndObject;  // end item
        Writer.WriteEndObject;  // end resource
    
        AResponse.Body.SetValue(Writer.JSON as TJSONValue, True);
      except
        Writer.Free;
        raise;
      end;
    end;

    구현을 마치면, 프로젝트를 실행하고 웹브라우저에서 "http://localhost:8080/books/"를 입력해 JSON 문자열이 화면에 표시되는 것을 확인합니다.


    GetItem - 리소스 상세

    GetItem 엔드포인트는 특정 도서의 상세 정보를 제공하도록 구현합니다.


    GET http://localhost:8080/books/{item}/

    {
      "book":
      {
        "BOOK_SEQ":15,
        "BOOK_TITLE":"델파이 Begin...End",
        "BOOK_ISBN":"9788996251613",
        "BOOK_AUTHOR":"김원경",
        "BOOK_PRICE":"28000",
        "BOOK_LINK":"http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9788996251613&orderClick=LAG&Kc=SETLBkserp1_5",
        "BOOK_DESCRIPTION":"델파이의 시작부터 끝까지 파헤치다!
    ... (생략)"
      }
    }

    다음과 같이 구현합니다.

    procedure TBooksResource1.GetItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    const
      SQL_ITEM_INFO = 'SELECT ' +
                        'BOOK_SEQ, BOOK_TITLE, BOOK_ISBN, BOOK_AUTHOR, BOOK_PRICE, ' +
                        'BOOK_LINK, BOOK_DESCRIPTION ' +
                      'FROM BOOK WHERE BOOK_SEQ = :BOOK_SEQ';
    
    var
      BOOK_SEQ: string;
      Writer: TJsonObjectWriter;
    begin
      BOOK_SEQ := ARequest.Params.Values['item'];
      // Sample code
      qryBook.Close;
      qryBook.SQL.Text := SQL_ITEM_INFO;
      qryBook.ParamByName('BOOK_SEQ').AsString := BOOK_SEQ;
      qryBook.Open;
    
      if qryBook.RecordCount = 0 then
        AResponse.RaiseNotFound('Not found', '''' + BOOK_SEQ + ''' is not found');
    
      Writer := TJsonObjectWriter.Create;
      try
        Writer.WriteStartObject;  // start resource
        Writer.WritePropertyName('book');
    
        Writer.WriteStartObject;  // start item
        Writer.WritePropertyName('BOOK_SEQ');
        Writer.WriteValue(qryBook.FieldByName('BOOK_SEQ').AsInteger);
    
        Writer.WritePropertyName('BOOK_TITLE');
        Writer.WriteValue(qryBook.FieldByName('BOOK_TITLE').AsString);
    
        Writer.WritePropertyName('BOOK_ISBN');
        Writer.WriteValue(qryBook.FieldByName('BOOK_ISBN').AsString);
    
        Writer.WritePropertyName('BOOK_AUTHOR');
        Writer.WriteValue(qryBook.FieldByName('BOOK_AUTHOR').AsString);
    
        Writer.WritePropertyName('BOOK_PRICE');
        Writer.WriteValue(qryBook.FieldByName('BOOK_PRICE').AsString);
    
        Writer.WritePropertyName('BOOK_LINK');
        Writer.WriteValue(qryBook.FieldByName('BOOK_LINK').AsString);
    
        Writer.WritePropertyName('BOOK_DESCRIPTION');
        Writer.WriteValue(qryBook.FieldByName('BOOK_DESCRIPTION').AsString);
    
        Writer.WriteEndObject;  // end item
        Writer.WriteEndObject;  // end resource
    
        AResponse.Body.SetValue(Writer.JSON as TJSONValue, True);
      except
        Writer.Free;
        raise;
      end;
    end;

    구현을 마치고, 프로젝트를 실행하고, 웹브라우저에 "http://localhost:8080/books/{item}/"({item}은 목록의 BOOK_SEQ로 치환합니다.) 입력해 결과를 확인합니다.

    RESTDebugger - REST API 분석도구

    GET 메소드의 경우 웹브라우저로 손쉽게 테스트 해볼 수 있습니다. 테스트 하기 어려운 POST, PUT, DELETE 메소들은 RESTDebugger를 이용해 테스트 할 수 있습니다.


    RESTDebugger는 Tools > REST Debugger 메뉴를 사용해 실행합니다.

    Request 탭의 Method(HTTP 메소드), URL, Conentt-type, Custom body 등을 지정 후


    Parameters 탭에서 Resource, Request Parameters 항목을 지정 해 [Send Reuqest] 버튼을 눌러 요청합니다.

    Resource 항목의 경우 {item}과 같이 중괄호로 지정한 항목이 자동으로 파라메터에 추가됩니다.


    응답은 Headers와 Body 탭에 정보가 표시됩니다.



    자세한 사용법은 다음 링크를 참고하시기 바랍니다.


    Post / PutItem / DeleteItem

    리소스를 생성, 수정, 삭제합니다. 생성과 수정에 필요한 정보는 요청 시 Custom Body영역에 JSON 포맷으로 전달하도록 구현합니다.

    Post - 리소스 생성

    Post 엔드포인트는 도서정보를 생성하도록 구현합니다. 도서에 대한 정보는 요청(Request)의 Custom Body에 담긴JSON 데이터를 이용합니다.

    POST http://localhost:8080/books/
    Custom Body

    {
      "book":
      {
        "BOOK_TITLE":"테스트",
        "BOOK_ISBN":"1234567890123",
        "BOOK_AUTHOR":"홍길동",
        "BOOK_PRICE":"10000",
        "BOOK_LINK":"",
        "BOOK_DESCRIPTION":"12345."
      }
    }


    다음과 같이 구현합니다.

    procedure TBooksResource1.Post(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    const
      SQL_ITEM_INSERT = 'INSERT INTO BOOK(BOOK_TITLE, BOOK_ISBN, BOOK_AUTHOR, BOOK_PRICE, BOOK_LINK, BOOK_DESCRIPTION)' +
                        '  VALUES (:BOOK_TITLE, :BOOK_ISBN, :BOOK_AUTHOR, :BOOK_PRICE, :BOOK_LINK, :BOOK_DESCRIPTION)';
    
    var
      Title, Author, Price, ISBN, Link, Desc: string;
      Json: TJSONValue;
    begin
      JSON := ARequest.Body.GetValue;
    
      Title := JSON.GetValue<string>('book.BOOK_TITLE');
      ISBN := JSON.GetValue<string>('book.BOOK_ISBN');
      Author := JSON.GetValue<string>('book.BOOK_AUTHOR');
      Price := JSON.GetValue<string>('book.BOOK_PRICE');
      Link := JSON.GetValue<string>('book.BOOK_LINK');
      Desc := JSON.GetValue<string>('book.BOOK_DESCRIPTION');
      qryBook.Close;
      qryBook.SQL.Text := SQL_ITEM_INSERT;
      qryBook.ParamByName('BOOK_TITLE').AsString := Title;
      qryBook.ParamByName('BOOK_ISBN').AsString := ISBN;
      qryBook.ParamByName('BOOK_AUTHOR').AsString := Author;
      qryBook.ParamByName('BOOK_PRICE').AsString := Price;
      qryBook.ParamByName('BOOK_LINK').AsString := Link;
      qryBook.ParamByName('BOOK_DESCRIPTION').AsString := Desc;
      qryBook.ExecSQL;
    end;


    구현을 마치고, 프로젝트를 실행합니다. REST Debugger에서 아래와 같이 정보 입력해 테스트 합니다. 요청 후 도서 목록(http://localhost:8080/books/)에서 추가된 것을 확인합니다.


    현재(2017.05) REST Debugger의 Custom Body가 유니코드를 지원하지 않는 버그가 있습니다.(한글을 입력 후 요청 시 캐릭터셋이 맞지 않는 오류가 EMS 패키지에서 발생합니다.)


    조치방법

    1번안 - REST Debugger 소스코드를 수정합니다.

    • C:\Program Files (x86)\Embarcadero\Studio\19.0\source\data\rest\restdebugger\RESTDebugger.dpr(10.2 도쿄 기준) 프로젝트 열기
    • uMain_frm.pas의 762번째 줄을 아래와 같이 수정
      •   memo_RequestBody.Lines.SaveToStream(FRESTParams.CustomBody, TEncoding.UTF8);
    • 컴파일(Project > Options > Delphi Compoiler > Output Directory를 접근 권한이 있는 곳으로 변경)


    2번안 - 아래 RESTDebugger 실행파일을 다운로드 후 테스트 합니다.

    RESTDebugger.zip


    PutItem - 리소스 수정

    PutItem 엔드포인트는 특정한 도서정보를 수정하도록 구현합니다. 도서의 Id는 리소스 접미사를 이용해 파악합니다. 도서에 대한 정보는 요청(Request)의 Custom Body에 담긴JSON 데이터를 이용합니다.

    PUT http://localhost:8080/books/{item}/ - {item}은 유효한 도서일련번호로 변경할 것
    Custom Body

    {
      "book":
      {
        "BOOK_TITLE":"테스트 수정",
        "BOOK_ISBN":"1234567890123",
        "BOOK_AUTHOR":"홍길동",
        "BOOK_PRICE":"10000",
        "BOOK_LINK":"",
        "BOOK_DESCRIPTION":"12345."
      }
    }


    다음과 같이 구현합니다.

    procedure TBooksResource1.PutItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    const
      SQL_ITEM_UPDATE = 'UPDATE BOOK SET ' +
                        '  BOOK_TITLE = :BOOK_TITLE,' +
                        '  BOOK_ISBN = :BOOK_ISBN, ' +
                        '  BOOK_AUTHOR = :BOOK_AUTHOR,' +
                        '  BOOK_PRICE = :BOOK_PRICE,' +
                        '  BOOK_LINK = :BOOK_LINK, ' +
                        '  BOOK_DESCRIPTION = :BOOK_DESCRIPTION ' +
                        ' WHERE ' +
                        '  BOOK_SEQ = :BOOK_SEQ';
    
    var
      BOOK_SEQ: string;
      Title, Author, Price, ISBN, Link, Desc: string;
      Json: TJSONValue;
    begin
      BOOK_SEQ := ARequest.Params.Values['item'];
      JSON := ARequest.Body.GetValue;
    
      Title := JSON.GetValue<string>('book.BOOK_TITLE');
      ISBN := JSON.GetValue<string>('book.BOOK_ISBN');
      Author := JSON.GetValue<string>('book.BOOK_AUTHOR');
      Price := JSON.GetValue<string>('book.BOOK_PRICE');
      Link := JSON.GetValue<string>('book.BOOK_LINK');
      Desc := JSON.GetValue<string>('book.BOOK_DESCRIPTION');
      qryBook.Close;
      qryBook.SQL.Text := SQL_ITEM_UPDATE;
      qryBook.ParamByName('BOOK_TITLE').AsString := Title;
      qryBook.ParamByName('BOOK_ISBN').AsString := ISBN;
      qryBook.ParamByName('BOOK_AUTHOR').AsString := Author;
      qryBook.ParamByName('BOOK_PRICE').AsString := Price;
      qryBook.ParamByName('BOOK_LINK').AsString := Link;
      qryBook.ParamByName('BOOK_DESCRIPTION').AsString := Desc;
      qryBook.ParamByName('BOOK_SEQ').AsString := BOOK_SEQ;
      qryBook.ExecSQL;
    
      if qryBook.RowsAffected = 0 then
        AResponse.RaiseNotFound('Not found', '''' + BOOK_SEQ + ''' is not found');
    end;


    구현을 마치고, 프로젝트를 실행합니다. REST Debugger에서 아래와 같이 정보 입력해 테스트 합니다. 요청 후 도서 목록(http://localhost:8080/books/)에서 수정된 것을 확인합니다.


    DeleteItem - 리소스 삭제

    DeleteItem 엔드포인트는 특정 도서정보를 삭제하도록 구현합니다. 도서의 Id는 리소스 접미사를 이용해 파악합니다. 

    DELETE http://localhost:8080/books/{item}/ - {item}은 유효한 도서일련번호로 변경할 것

    다음과 같이 구현합니다.

    procedure TBooksResource1.DeleteItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    const
      SQL_ITEM_DELETE ='DELETE FROM BOOK WHERE BOOK_SEQ = :BOOK_SEQ';
    
    var
      BOOK_SEQ: string;
    begin
      BOOK_SEQ := ARequest.Params.Values['item'];
    
      qryBook.Close;
      qryBook.SQL.Text := SQL_ITEM_DELETE;
      qryBook.ParamByName('BOOK_SEQ').AsString := BOOK_SEQ;
      qryBook.ExecSQL;
    
      if qryBook.RowsAffected = 0 then
        AResponse.RaiseNotFound('Not found', '''' + BOOK_SEQ + ''' is not found');
    end;


    구현을 마치고, 프로젝트를 실행합니다. REST Debugger에서 아래와 같이 정보 입력해 테스트 합니다. 요청 후 도서 목록(http://localhost:8080/books/)에서 삭제된 것을 확인합니다.


    GetItem - 이미지 제공

    도서정보의 경우 이미지를 제공합니다. 이미지 제공은 상세 정보 하위 "photo" 리소스를 추가해 구현합니다.


    GET http://localhost:8080/books/{item}/photo/ - {item}은 유효한 도서일련번호로 변경할 것

    아래 코드를 참고해 하위 리소스 엔드포인트를 추가합니다.

    [ResourceSuffix('{item}/photo/')]
    procedure GetItemPhoto(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);

    다음과 같이 구현합니다. 

    procedure TBooksResource1.GetItemPhoto(const AContext: TEndpointContext;
      const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    const
      SQL_ITEM_IMAGE ='SELECT BOOK_IMAGE FROM BOOK WHERE BOOK_SEQ = :BOOK_SEQ';
    var
      BOOK_SEQ: string;
      Stream: TMemoryStream;
    begin
      BOOK_SEQ := ARequest.Params.Values['item'];
    
      Stream := TMemoryStream.Create;
      try
        qryBook.Close;
        qryBook.SQL.Text := SQL_ITEM_IMAGE;
        qryBook.ParamByName('BOOK_SEQ').AsString := BOOK_SEQ;
        qryBook.Open;
    
        if qryBook.RecordCount = 0 then
          AResponse.RaiseNotFound('Not found', '''' + BOOK_SEQ + ''' is not found');
    
        TBlobField(qryBook.FieldByName('BOOK_IMAGE')).SaveToStream(Stream);
    
        if Stream.Size = 0 then
          AResponse.RaiseNotFound('Not found', '''' + BOOK_SEQ + ''' is not found');
    
        Stream.Position := 0;
        AResponse.Body.SetStream(Stream, 'image/jpeg', True);
      except
        Stream.Free;
        raise;
      end;
    end;

    위 코드는 DB에 저장된 이미지 데이터를 Stream으로 로드 해 그대로 응답합니다. 특히 Content-type을 'image/jpg'로 지정해 데이터가 이미지라는 것을 정의합니다.


    구현을 마치면, 프로젝트를 실행하고 웹브라우저에서 "http://localhost:8080/books/{item}/photo/"를 입력해 화면에 이미지가 표시되는 것을 확인합니다.



    추가 학습할 내용

    REST API 클라이언트 개발하기(REST 클라이언트 이용)

    위에서 작성한 REST API 서버와 연동하는 클라이언트를 개발합니다. REST API를 분석해 조회, 입력, 수정, 삭제, 이미지 수신 기능을 실습위주로 학습합니다.

    • http://blog.hjf.pe.kr/464

    참고/관련 자료





    험프리.김현수 Delphi/C++Builder

    [REST API] REST API 이해하기

    2017.05.11 17:17

    이 글에서는 REST 아키텍처를 소개합니다.


    REST는?

    REST(Representational State Transfer)는 인터넷 상의 컴퓨터 시스템간 상호 운용성을 제공하는 방법 중 하나입니다. 


    REST는 HTTP 기반으로 필요한 자원에 접근하는 방식을 정해놓은 네트워크 아키텍처입니다.

    여기서 자원이란, 저장된 데이터(DBMS 등)는 물론, 이미지/동영상/문서(PDF 등)와 같은 파일, 서비스(이메일 전송, 푸쉬 메시지 등) 등을 모두 포함합니다.


    REST는 HTTP의 주요 저자 중 한사람인 로이 필딩의 2000년 박사학위 논문에서 처음 소개되었습니다.

    REST의 제약조건

    아래 REST 제약조건을 준수하는 웹서비스를 RESTful 하다고 합니다.

    • 클라이언트/서버 : 클라이언트와 서버가 각각 역할이 구분되어야 한다. 
      • 서버는 API를 제공하고 API 요청 시 비지니스 로직 처리와 데이터 저장을 책임. 클라이언트는 사용자 인증, 상태(세션, 로그인 정보)관리와 서버 리소스 요청을 책임지는 구조로 역할 구분(상호 의존성을 줄임)
    • 무상태(Stateless) : REST 서버는 작업을 위한 상태정보(세션, 쿠키 등)를 관리하지 않아야 한다.
      • 시스템 영향없이 관리 및 업데이트 가능
    • 캐쉬(Cacheable) : 캐쉬를 제공해야 한다.
      • HTTP 웹표준으로 HTTP가 가진 캐싱 기능이 적용됨
    • 계층화(Layered system) : 서버를 다중 계층으로 구성 할 수 있어야 한다.
      • 비지니스 로직을 수행하는 API 서버와 그 앞단에 사용자 인증, 암호화, 로드밸런싱 등의 계층을 추가해 구조상의 유연성 제공
    • 인터페이스 일관성(Uniform interface)
      • 아키텍처를 단순화하고 분리해 각 부분을 독립적으로 발전 시킬 수 있음


    REST 주요 구성요소

    REST 주요 구성요소 3가지

    • 자원(리소스) : 접근할 대상 - URI를 통해 식별
    • 행위(메소드) : 자원에 대한 행위 - 표준 HTTP 메소드에 따라 자원에 접근
    • 정보(메시지) : 자원에 대한 정보 - HTTP 해더와 바디, 응답코드 활용
    즉, REST는 어떤 자원(리소스)에 어떤 행위(메소드)를 어떻게(메시지) 할지 HTTP 기반으로 정해놓은 아키텍처입니다.

    자원(리소스)

    리소스는 URI를 통해 정의합니다.


    예를 들면, 아래와 같은 URI는 다음과 같은 의미를 갖습니다.

     URI 

     의미 

     http://api.domain.com/books/

     도서정보 콜렉션 

     http://api.domain.com/books/1/ 

     1번 도서 정보 

     http://api.domain.com/books/1/photo/

     1번 도서의 사진


    리소스명은 동사보다 명사를 활용해 어떤 자원인지 표현하는데 집중해야 합니다.(/getBooks/와 같은 리소스는 적절하지 않습니다.)


    슬래시(/)는 계층 관계를 나타내며, URI 앞쪽부터 넓은 의미로 사용합니다.

    일반적으로 계층은 컬렉션(목록) 하위에 아이템을 지정하는 방식으로 정의합니다.


    아래와 같이 URI를 구성할 수 있습니다.

    /sports/soccer/players/1/

    /(컬렉션)/(아이템)/(컬렉션)/(아이템)/


    메소드

    REST에서는 HTTP 메소드를 통해 리소스에 대한 행위를 정의합니다.


    표준 HTTP 메소드 중 Get, Post, Put, Delete를 통해 자원의 CRUD를 정의합니다.

     HTTP 메소드

     자원에 대한 행위

     POST

     자원 생성(Create)

     GET

     자원 조회(Read)

     PUT

     자원 수정(Update)

     DELETE

     자원 삭제(Delete)


    Endpoint

    다음과 같이 메소드와 URI를 이용해 리소스에 접근합니다. URI 별 HTTP 메소드로 구현된 항목을 Endpoint라고 합니다.

     HTTP 메소드 

     URI(자원)

     Endpoint의 행위

     POST

     http://api.domain.com/books/

     새로운 도서정보 생성

     GET

     http://api.domain.com/books/

     도서정보 목록 조회

     GET

     http://api.domain.com/books/1/

     1번 도서정보 조회

     PUT

     http://api.domain.com/books/1/

     1번 도서정보 수정

     DELETE

     http://api.domain.com/books/1/

     1번 도서정보 삭제


    메시지

    REST에서 자원에 대한 정보는 HTTP 바디와 HTTP 해더, 응답 상태코드를 활용해 표현합니다.


    HTTP 바디

    HTTP 바디에 포함된 데이터를 통해 자원에 대한 정보를 전달합니다.

    데이터 포맷으로는 최근 JSON을 많이 사용하는 추세이며, XML과 사용자정의 포맷 등을 정해서 사용할 수도 있습니다.


    조회(GET 메소드) 요청 시 서버는 조건에 맞는 정보를 HTTP 바디에 담아 클라이언트에 응답합니다.

    생성(POST 메소드), 수정(PUT 메소드) 요청 시 클라이언트는 자원에 대한 정보를 요청 HTTP 바디에 담아 서버에 요청합니다.


    HTTP 해더

    HTTP 해더에는 HTTP 바디의 컨텐츠 종류를 명시할 수 있습니다. 해더에 정의된 컨텐츠 타입에 따라 데이터를 분석하도록 구현해야 합니다.

    요청 HTTP 해더는 "Accept" 항목으로, 응답 HTTP 해더는 "Content-type"으로 컨텐츠 타입을 설명합니다.


    몇가지 컨텐츠 타입은 다음과 같습니다.

    • application/json
    • application/xml
    • text/plain
    • image/jpeg
    • image/png
    미디어 타입, 컨텐츠 타입 자세히 보기 : https://ko.wikipedia.org/wiki/미디어타입

    인증 권한정보(Authorization)도 보통 해더를 통해 전달합니다.

    응답 상태코드

    리소스 요청에 대한 결과는 응답 상태코드로 표현할 수 있습니다. 자원 요청 시 1차적으로 응답 상태코드로 결과를 표현하고, 바디 영역의 데이터로 상세 결과(코드 또는 메시지)를 제공할 수 있습니다.


    대표적인 응답 상태코드는 아래와 같습니다.
    • 200 - 요청을 정상 수행
    • 201 - 리소스 생성 요청 성공(Post로 생성 요청 시에 한함)
    • 400 - 요청이 부적절함
    • 401 - 인증되지 않은 상태에서 보호된 리소스 요청
    • 403 - 공개되지 않은 리소스에 접근 요청(인증과 무관)
    • 404 - 존재하지 않는 리소스 요청
    • 406 - 지원하지 않는 미디어타입을 요청
    • 409 - 리소스 상태에 의해 해당 요청을 수행하지 못함
    HTTP 상태코드 자세히 보기 : https://ko.wikipedia.org/wiki/HTTP_상태_코드

    REST API 구현

    REST 기반으로 서비스 API를 구현한 것을 REST API라고 합니다.

    REST API 구현의 특징

    최근 OpenAPI(누구나 사용할 수 있도록 공개된 API: 구글 맵, 공공 데이터 등), 마이크로 서비스(하나의 큰 애플리케이션을 여러 개의 작은 애플리케이션으로 쪼개어 변경과 조합이 가능하도록 만든 아키텍처) 등을 제공하는 업체 대부분은 REST API를 제공합니다. 


    또, 사내 시스템들도 REST 기반으로 시스템을 분산해 확장성과 재사용성을 높여 유지보수 및 운용을 편리하게 할 수 있습니다. 


    REST는 HTTP 표준을 기반으로 구현하므로, HTTP를 지원하는 프로그램 언어로 클라이언트, 서버를 구현할 수 있습니다. 

    즉, REST API를 제작하면 델파이 클라이언트 뿐 아니라, 자바, C#, 웹 등을 이용해 클라이언트를 제작할 수 있습니다. 물론 반대의 방법도 가능합니다.


    델파이로 REST API 구현

    델파이의 HTTP 라이브러리를 이용핸 REST API를 구현할 수 있습니다.

    REST API 구현해 특화된 기술은 서버 측 기술로는 EMS 서버 클라이언트 기술로는 REST 클라이언트 라이브러리가 있습니다.

    서버(Back-End) 프레임워크

    • RAD Server(EMS Server) - REST API Endpoint 제공
    • WebBroker - RAD 스튜디오(델파이, C++빌더) 웹 개발 프레임워크
    • DataSnap - RAD 스튜디오 멀티티어 개발 프레임워크, TCP/IP, HTTP 프로토콜 제공
    • Delphi MVC Framework - 오픈소스 웹서비스 개발 프레임워크
    • mORMot - 오픈소스 SOA, ORM 개발 프레임워크

    클라이언트(Front-End) 프레임워크

    • REST Client - REST 클라이언트 프레임워크
    • Net HTTP Client - 네이티브 HTTP 클라이언트 프레임워크
    • Indy Library - 범용 네트워크 라이브러리(HTTP 클라리언트, 서버 제공)


    추가 학습할 내용

    EMS 패키지 프로젝트 시작하기

    EMS 패키지는 REST API 리소스와 엔드포인트 개발을 지원합니다. EMS 패키지 프로젝트를 만들고, 배포하는 내용을 학습할 수 있습니다.

    REST API 서버 개발하기(엔드포인트 구현, RAD 서버 이용)

    EMS 패키지를 이용해 REST API를 제공하는 서버를 개발합니다. 미리 준비된 DB를 이용해 조회, 입력, 수정, 삭제, 이미지 제공 등의 기능을 실습위주로 학습합니다.

    REST API 클라이언트 개발하기(REST 클라이언트 이용)

    위에서 작성한 REST API 서버와 연동하는 클라이언트를 개발합니다. REST API를 분석해 조회, 입력, 수정, 삭제, 이미지 수신 기능을 실습위주로 학습합니다.


    참고 링크



    험프리.김현수 Delphi/C++Builder

    1. Blog Icon

      비밀댓글입니다

    [RAD서버] EMS 패키지 프로젝트 시작하기

    2017.04.27 17:10

    이 글에서는 EMS 서버에 필요한 기능을 추가할 수 있는, EMS 패키지 프로젝트 개발을 시작하는 과정을 안내합니다.

    EMS 패키지란?


    EMS 서버는 REST API 기반으로 리소스를 제공하는 미들웨어 서버입니다. EMS 서버가 제공하는 리소스는 기본 제공 리소스(사용자, 그룹, 푸시 등)와 사용자가 직접 개발 후 추가 할 수 있는 사용자 제작 리소스가 있습니다.


    사용자 제작 리소스는 RAD 스튜디오(델파이 또는 C++빌더)에서 EMS 패키지 프로젝트를 이용해 개발해, EMS 서버에 플러그인 형태로 추가할 수 있습니다.


    이 글에서는 다음 내용을 안내합니다.

    • EMS 패키지 프로젝트 생성
    • EMS 패키지 실행
    • EMS 패키지 배포 방법
    • 추가 학습할 내용

    EMS 패키지 프로젝트 생성

    프로젝트 생성

    File > New > Other 메뉴 선택 후 Delphi Projects > EMS 메뉴에서 EMS Package를 선택 후 [OK] 버튼을 누릅니다.


    EMS 패키지 마법사에서 패키지 종류를 선택합니다.

    리소스 제공을 위해 "Create package with resource" 항목 선택 후 [Next] 버튼을 클릭합니다.


    제공할 리소스 이름 입력 후, 파일 타입을 선택 후 [Next] 버튼을 클릭합니다.

    • Data Module : 리소스에서 쿼리 컴포넌트와 같은 논비주얼 컴포넌트를 사용할 경우
    • Unit : 코드만으로 리소스를 구성할 경우


    리소스에서 사용할 EndPoint 종류를 선택하고 [Finish] 버튼을 클릭합니다. 이 과정에서는 모든 EndPoint를 선택합니다.



    프로젝트가 만들어지면, File > Save all 메뉴를 눌러 원하는 경로에 프로젝트를 저장합니다.(저는 프로젝트 명만 HelloEMS으로 지정했습니다.)


    EMS 패키지 실행 및 테스트

    EMS 서버 환경설정

    EMS 서버를 최초 실행하는 경우 환경설정 단계를 수행합니다. 이 단계는 최초 실행 시에만 진행됩니다.


    Run (F9) 버튼을 누르면 아래 그림과 같이 EMS 개발 서버가 실행됩니다. EMS 서버 최초 실행 시 환경정보를 설정하는 과정이 진행됩니다. [Yes] 버튼을 클릭합니다.


    환경설정 첫번째 단계에서는 EMS 데이터베이스를 설정합니다. 

    (EMS 데이터베이스는 인터베이스를 사용합니다. 만약,  인터베이스를 설치 하지 않았다면, 현재 단계를 취소하고, 바로 아래의 "인터베이스 추가 설치" 항목을 참고해 인터베이스를 먼저 설치하고 다시 시도하시기 바랍니다.)

    • Server Instance : 인터베이스 서버의 인스턴스 이름 입력(기본 : gds_db)
      • 확인방법 : InterBase Server Manager 실행(시작 > 모든 프로그램 > Embarcadero Interbase XE7 > InterBase Server Manager 선택)  후 확인
    • DB File Name, DB File Directory, DB User Name, DB Password 입력


    인터베이스 추가 설치

    RAD 스튜디오 설치 시 추가 옵션으로 인터베이스 개발자 에디션을 설치할 수 있습니다.(기본 옵션에 포함)

    만약, 추가 옵션에서 인터베이스를 선택하지 않았다면, RAD 스튜디오 "메인메뉴 > Tools > Manage Platofmrs..." 메뉴를 선택해 인터베이스 개발자 에디션을 추가 설치합니다.


    샘플 데이터를 선택하고 [>> Next] 버튼 클릭합니다.


    EMS 콘솔(모니터링 웹사이트) 로그인 계정을 입력하고 [>>Next] 버튼을 클릭합니다.

    (향후 EMS 서버 설정파일에서 변경할 수 있습니다.)


    최종적으로 확인하고 [Finish] 버튼을 클릭합니다.


    개발 목적으로 EMS 서버를 라이선스 없이 사용할 경우 일부기능이 제한됩니다. [Yes] 버튼을 클릭합니다.


    EMS 패키지 실행

    Run (F9) 버튼을 눌러 EMS 패키지 프로젝트를 실행하면, 아래 그림과 같이 EMS 개발 서버가 실행 후 자동 시작됩니다.


    EMS 개발 서버는 EMS 패키지(*.bpl)를 동적 로드해 서비스하는 역할을 합니다.

    EMS 개발 서버는 RAD 스튜디오 실행파일과 같은 경로에서 제공하며, 

    • EMS 개발 서버 실행파일 경로 : C:\Program Files (x86)\Embarcadero\Studio\19.0\bin\EMSDevServer.exe

    EMS 패키지의 Host application(메인메뉴 > Run > Parameters...)으로 지정되어 있습니다.



    EMS 개발 서버의 화면 로그를 살펴보면 아래와 같은 로그가 있습니다.

    {"Loading":{"Filename":"C:\Users\Public\Documents\Embarcadero\Studio\19.0\Bpl\HelloEms.bpl","Thread":428}}

    {"RegResource":{"Resource":"helloems","Endpoints":["Get","GetItem","GetItemPhoto","Post","PutItem","DeleteItem"],"Thread":428}}


    앞에서 개발한 EMS 패키지(HelloEMS.bpl)을 로드하고, EMS 패키지의 리소스(helloems)와 엔드포인트가 등록됩니다.

    (패키지를 등록하는 내용은 뒤에서 다시 소개합니다.)


    웹브라우저를 열고, "http://(서버IP):(포트번호)/(리소스 이름)/" 주소를 엽니다.


    EMS 패키지 생성하는 과정과 실행하는 과정을 살펴봤습니다.

    아래에서 EMS 패키지의 소스코드 구조와 배포방법을 간단히 살펴봅니다.


    JSON 포맷의 데이터 제공과 데이터셋 연결하는 내용은 아래 "추가 학습할 내용"을 통해 학습하시기 바랍니다.


    참고>

    인터넷 익스플로러에서 json 파일을 다운로드 된다면, 레지스트리를 수정해 웹브라우저에 문자열이 표시되도록 조치할 수 있습니다.


    [HKEY_CLASSES_ROOT\MIME\Database\Content Type\application/json] 

    "CLSID"="{25336920-03F9-11cf-8FD0-00AA00686F13}" 

    "Encoding"=hex:08,00,00,00


    EMS 패키지 소스코드 구조 소개

    생성된 프로젝트는 아래와 같은 구조로 소스코드가 자동 생성됩니다.



    [ResourceName('helloems')]

    리소스 이름을 지정하는 특성(Attribute)입니다. 구문 바로아래 정의된 클래스(THelloemsResource1)의 리소스 이름을 지정합니다.

    즉, 'helloems' 리소스 호출 시 THelloemsResource1 클래스에 정의된 함수가 호출됩니다.


    Get, GetItem, Post, PutItem, DeleteItem

    HTTP 메소드 Get, Post, Put, Delete와 매핑되는 메소드들 입니다. REST 규약에 맞춰 Get은 읽기, Post는 쓰기, Put은 수정, Delete는 삭제 기능을 구현하면 됩니다.


    HTTP 메소드 중 Get의 경우 Get과 GetItem 두개의 함수를 제공합니다. 일반적으로 Get 함수는 리소스 목록을 GetItem은 특정한 리소스의 상세정보를 제공합니다. 뒤쪽에 Item이 붙은 함수들(GetItem, PutItem, DeleteItem)은 리소스의 특정 항목에 대해 처리(조회, 수정, 삭제)합니다.


    [ResourceSuffix('{item}')]

    리소스 항목을 가져올 파라메터 이름 지정하는 특성(Attribute)입니다. 

    예를 들어 "GET http://localhost:8080/helloems/101/" 요청의 경우 "helloems" 리소스 중 id가 101인 항목의 정보를 제공합니다. 리소스 id를 가져올 파라메터 이름을 지정하는 특성인 ResourceSuffix 입니다.


    GetItem 구현부에서는 아래와 같은 코드로 리소스 id를 가져올 수 있습니다.

      LItem := ARequest.Params.Values['item'];

    참고로, 리소스 하위의 리소스에 접근하는 경우 아래와 같이 정의해 접근할 수 있습니다.

    [ResourceSuffix('{item}')]
    procedure GetItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    [ResourceSuffix('{item}/photo/{id}')]
    procedure GetItemPhoto(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);


    EMS 패키지 배포 방법

    EMS 패키지 생성 경로

    EMS 패키지 기본 생성 경로는 패키지와 마찬가지로 "C:\Users\Public\Documents\Embarcadero\Studio\19.0\Bpl"(10.2 도쿄 기준)에 생성됩니다.


    EMS 패키지 생성 경로는 프로젝트 옵션의 Package output directory에서 지정할 수 있습니다.

    경로를 선택하거나, 상대경로를 지정할 수 있습니다. 아래 그림과 같이 환경변수를 이용해 플랫폼, 빌드옵션 별로 파일을 생성할 수 있습니다.


    EMS 패키지 등록

    EMS 패키지를 여러개 개발해 테스트하거나 운영하려면 EMS 서버 환경파일(emsserver.ini)에 패키지를 추가해야합니다.

    EMS 서버 환경파일의 경로는 EMS 환경설정 단계에서 지정되며, 기본 값으로 "C:\Users\Public\Documents\Embarcadero\EMS"을 사용합니다.


    환경파일의 경로는 레지스트리(HKEY_CURRNET_USER\Software\Embarcadero\EMS\ConfigFile)를 통해 재설정 할 수 있습니다.


    환경파일(emsserver.ini)을 열고, [Server.Packages] 섹션으로 이동합니다.

    아래 그림과 같이 "경로"="패키지 설명" 형식으로 패키지 정보를 추가합니다.


    환경파일 수정에 대한 자세한 내용은 다음 링크에서 자세히 확인할 수 있습니다.


    추가 학습할 내용

    EMS 패키지 - JSON 형식의 REST EndPoint 제공



    EMS 패키지 - 데이터셋 기반 REST EndPoint 제공


    EMS 서버 운영환경에 설치하기(독립형 실행파일)

    독립현 실행파일 방식의 EMS 서버를 운영환경(윈도우즈 서버)에 설치하는 내용을 설명합니다.


    참고/관련 자료



    험프리.김현수 Delphi/C++Builder