Cqrs api v2
-
Upload
brandon-mueller -
Category
Technology
-
view
400 -
download
5
Transcript of Cqrs api v2
Panhandle Web Techhttp://www.meetup.com/Panhandle-Web-Tech/
6:30 on the Third Tuesday of the Month@ Firebrand Media229 East Martin St, Suite 5Martinsburg, WV 25401
What is covered
● API Basics● API Good Practices● CRUD API Examples● Commanding API Explained● Commanding API Examples● CRUD and Commanding Coexistence
What is NOT covered
● Security or Authentication● HAL or HATEOAS● CQRS* or DDD*● Nitty-Gritty Implementation Details
● The farm is a home to people, places and things. These are the nouns in your API
● Nouns are also called resources or entities.● The nouns are represented in your API by the URL.● Like things inside of your farm, you can do things with
your resources.● You tell your nouns to do things via verbs. ● The HTTP spec come with built in verbs, among these
are GET, PUT, POST, and DELETE● These verbs are great for CRUD functionality.
Your API is Like a Farm
HTTP verb Resource URL Explanation
POST /barns Creates a new barn
GET /barns Gets all the barns on the farm
GET /barns/11 Gets the barn with the ID of 11
PUT /barns/11 Updates the barn with the ID of 11
DELETE /barns/11 Deletes the barn with the ID of 11
C
R
UD
Some Good Ideas to Follow:1. ALWAYS use plural nouns - keeps it simple2. Nest resources!
/barns/30/animals
/barns/30/stables/1/animals
3. Handle errors with a standardized response body4. Use the standard HTTP verbs5. Use appropriate HTTP headers6. Use appropriate HTTP response codes
Read The Spec
Status Codes: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.htmlHeaders: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
Status Codes In a Nutshell
● 2xx - It worked● 3xx - Go away● 4xx - The client messed up● 5xx - The server messed up
Idempotent/Safe Methods
Idempotent methods can be applied over and over again and always have the same effect on the resource
Safe methods do not have any modifying effect on the resource
Idempotent/Safe MethodsMethod Idempotent SafeGET YES YES
POST NO NO
PUT YES NO
DELETE YES NO
PATCH NO NO
HEAD YES YES
OPTIONS YES YES
POST v PUT v PATCH
● POST is used to create an entity● PUT is used to update an entity where you
must send the entire representation of the entity as you wish for it to be stored
● PATCH is used to update an entity where you send only the fields that need updated
CRUDy Workflow
Client
Application Server
Client uses HTTP POST, GET, PUT and DELETEVerbs to CREATE, READ, UPDATE and DELETE
Create an Animal$.post({
url: '/api/animals,
data: {
name: 'Bob',
}
});
Server returns “201 created” status and a JSON representation of the newly created street, as well a link to the street{
id: 30,
name: 'Bob',
_links: { self: '/api/animals/30' }
}
Read Animals$.get({
url: '/api/animals,
});
Server returns “200 OK”, and a JSONrepresentation of the streets{
page: 1,
total_pages: 10,
items: [
{id: 30, 'name': 'Bob', _links: { self: '/api/animals/30' },
....
]
}
Update an Animal$.put({
url: '/api/animals/30',
data: {
name: 'Robert'
}
});
Server returns “200 OK” status and aJSON representation of the street,{
id: 30,
name: 'Robert',
_links: { self: '/api/animals/30' }
}
NOTE: Most implementations of the PUT verb require the entire representation of the entity. See HTTP PATCH verb for updating with a partial representation of the entity.
Delete an Animal$.ajax({
type: 'DELETE',
url: '/api/animals/30'
});
Server returns a ‘204 No Content’ status and should not have aresponse body. Any further GET requests to /api/animals/30 should return a ‘404 Not Found’ status
Awesome!● We can create some really awesome APIs
where we can create, read, update, and delete entities in a standard way.
● These standards have lead to some very powerful libraries that can help you create and consume CRUD APIs
Where is the Business Logic?Client
Application Server
Client uses HTTP POST, GET, PUT and DELETEVerbs to CREATE, READ, UPDATE and DELETE
● Sometimes this is what we want● When we create APIs we don’t always know the specific
use case● We just want to expose the data
Business Logic on The Client Side?
● A CRUD API is a really good way to expose meaningful data in a flexible way
● You make few assumptions on how the data will be displayed or used
● Fosters innovation and allows for really interesting clients
Really? Client Side?
● Stopping at CRUD functionality limits what your API can actually do
● Complex business problems should not rely on client side implementations
● Only implementing CRUD functionality can lead to an API that doesn't know what it does, it only knows about the data it stores
Wait, This SUCKS!
How do you go beyond simply creating, reading, updating, and deleting things?● How do you reroof a barn?● Clean a stable?● Castrate a goat?
Commanding API
Take a resources, add a command (verb) to the end, send data for that command in POST HTTP verb
○ POST /barns/11/reroof○ POST /barns/1/stable/2/clean○ POST /goats/133/castrate
Command or Resource?Command Resource
Verb Noun
You can only POST and sometimes GET never PUT or DELETE
All HTTP verbs are OK
Once a command has been submitted, it cannot be removed or updated (read only)
Most resources can be removed or updated
HTTP Verb
Command URL Explained
POST /barns/11/reroof Sends the command to reroof barn 11
GET /barns/11/reroof Meta data about reroof command and barn 11. Maybe the last time it was reroofed, whether or not we are currently reroofing
GET /barns/11/reroof/{cmdID} Meta data about the specific instance of the reroof command
Commands Are NOT First Class Citizens
POST /createBarnPOST /barns
POST /updateBarnPUT /barns/1
POST /cleanBarnPOST /barns/1/clean
Example: Reroof a barn$.post({
url: '/barns/11/reroof'
});Server responds with ‘200 OK’ status, and meta data about the command:{cmd_id: '123e4567-e89b-12d3-a456-426655440000'}
In this example, the command is executed and completed within the lifecycle of the HTTP request.
Wait: That’s Not The Whole Story
We use a Commanding Pattern because we are performing an action on a resource. In the real word, these actions can take time.
Reroof a Barn$.post({
url: '/barns/11/reroof'
});
Server responds with ‘202 Accepted’status, and meta data about thecommand:
{
cmd_id: '123e4567-e89b-12d3-a456-426655440000',
_links: {
status: '/barns/11/reroof/123e4567-e89b-12d3-a456-426655440000'
}
}
Reroof a Barn; Check Status$.get({
url: '/barns/11/reroof/123e4567-e89b-12d3-a456-426655440000'
});
Server responds with ‘200 OK’ status and data about the command{
shingles_complete: 5,
out_of: 1024,
}
Client
Application Server
Client sendsPOST command
Clients Checks Status URL until
complete, updating UI with progress
What About Querying?
● Sometimes a query request cannot be completed in a reasonable amount of time
● Sometimes you have to send a POST payload in order to send enough data for the server to process a query
● This is a special case of a command
Querying$.post({
url: '/chickens/search'
data: {
type: 'heritage'
egg_color: 'blue',
age: 'young'
}
}); Just like a command, we return ‘202 Accepted’ status, and return some meta data:{
cmd_id: '7ecba660-5032-11e4-916c-0800200c9a66',_links: {
results: '/chickens/searchResults/7ecba660-5032-11e4-916c-0800200c9a66',status: '/chickens/search/7ecba660-5032-11e4-916c-0800200c9a66',
}}
Getting Results...If you try to hit the results link before the results are complete:● the server will return the search results in whatever
state it is available● return a ‘203 Non-Authoritative Information’● a link to the status url● and a Retry-After headerUsing this pattern, you can expire content and return the 203 status code to tell the client to refresh the content
Getting Results...HTTP Request
Do we have the
resource?
203 With a Retry After Header And Status URL
200 OK
Has the data expired or still being created?
Check Status
Status
Is it done?
Separating Command and Queries...
Developing expressive and meaningful endpoints...
Using nouns and verbs that reflect what your API
actually does...
Proudly Inspired by Others
CQRS Martin FowlerCQRS stands for Command Query Responsibility Segregation. It's a pattern that I first heard described by Greg Young. At its heart is a simple notion that you can use a different model to update information than the model you use to read information. This simple notion leads to some profound consequences for the design of information systems.
http://martinfowler.com/bliki/CQRS.html
DDD WikipediaDomain-driven design (DDD) is an approach to software development for complex needs by connecting the implementation to an evolving model. The premise of domain-driven design is the following:1. Placing the project's primary focus on the core domain
and domain logic.2. Basing complex designs on a model of the domain.3. Initiating a creative collaboration between technical and
domain experts to iteratively refine a conceptual model that addresses particular domain problems.
http://en.wikipedia.org/wiki/Domain-driven_design
DDD and CQRS in My Own Words...● Domain Driven Design is a philosophy and methodology
in which your domain model should represent the business problems that your app is actually solving
● Command Query Responsibility Segregation is the strategy of separating commands from queries, as opposed to CRUD functionality which is represented in the same object. CQRS can help you follow the SOLID principle
DDD - Know Your Role!
● Talk to stakeholders and domain experts
● Strive for a ubiquitous language● Know the context in which your
API endpoints will be used● Use this knowledge to develop
your endpoints
CRUD API Commanding API
Create a Product POST /products POST /products
Update a Product PUT /products/{id} PUT /products/{id}
Mark Product as Active PUT /products/{id} POST /products/{id}/activate
Describe a Product PUT /products/{id} POST /products/{id}/describe
Order a Product ???? POST /products/{id}/order
Markdown a Product PUT /products/{id} POST /products/{id}/markdown
Review a products POST /products/{id}/reviews POST /products/{id}/review
Mark product as out of stock PUT /products/{id} POST /products/{id}/outOfStock
CRUDy v Commandy
Commands Are NOT First Class Citizens
POST /createBarnPOST /barns
POST /updateBarnPUT /barns/1
POST /cleanBarnPOST /barns/1/clean
CQRS and CRUD Can CoexistPUT or PATCH is just an update command BUT:● Be very selective with what is allowed to be updated● It is not always appropriate to expose update
functionality for a particular object or property● If another command updates a property, updating that
property directly probably shouldn’t be allowedDELETE is a special use case command too