@Getter @Setter // adds getters and setters to all fields
public class ResponseEnvelope<T> {
private int status;
private ResponseVersion version;
private T data;
private String error;
}
The @ApiController annotation, used at the class level, tells the KOS system that this particular class has REST endpoints. In other words, the class has "request" mappings for the HTTP GET/PUT/POST/DELETE methods. The KOS system must know which classes have endpoints, as it uses that information to determine where to dispatch various HTTP requests to.
The following annotations are documented in this article:
@ApiController
@ApiEndpoint
@HandleVariable
@PathVariable
@RequestBody
@RequestParam
@Tracker
In addition, these two intefaces are discussed:
HttpRequest
HttpResponse
As is the class:
ResponseEnvelope
API Endpoints
API endpoints are URLs that act as access points to a software application’s resources. When clients interact with an API, they send an HTTP request to one of these URLs. Those endpoints may accept information, return information, and/or perform some action. |
Some things to note in this article:
All objects are transferred to and from KOS endpoints in JSON format.
All return values are enclosed in a response envelope (see next section).
All "desc" (description) annotation elements are multi-line and Markdown-capable.
All controllers are documented on-the-fly at runtime by hitting the "{base}/openapi" endpoint.
In the documentation regarding URLs, the "{base}" value is either:
http(s)://hostname:port/api/kos
(for a standard app)
http(s)://hostname:port/api/system
(for a system app)
Source code for this and most other Java reference pages is available on GitHub. |
The ResponseEnvelope class encapsulates the response from all KOS HTTP/REST endpoints. These are automatically created by KOS, so you should never have to create one.
ResponseEnvelope
class@Getter @Setter // adds getters and setters to all fields
public class ResponseEnvelope<T> {
private int status;
private ResponseVersion version;
private T data;
private String error;
}
A typical response might then look like, "data" is the payload:
ResponseEnvelope
example{
"status": 200,
"version": {
"major": "1",
"minor": "23"
},
"data": {
"user": {
"firstName": "Fred",
"lastName": "Flintstone"
}
},
"error": null
}
The @ApiController annotation can only be used on classes. The "value" parameter represents the base URL path that all subsequent methods have.
@ApiController
annotation@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiController {
/**
* Base path for mappings.
*/
String base();
/**
* Title of the controller for OpenApi docs.
*/
String title() default "";
/**
* Description of the controller for OpenApi docs.
*/
String desc() default "";
}
@ApiController
example/**
* All endpoint URLs in this class are prefixed with "/mycontroller".
*/
@ApiController(
base = "/mycontroller",
title = "These endpoints related to foo",
desc = "This is a more detailed description.")
public class MyController {
}
The @ApiEndpoint annotation is used on endpoints methods inside an @ApiController class. They specify the endpoint’s URL, HTTP method, description, and optional parameter descriptions.
One of the methods, with URL path, is required, as is the description.
@ApiEndpoint
annotation@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiEndpoint {
/**
* Sets the URL path of the associated GET operation.
*/
String GET() default "";
/**
* Sets the URL path of the associated PUT operation.
*/
String PUT() default "";
/**
* Sets the URL path of the associated POST operation.
*/
String POST() default "";
/**
* Sets the URL path of the associated DELETE operation.
*/
String DELETE() default "";
/**
* Description of the endpoint.
*/
String desc();
/**
* Documents the URL parameters. Name of @Param should match a named parameter
* in the request handler.
*/
Param[] params() default {};
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Param {
/**
* Name of a parameter in the request handler. Name must match
* for the documentation to be displayed.
*/
String name();
/**
* Description of the parameter.
*/
String desc();
}
@ApiEndpoint
example@ApiController(base = "/mycontroller")
public class MyController {
/**
* When "GET {base}/mycontroller/fetch" is hit,
* then this method is called.
*/
@ApiEndpoint(GET = "/fetch", desc = "This is what this endpoint does")
public SomeBeanType fetch() {
// fetch SomeBeanType here and return it
}
}
The @ApiVersion annotation gives you the ability to document each endpoint with a version number. This version information is returned in the payload envelope, so that clients can determine how to process the payload in those cases where the payload changes over time. It can be used on classes and methods.
The version number string is in "major.minor" format. For example, "1.1", "2.17", etc.
All methods without an explicit version number are at version "1.0".
@ApiVersion
example@ApiController(base = "/mycontroller")
public class MyController {
/**
* When "POST {base}/mycontroller/method1" is called,
* this method returns version "1.0" in the payload envelope.
*/
@ApiEndpoint(POST = "/method1", desc = "")
public void method1() {
}
/**
* When "POST {base}/mycontroller/method2" is called,
* this method returns version "4.56" in the payload envelope.
*/
@ApiVersion("4.56")
@ApiEndpoint(PUT = "/method2", desc = "")
public void method2() {
}
}
The @HandleVariable annotation binds a method variable to a bean handle.
@HandleVariable
example@ApiController(base = "/mycontroller")
public class MyController {
/**
* When "GET {base}/mycontroller/br-549" is called,
* the object whose handle is "br-549" is passed in the "bean" variable.
*/
@ApiEndpoint(GET = "/something/{handle}", desc = "")
public void getBean(@HandleVariable("handle") SomeBean someBean) {
// use the someBean object
}
}
The @PathVariable annotation binds a method variable to a path parameter. The method variable must be a common type, such as String, Integer, Long, Float, Double, or Boolean.
In the example below, note:
the multi-line endpoint description, and
a description of the "id" variable using the params = @Param
annotation, which is used to document URL path parameters. See @ApiEndpoint for more info.
@PathVariable
example@ApiController(base = "/mycontroller")
public class MyController {
/**
* When "GET {base}/mycontroller/user/63" is called,
* the method parameter "id" has a value of 63.
*/
@ApiEndpoint(GET = "/user/{id}", desc = """
This is a multi-line description that can go on and on and on.
It can be in Markdown format and can contain blank lines.""",
params = @Param(name = "id", desc = "The unique 6-digit integer"))
public SomeBeanType getBean(@PathVariable("id") Integer id) {
// return
}
}
The @RequestBody annotation indicates that the body of the request should be parsed in an object and made available in the associated method parameter.
@RequestBody
example@ApiController(base = "/mycontroller")
public class MyController {
/**
* When "POST {base}/mycontroller/user/save" is called,
* the method parameter "userBean" is populated from the request's body.
*/
@ApiEndpoint(POST = "/user/save", desc = "")
public void saveUser(@RequestBody UserBean userBean) {
// process userBean object
}
}
The @RequestParam annotation binds a method variable to a query parameter.
In the following, if the input URL is something like http://myserver.com/api/tolower?variable=ThisIsAString
, then the method will return "thisisastring".
@RequestParam
example@ApiController(base = "/mycontroller")
public class MyController {
/**
* When "GET {base}/mycontroller/user/list?order=firstName&limit=10" is called,
* the method parameter "order" contains "firstName", and
* the method parameter "limit" is 10.
* As you can see, "order" is required, but "limit" is not.
*/
@ApiEndpoint(GET = "/user/list", desc = "")
public List<UserBean> listUsers(
@RequestParam(value = "order", required = true) String order,
@RequestParam(value = "limit", defaultValue = 20) Integer limit) {
// process request
}
}
The @ResponseStream annotation indicates that the response is a "raw output stream". Used then when a request method serves content such as a file or other stream of bytes.
@ResponseStream
example@ApiController(base = "/mycontroller")
public class MyController {
/**
* When "GET {base}/mycontroller/file/data.json" is called,
* the method parameter "fileName" contains "data.json".
* The resulting stream of bytes is returned to the httpResponse.getOutputStream().
*/
@ApiEndpoint(GET = "/file/{name}", desc = "")
@ResponseStream
public void serveContent(HttpResponse httpResponse, @PathVariable("name") String fileName) {
// send bytes to the httpResponse's output stream
}
}
The @Tracker annotation binds a method parameter to a special tracker variable. Please read the Javadocs for a more detailed explanation.
@Tracker
example@ApiController(base = "/mycontroller")
public class MyController {
@ApiEndpoint(POST = "/pump/{pump}/start", desc = "")
public void startPump(@HandleVariable("pump") Pump pump, @Tracker String tracker) {
pumpService.start(pump, tracker);
}
}
The HttpRequest interface abstracts out the common request methods used by the KOS system dispatcher.
HttpRequest
interfacepublic interface HttpRequest extends AttributeAware {
String getPath();
RequestMethod getMethod();
InputStream getInputStream() throws IOException;
JsonNode getJsonBody();
String getParameter(String name);
MultiValueMap<String, String> getParameters();
InetSocketAddress getClientAddress();
String getHeader(String name);
Collection<String> getHeaders(String name);
Collection<String> getHeaderNames();
}
HttpRequest
example@ApiController(base = "/mycontroller")
public class MyController {
@ApiEndpoint(GET = "/whatever", desc = "")
public void startPump(HttpRequest httpRequest) {
// use the httpRequest variable
}
}
The HttpResponse interface abstracts out the common response methods used by the KOS system dispatcher.
HttpResponse
interfacepublic interface HttpResponse {
OutputStream getOutputStream() throws IOException;
void setHeader(String name, String val);
void setDateHeader(String name, long date);
int getStatus();
void setStatus(int status);
void sendError(int status) throws IOException;
}
HttpResponse
example@ApiController(base = "/mycontroller")
public class MyController {
@ApiEndpoint(GET = "/whatever", desc = "")
public void startPump(HttpResponse httpResponse) {
// use the httpResponse variable
}
}
This article explained the REST controller API of the KOS SDK.
RESTful API
This following annotations, interfaces, and classes comprise the KOS REST controller API:
|
Next up, we’ll examine how to make RESTful calls using the KOS ApiClient component.