Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
600 views
in Technique[技术] by (71.8m points)

domain driven design - Rest API and DDD

In my project using DDD methodology.

The project has the aggregate(entity) Deal. This aggregate has many of use cases.

For this aggregate I need to create a rest api.

With standard: create and delete no problem.

1) CreateDealUseCase(name, price and many another params);

POST /rest/{version}/deals/
{ 
   'name': 'deal123',
   'price': 1234;
   'etc': 'etc'
}

2) DeleteDealUseCase(id)

DELETE /rest/{version}/deals/{id}

But what to do with the rest of the use cases?

  • HoldDealUseCase(id, reason);
  • UnholdDealUseCase(id);
  • CompleteDealUseCase(id, and many another params);
  • CancelDealUseCase(id, amercement, reason);
  • ChangePriceUseCase(id, newPrice, reason);
  • ChangeCompletionDateUseCase(id, newDate, amercement, whyChanged);
  • etc(total 20 use cases)...

What are the solutions?

1) Use verbs:

PUT /rest/{version}/deals/{id}/hold
{ 
   'reason': 'test'
}

But! Verbs can not be used in the url(in REST theory).

2) Use the completed state(which will be after the the use case):

PUT /rest/{version}/deals/{id}/holded
{ 
   'reason': 'test'
}

Personally for me it looks ugly. Maybe I'm wrong?

3) Use 1 PUT request for all operations:

PUT /rest/{version}/deals/{id}
{ 
   'action': 'HoldDeal',
   'params': {'reason': 'test'}
}

PUT /rest/{version}/deals/{id}
{ 
   'action': 'UnholdDeal',
   'params': {}
}

It is difficult to handle in the backend. Moreover, it is difficult to document. Since 1 action has many different variants of requests, from which is already dependent on specific responses.

All solutions have significant drawbacks.

I have read many articles about the REST on the internet. Everywhere only a theory, how to be here with my specific problem?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I have read many articles about the REST on the internet.

Based on what I see here, you really need to watch at least one of Jim Webber's talks on REST and DDD

But what to do with the rest of the use cases?

Ignore the API for a moment - how would you do it with HTML forms?

You'd presumably have a web page the presents a representation of Deal, with a bunch of links on it. One link would take you to the HoldDeal form, and another link would take you to the ChangePrice form, and so on. Each of those forms would have zero or more fields to fill in, and the forms would each post to some resource to update the domain model.

Would they all post to the same resource? Perhaps, perhaps not. They would all have the same media type, so if they were all posting to the same web endpoint, you would have to decode the content on the other side.

Given that approach, how do you implement your system? Well, the media type wants to be json, based on your examples, but there really isn't anything wrong with the rest of it.

1) Use verbs:

That's fine.

But! Verbs can not be used in the url(in REST theory).

Um... no. REST doesn't care about the spelling of your resource identifiers. There's a bunch of URI best practices that claim that verbs are bad - that's true - but that's not something that follows from REST.

But if people are being so fussy, you name the endpoint for the command instead of the verb. (ie: "hold" isn't a verb, it's a use case).

Use 1 PUT request for all operations:

Honestly, that one isn't bad either. You won't want to share the URI though (because of the way the PUT method is specified), but use a template where the clients can specify a unique identifier.

Here's the meat: you are building an API on top of HTTP and HTTP methods. HTTP is designed for document transfer. The client gives you a document, describing a requested change in your domain model, and you apply the change to the domain (or not), and return another document describing the new state.

Borrowing from the CQRS vocabulary for a moment, you are posting commands to update your domain model.

PUT /commands/{commandId}
{ 
   'deal' : dealId
   'action': 'HoldDeal',
   'params': {'reason': 'test'}
}

Justification - you are putting a specific command (a command with a specific Id) into the command queue, which is a collection.

PUT /rest/{version}/deals/{dealId}/commands/{commandId}
{ 
   'action': 'HoldDeal',
   'params': {'reason': 'test'}
}

Yeah, that's fine too.

Take another look at RESTBucks. It's a coffee shop protocol, but all of the api is just passing small documents around to advance the state machine.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...