RESTful API에서 명령 패턴 구현


12

HTTP API를 디자인하는 과정에서 가능한 한 RESTful하게 만들었습니다.

기능이 몇 가지 리소스에 퍼져있는 작업이 있으며 언젠가 취소해야합니다.

제 생각에 이것은 명령 패턴처럼 들리지만 어떻게 리소스로 모델링 할 수 있습니까?

DepositAction과 같은 XXAction이라는 새로운 리소스를 소개합니다.

POST /card/{card-id}/account/{account-id}/Deposit
AmountToDeposit=100, different parameters...

실제로 새 DepositAction을 작성하고 Do / Execute 메소드를 활성화합니다. 이 경우 201 Created HTTP 상태를 반환하면 작업이 성공적으로 실행 된 것입니다.

나중에 고객이 수행 할 수있는 작업 세부 정보를 보려는 경우

GET /action/{action-id}

업데이트 / PUT은 여기와 관련이 없기 때문에 차단되어야합니다.

그리고 행동을 취소하기 위해, 나는

DELETE /action/{action-id}

실제로 관련 개체의 Undo 메서드를 호출하고 상태를 변경합니다.

하나의 Do-Undo만으로 만족한다고 가정 해 봅시다. 다시 실행할 필요는 없습니다.

이 방법은 괜찮습니까?

사용하지 않는 이유가 있습니까?

이것은 고객의 POV에서 이해됩니까?


짧은 대답은 REST가 아닙니다.
Evan Plaice

3
@EvanPlaice가 그것에 대해 자세히 신경써? 그것이 바로 질문입니다.
Mithir

1
답변을 자세히 설명했지만 Gary의 답변은 이미 추가 할 내용의 대부분 / 모든 내용을 다루고 있습니다. URI는 리소스만을 나타 내기 때문에 (휴식이 아닌) 휴식이 아니라고 말합니다. 조치는 GET / POST / PUT / DELETE / HEAD를 통해 처리됩니다. REST를 OOP 인터페이스로 생각하십시오. 목표는 API를 일반적인 패턴에 맞추고 가능한 구현 세부 사항에서 분리하는 것입니다.
Evan Plaice

1
@EvanPlaice Ok 이해합니다, 감사합니다. 예금은 명사와 동사로 생각할 수 있기 때문에 여기에 혼란스러워합니다.
Mithir

이 경우 URI는 직불 결제 (돈을 버는 것) 및 크레딧 (돈을주는 것)이 POST 요청을 통해 수행되는 트랜잭션을 나타내야합니다. POST는 돈이 어느 방향 으로든 움직일 때마다 새로운 거래가 생성되기 때문에 두 가지 용도로 사용됩니다. 특정한 경우, 카드 소지자의 계정에서 거래가 이루어 지므로 카드의 계정 번호는 리소스 URI입니다.
Evan Plaice

답변:


13

혼란스러운 추상화 계층을 추가하고 있습니다.

API는 매우 깨끗하고 단순하게 시작됩니다. HTTP POST는 지정된 매개 변수를 사용하여 새 Deposit 자원을 작성합니다. 그런 다음 API의 핵심 부분이 아닌 구현 세부 사항 인 "조치"에 대한 아이디어를 도입하여 문제를 해결합니다.

대안 으로이 HTTP 대화를 고려하십시오 ...

POST / card / {card-id} / account / {account-id} / 예금

AmountToDeposit = 100, 다른 매개 변수 ...

201 년 창조

위치 = / 카드 / 123 / 계정 / 456 / 예금 / 789

이제이 작업을 취소하려고합니다 (기술적으로 균형 잡힌 회계 시스템에서는 허용되지 않아야하지만 헤이는 무엇입니까).

삭제 / card / 123 / account / 456 / Deposit / 789

204 콘텐츠 없음

API 소비자는 자신이 Deposit 리소스를 처리하고 있으며 어떤 작업이 허용되는지 (일반적으로 HTTP의 OPTIONS를 통해) 확인할 수 있습니다.

삭제 작업의 구현은 오늘날 "조치"를 통해 수행되지만이 시스템을 C #에서 Haskell로 마이그레이션하고 "조치"의 보조 개념이 계속해서 가치를 추가 할 것이라는 프런트 엔드를 유지한다고 보장 할 수는 없습니다. 예금의 기본 개념은 확실히 그렇습니다.

삭제 및 입금에 대한 대안을 포함하도록 편집

삭제 조작을 피하면서 여전히 입금을 효과적으로 제거하려면 다음을 수행해야합니다 (일반 거래를 사용하여 입금 및 출금 허용).

POST / card / {card-id} / account / {account-id} / Transaction

금액 = -100 , 다른 매개 변수 ...

201 년 창조

위치 = / 카드 / 123 / 계정 / 456 / 전송 / 790

정확히 반대 금액 (-100)을 갖는 새로운 거래 리소스가 생성됩니다. 이는 원래 거래를 무시하고 계정을 다시 0으로 균형을 맞추는 효과가 있습니다.

다음과 같은 "유틸리티"엔드 포인트 작성을 고려할 수 있습니다.

POST / card / {card-id} / account / {account-id} / Transaction / 789 / Undo <-BAD!

같은 효과를 얻을 수 있습니다. 그러나 이것은 동사를 도입함으로써 URI의 의미를 식별자로 깨뜨립니다. 식별자에서 명사를 고수하고 연산을 HTTP 동사로 제한하는 것이 좋습니다. 그렇게하면 식별자에서 퍼머 링크를 쉽게 생성하고 GET 등에 사용할 수 있습니다.


