... | @@ -6,6 +6,7 @@ This document governs best practices for writing CFML for inLeague applications |
... | @@ -6,6 +6,7 @@ This document governs best practices for writing CFML for inLeague applications |
|
|
|
|
|
1. [Function Architecture: Handlers, Services, Models](#function-architecture)
|
|
1. [Function Architecture: Handlers, Services, Models](#function-architecture)
|
|
2. [Writing API Endpoints](#writing-api-endpoints)
|
|
2. [Writing API Endpoints](#writing-api-endpoints)
|
|
|
|
3. [Documenting API Endpoints](#documenting-api-endpoints)
|
|
|
|
|
|
## Function Architecture
|
|
## Function Architecture
|
|
|
|
|
... | @@ -152,4 +153,29 @@ This approach leverages `constraints` on a domain object, but pulls those constr |
... | @@ -152,4 +153,29 @@ This approach leverages `constraints` on a domain object, but pulls those constr |
|
|
|
|
|
The content of a single Coldbox event should be as short as possible to achieve the desired results. This is an area of concern for **DRY**: If there is a significant amount of business logic going on, that should take place in a model or service layer and not the API handler, unless it is absolutely, positively certain that the business logic will only ever be used in one place. Even then, envision a subsequent version of your API: if you wanted to take your endpoint and update it from **v1** to **v2**, you would ideally only concern yourself with writing the changes in business logic in the **v2** endpoint. If you would have to replicate a lot of unchanged code from your **v1** handler, probably that portion should have gone into a service layer (whether on a model object or a separate service object).
|
|
The content of a single Coldbox event should be as short as possible to achieve the desired results. This is an area of concern for **DRY**: If there is a significant amount of business logic going on, that should take place in a model or service layer and not the API handler, unless it is absolutely, positively certain that the business logic will only ever be used in one place. Even then, envision a subsequent version of your API: if you wanted to take your endpoint and update it from **v1** to **v2**, you would ideally only concern yourself with writing the changes in business logic in the **v2** endpoint. If you would have to replicate a lot of unchanged code from your **v1** handler, probably that portion should have gone into a service layer (whether on a model object or a separate service object).
|
|
|
|
|
|
Remember: **Fat models, skinny handlers.** |
|
Remember: **Fat models, skinny handlers.**
|
|
\ No newline at end of file |
|
|
|
|
|
## Documenting API Endpoints
|
|
|
|
|
|
|
|
inLeague uses [cbSwagger](https://forgebox.io/view/cbswagger) for API documentation according to the OpenAPI standard. API routes are documented in Javadoc-style "blocks" above the handler function definition, e.g.
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* /api/v1/contentChunk GET (ID)
|
|
|
|
* @hint Retrieve a content chunk by chunkID. Overrides are applied automatically unless explicitly disabled.
|
|
|
|
* @param-chunkID { "schema":{ "type":"integer" }, "in":"path", "description" : "Integer Chunk ID to retrieve." }
|
|
|
|
* @param-override { "schema":{ "type": "boolean", "default" : true }, "in" : "query", "description" : "Applies client overrides if they exist." }
|
|
|
|
* @param-obeyDates { "schema" : { "type" : "boolean", "default" : true }, "in" : "query", "description" : "If false, ignores content embargo dates. Requires inLeague authorization." }
|
|
|
|
* @responses ~contentChunk/get.response.yml
|
|
|
|
*/
|
|
|
|
|
|
|
|
public function show( event, rc, prc ) {
|
|
|
|
... function definition
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
1. The first comment line is not visible in the docs; it is purely an in-line comment for developers reading the handler code.
|
|
|
|
2. The @hint comment is displayed in the header for the endpoint documentation.
|
|
|
|
3. The request structure for many simple GET requests may be described in-line (as in this example) as opposed to an external schema definition using the `@requestBody` declaration. Any request with a real "body" (e.g. PUT, POST) should use `@requestBody`.
|
|
|
|
4. When describing parameters in-line, they still must conform to the syntax above to specify whether the parameter is in the path (`/foo/{GUID}`) or a query parameter (`/foo?someID={GUID}`)
|
|
|
|
5. External schemas are located in the `/resources/api` folder and grouped in subfolders according to the parent domain object. They should be written in YAML (not JSON, whenever possible) and re-used -- do not repeat schema definitions. |