Enterprise Architecture
- Components
- Enterprise Architecture
Enterprise Architecture
Design
URI Format
URI = scheme "://" authority "/" path [ "?" query ] ["#" fragment "]
Rules for URI formatting
A forward slash / is used to indicate hierarchical relationship between resources
A trailing forward slash / should not be included in URI's
Hyphens - should be used to improve readability
Underscores _ should not be used (in the address bar of a browser the underscore could be hard to see)
Lowercase letters are preferred - the path part of the URI is case sensitive and could lead to problems
Ensure that the URI is easy to read and construct.
URI Path Design for REST Services
Paths are be broken into documents, collections, stores and controllers
Collections
A collection is a directory of resources typically broken by parameters to access and individual document i.e.
GET /cars → All cars in the collection
GET /cars/1 → Single document for cars (in a collection)
Use a plural noun to define a collection
Documents
A document is a resource pointing to a single object (think of a row in a database) i.e.
GET /cars/1 → single document for car 1
GET /cars/1/engines → All engines used for car 1
GET /cars/1/engines/1 → Engine 1 for car 1
Controller
A controller resource is like a procedure, this is used when a resource cannot be mapped to a CRUD function
The names for controllers appear as the last segment in a URI path with no child resources.
If the controller requires parameters, these would typically be included in the query string:
POST /cars/1/fuel → refuel car 1
POST /cars/1/fuel?type=diesel → refuel car 1 with diesel
When defining a controller name always use a verb - indicating an action or a state of being
Store
A store is a client managed resource repository, it allows the client to add, retrieve and delete resources
A store will never generate a new URI it will use the one specified by the client. i.e.
PUT /cars/{id}
Add a new car to the store with a specific ID. If an id is not specified a response would need to include a reference to the newly
created document. Always use a plural noun for store names
CRUD function names
When designing great REST URIs we never use a CRUD function name as part of the URI, instead we use the HTTP verb i.e.
DELETE /cars/1234
Never include the verb in the URI as follows
DELETE /deleteCars/1234
Use the HTTP verbs
- GET
- POST
- PUT
- PATCH
- DELETE
- HEAD
- OPTIONS
URI query design
It is perfectly acceptable to use a query string as part of an API call; however, I would
refrain from using this to pass data to the service. Instead the query should be used to
perform actions such as:
- Paging
- Filtering
- Sorting
If we need to make a call to a controller, we discussed earlier that we should use a POST
request as this is most likely a non-idempotent request.
Response Codes
Always use HTTP status codes to indicate to the client the success or failure of the request.
Consider the following bad practice:
POST /cars
RESPONSE HTTP 200 OK
{
""status":": 401,
""statusMessage": "": "Bad Request""
}
Successful request:
POST /cars
RESPONSE HTTP 201 CREATED
{
""status":": 201,
""statusMessage": "": "Created",",
""car":": {
"id": "": "1234334dffdf23",",
""name": "": "Ferrari 488""
}
}
Always include status code and status message.
Use the following list of status codes
2xx Success
2xx status codes indicate that the clients request has been successfully received and
understood.
200 OK
This is a generic response code indicating that the request has succeeded. The response
accompanying this code is generally:
GET: An, an entity corresponding to the requested resource
HEAD: The, the header fields corresponding to the requested resource without the message body
POST: An, an entity describing or containing the result of the action
201 Created
The created response is sent when a request succeeds and the result is that a new entity has been created. Along with the response it is common that the API will return a Location header with the location of the newly created entity:
201 Created
Location: https://api.cars.com/v1/cars/123
It is optional to return an object body with this response type.
204 No Content
This status informs the client that the request has been successfully processed; however, there will be no message body with the response. For example, if the user makes a DELETE request to the collection then the response may return a 204 status.
3xx Redirection
The 3xx indicate class of status codes indicates that the client must take additional action to complete the request. Many of these status codes are used by CDNs and other content redirection techniques, however, code 304 can exceptionally useful when designing our APIs to provide semantic feedback to the client.
301 Moved Permanently
This tells the client that the resource they have requested has been permanently moved to a different location. Whilst this is traditionally used to redirect a page or resource from a web server it can also be useful to us when we are building our APIs. In the instance that we rename a collection we could use a 301 redirect to send the client to the correct location. This however should be used as an exception rather than the norm. Some clients do not implicitly follow 301 redirect and implementing this capability adds additional complexity for your consumers.
304 Not Modified
This response is generally used by a CDN or caching server and is set to indicate that the response has not been modified since the last call to the API. This is designed to save bandwidth and the request will not return a body, but will return a Content-Location
and Expires header.
4xx Client Error
In the instance of an error caused by a client, not the server, the server will return a 4xx response and will always return an entity that gives further details on the error.
400 Bad Request
This response indicates that the request could not be understood by the client due to a malformed request or due to a failure of domain validation (missing data, or an operation that would cause invalid state).
401 Unauthorized
This indicates that the request requires user authentication and will include a WWW- Authenticate header containing a challenge applicable to the requested resource. If the user has included the required credentials in the WWW-Authenticate header, then the response should include an error object that may contain relevant diagnostic information.
403 Forbidden
The server has understood the request, but is refusing to fulfill it. This could be due to incorrect access level to a resource not that the user is not authenticated. If the server does not wish to make the fact that a request is not able to access a resource due
to access level public, then it is permissible to return a 404 Not found status instead of this response.
404 Not Found
This response indicates that the server has not found anything matching the requested URI. No indication is given of whether the condition is temporary or permanent. It is permissible for the client to make multiple requests to this endpoint as the state may
not be permanent.
405 Method Not Allowed
The method specified in the request is not allowed for the resource indicated by the URI. This may be when the client attempts to mutate a collection by sending a POST, PUT, or PATCH to a collection that only serves retrieval of documents.
408 Request Timeout
The client did not produce a request within the time that the server is prepared to wait. The client may repeat the request without modification at a later time.
5xx Server Error
Response status codes within the 500 range indicate that something has gone "Bang", the server knows this and is sorry for the situation. The RFC advises that an error entity should be returned in the response explaining whether this is permanent or temporary and containing an explanation of the error. When we look at our chapter on security we will look at the recommendation about not giving too much information away in error messages as this state may have been engineered by a user in the
attempt to compromise your system and by returning things such as a stack trace or other internal information with a 5xx error can actually help to compromise your system. With this in mind it is currently common that a 500 error will just return something very generic.
500 Internal Server Error
A generic error message indicating that something did not go quite as planned.
503 Service Unavailable
The server is currently unavailable due to temporary overloading or maintenance. There is a rather useful pattern that you can implement to avoid cascading failure in the instance of a malfunction in which the microservice will monitor its internal state and in the case of failure or overloading will refuse to accept the request and immediately signal this to the client. We will look at this pattern more in chapter xx; however, this instance is probably where you will be wanting to return a 503 status code. This could also be used as part of your health checks.
Versioning APIs
API versioning is something you should think about from the very beginning and avoid as long as you can. In general, you will need to make changes to your API, however, having to maintain n different versions can be a royal pain in the backside, so doing the upfront design thinking at the beginning can save you a whole load of trouble. Before we look at how you can version your API, which is quite straightforward let's look at when you should version.
You would increment your API version number when you introduce a breaking change.
Breaking changes include:
- Removing or renaming APIs or API parameters
- Changing the type of an API parameter, for example, from integer to string
- Changes to response codes, error codes, or fault contracts
- Changes to the behavior of an existing API
- Things that do not involve a breaking change include:
- Adding parameters to a returned entity
- Adding additional endpoints or functionality
- Bug fixes or other maintenance that does not include items in the breaking changes list
Semantic versioning
Microservices should implement the Major versioning scheme. Quite often, designers will elect to only implement a Major version number and imply .0 for the minor version as according to the semantic versioning principles http://semver.org a Minor version would generally indicate the addition of functionality that has been implemented in a backwards compatible way. This could be adding additional endpoints to your API. It can be argued that since this would not affect the client's ability to interact with your API you should not worry about Minor versions and only concentrate on major as the client will not need to request a particular version without these additions in order to function.
When versioning APIs I think it is cleaner to drop the minor version and only concentrate on major version. We would take this approach for two reasons:
The URI becomes more readable, and dots are only used as network location separators. When using an RPC API dots are only used to separate API.VERSION.METHOD and make everything easier to read.
We should be inferring through our API versioning that change is a big thing andhas an impact on the function of the client. Internally we can still use Major.Minor; however, this does not need to be something to the client as they will not have the capability to elect to use minor versions of the API.
Versioning formats for REST APIs
To allow the client to request a particular API version, there are three common ways you
can do this.
- It can be done as part of the URI https://myserver.com/v1/helloworld
- It can also be done as a query string parameter https://myserver.com/helloworld?api-version=1
- Finally, It can be done by using a custom HTTP header GET https://myserver.com/helloworld
api-version: 2
Whichever way you implement versioning is up to you and your team, but it should play a big part in your upfront design thinking. Once you have decided on an option stick, to it as providing a consistent and great experience for your consumers should be one of your primary goals.