3
+1 "기술적으로 이것은 균형 회계 시스템에서 허용되지 않아야합니다". 누군가 콩을 계산하는 방법을 알고 있습니다. 그 진술은 절대적으로 정확합니다. 되돌릴 수있는 방법은 자금을 상환하는 다른 거래를 만드는 것입니다. 거래가 완료되면 총계정 원장 항목은 항상 변경 불가능하고 영구적으로 간주되어야합니다.
Evan Plaice

그래서 내 질문에서 Delete / action / ... 대신 Delete / deposit / ...을 변경하면 괜찮습니까?
Mithir

2
@Mithir 나는 회계 규칙을 설명했다. 표준 이중 입력 부기 시스템에서는 거래를 제거하지 않습니다. 한 번 커밋 된 역사는 사람들을 정직하게 지키기 위해 불변의 것으로 간주됩니다. 귀하의 경우 여전히 DELETE 조치를 사용할 수 있지만 백엔드 (예 : 일반 원장 데이터베이스 테이블)에서 사용자에게 돈을 돌려주는 (즉, 돌려주는) 다른 거래를 추가해야합니다. 저는 빈 카운터 (예 : 회계사)는 아니지만 "회계 원칙 I"과정에서 가르치는 표준 관행 중 하나입니다.
Evan Plaice

2
(계속) 데이터베이스 로그는 비슷한 방식으로 트랜잭션을 사용합니다. 그렇기 때문에 로그 만 사용하여 데이터 세트를 복제 및 / 또는 재 구축 할 수 있습니다. 트랜잭션이 시간순으로 재생되는 한, 히스토리의 어느 시점에서나 데이터 세트를 다시 빌드 할 수 있어야합니다. 방정식에서 가변성을 제거하면 일관성이 보장됩니다.
Evan Plaice

1
공정하게 이름을 Transaction으로 바꾸십시오.
Gary Rowe

1

REST가 존재하는 주된 이유는 네트워크 오류에 대한 복원력입니다. 어느 쪽까지 모든 작업이 dem 등원 이어야합니다 .

기본적인 접근 방식은 합리적으로 보이지만, DepositAction창작물 을 묘사하는 방식 은 dem 등 전한 것처럼 들리지 않으므로 수정해야합니다. 함으로써 클라이언트 중복 요청을 감지하는 데 사용되는 고유 ID를 제공합니다. 그래서 창조는

PUT /card/{card-id}/account/{account-id}/Deposit/{action-id}
AmountToDeposit=100, different parameters...

동일한 URL에 대한 다른 PUT이 이전과 동일한 내용으로 작성된 201 created경우 내용이 동일하면 응답이 계속 유지 되고 내용이 다른 경우 오류가 발생합니다. 이를 통해 클라이언트는 요청 또는 응답이 손실되었는지 여부를 알 수 없으므로 요청이 실패 할 때 요청을 재전송 할 수 있습니다.

PUT은 리소스를 쓰고 dem 등성이므로 POST를 사용하는 것이 더 합리적이지만 POST를 사용하더라도 실제로 문제가 발생하지는 않습니다.

거래 세부 정보를 확인하기 위해 고객은 GET동일한 URL (예 :

GET /card/{card-id}/account/{account-id}/Deposit/{action-id}

실행 취소하려면 삭제할 수 있습니다. 그러나 실제로 샘플에서 제안한 바와 같이 돈과 관련이 있다면 책임을 위해 대신 "취소 된"플래그를 추가하여 PUTting하는 것이 좋습니다 (생성 및 취소 된 트랜잭션의 흔적이 남아 있음).

이제 고유 한 ID를 만드는 방법을 선택해야합니다. 몇 가지 옵션이 있습니다.

  1. 포함해야하는 교환 이전에 클라이언트 고유 접 두부를 발행하십시오.
  2. 서버에서 빈 고유 ID를 얻으려면 특수 POST 요청을 추가하십시오. 사용되지 않은 ID는 실제로 문제를 일으키지 않기 때문에이 요청은 dem 등적일 필요는 없습니다 (실제로는 불가능).
  3. UUID를 사용하십시오. 모두가 그것들을 사용하고 아무도 MAC 기반이나 랜덤에 문제가없는 것 같습니다.

2
내가 아는 것에서 POST는 dem 등성이 아닙니다. en.wikipedia.org/wiki/POST_(HTTP)#Affecting_server_state
Mithir

@Mithir : POST는 dem 등원으로 간주되지 않습니다. 여전히 가능합니다. 그러나 모든 REST 조작이 dem 등원이어야하므로 POST는 기본적으로 REST에 위치하지 않습니다.
Jan Hudec

1
혼란 스럽습니다 ... 읽은 내용과 익숙한 기존 구현 (ServiceStack, ASP.NET Web API)은 POST가 REST에 자리 잡고 있음을 제안합니다.
Mithir

3
REST에서 idempotence는 프로토콜 또는 응답 코드가 아닌 자원에 지정됩니다. 따라서 HTTP를 통한 REST에서 응답 코드가 후속 호출에 따라 다를 수 있지만 GET, PUT, DELETE, PATCH 등의 메소드는 dem 등원으로 간주됩니다. POST는 모든 호출이 새로운 리소스를 생성한다는 점에서 dem 등합니다. Fielding의 POST를 사용해도 됩니다. 참조하십시오 .
Gary Rowe

1
dem 등원이 아닌 작업은 휴지 상태로 허용됩니다. 그 주장은 잘못되어 있습니다.
Andy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.