takes
takes copied to clipboard
Description for a Takes based REST service
I thinking about Takes as a tool for a REST services development. Is there any idea how to generate REST service description and keep it be equal a real REST service ? I need in json/xml format
- uri
- method
- description
- request parameters
- response parameters
- response statuses
- authorization requirements
@dmzaytsev interesting question, but I'm sure I understand it entirely... shall this information be provided in runtime, through some HTTP requests or how?
@dmzaytsev maybe you can give an example of how it's done in other frameworks?
@yegor256 there is a project called Swagger that can dynamically generate documentation from a Swagger-compliant API You can see sample of swagger server and the json api docs I doubt we can generate such json for Takes rest service In case jax-rs it's simple. We have jax-rs annotations + swagger annotations e.q.
@GET
@Path("/{petId}")
@ApiOperation(value = "Find pet by ID", notes = "More notes about this method", response = Pet.class)
@ApiResponses(value = {
@ApiResponse(code = 400, message = "Invalid ID supplied"),
@ApiResponse(code = 404, message = "Pet not found")
})
public Response getPetById(
@ApiParam(value = "ID of pet to fetch", required = true) @PathParam("petId") String petId)
throws WebApplicationException {
I have no idea how to do this with set of Takes classes
@dmzaytsev according to my understanding of RESTful principles, the API should be self-descriptive through INFO
requests. Say, I create a service that lets you book a room in a hotel. This is the request you should make to get a reservation:
POST /rooms/203/book HTTP/1.1
Host: www.example.com
adults=1&nights=2&date=2015-05-23
This is the response you will get:
HTTP/1.1 303 See Other
Location: /rooms/203/bookings/467284
As I understand, this web service should be able to answer to INFO
:
INFO /rooms/203 HTTP/1.1
Host: www.example.com
And we should expect something like this back:
HTTP/1.1 200 OK
Content-Type: text/xml
<endpoints>
<endpoint>
<uri>/book</uri>
<method>POST</method>
<params>
<param>
<name>adults</name>
<type>integer</type>
<description>total number of adults planning to stay</description>
</param>
<param>
<name>nights</name>
<type>integer</type>
... etc ...
</param>
</params>
</endpoint>
</endpoints>
I'm making this up, but I'm sure there is some standard for the format of such response. What do you think?
@yegor256 there are some standarts for a rest service description RSDL, WADL... But they are not so common such as WSDL for SOAP services. Btw the request method INFO not described by any standart as far as I know. But it is not so important. If we have a structured description, we can easily convert it to any format: a Swagger compatible or a INFO-based requests or WADL, RSDL or something else.
I'm talking about simple, maybe partial auto-generate description for a Takes-based rest service. E.g, an endpoint, a method, param names (and maybe param types), response type(I predict some trouble here) we could auto-generate. Maybe we can use some annotations to describe another properties. I think about how it might be and will make an example.
@dmzaytsev I'm thinking about something like this:
new TkExplained(
new Take() {
@Override
public Response act(final Request req) {
return new RsText(
String.format(
"your balance is %d USD",
database.get_balance_of_a_user_by_id(
new RqHref(req).href().param("id").iterator().next()
)
)
);
}
},
"method GET",
"since 0.15.3",
"author [email protected]",
"content_type text/plain",
"query_param id",
"param_type id integer",
"param_constraint id >0",
"purpose 'Get current balance of the user, in US dollars'",
"success 200",
"error 404 'When user ID is not found in the database'",
"error 400 'When user ID provided is not a valid integer'"
)
I'm not sure about the exact meta "language" here, but this is how I see the design... what you think?
@yegor256 I think it should be a Fork implementation something like this
new FkRest(
RqMethod.POST,
Response.TEXT_PLAIN,
'/user/{user}/limit'
new Describe(
new Item (new Describe.Purpose("change daily withdrawal limit for user")
new Item (new Describe.Since("0.15.3")
new Item (new Describe.Author("author [email protected]")
new Item (
new Describe.PathParam("user"),
"user identifier",
Type.Integer,
new Constraint(Lower,1000)
),
new Item (new Describe.QueryParam("new"), "a new daily limit", Type.Money)
new Item (new Describe.Status(200, "success"),
new Item (new Describe.Status(404, "When user ID is not found in the database"),
new Item (new Describe.Status(400, "When user ID provided is not a valid integer"),
new Item (new Describe.Response(Type.Text,"some message"),
new Item (new Describe.Auth(Auth.Basic),
),
new Take() {
@Override
public Response act(final Request req) {
return new RsText(
String.format(
"your balance changed",
database.change_balance_for_user(
new RqHeaders.Rest(req).pathParam("user"),
new RqHeaders.Rest(req).queryParam("new"),
)
)
);
}
}
);
so we get some control over the compliance of the description and the actual service implementation.
@dmzaytsev I get your point, but this structure looks over-complicated to me... we're creating so many objects, but none of them are really objects. they are just holders of meta-information. all they will have is just getters. not a very nice design, in my understanding... it's better to keep it simple and object-less. all we have to do with this meta-information is to translate it into JSON or XML or some other format, right?
@yegor256 I guess FkRest will check the data corresponds to the description at runtime. For example if a Take returns status 500, but it is not in the description, the FkRest tell us about it.
And here this is both the meta information and the route instruction - accepts POST request for this Take
new FkRest(
RqMethod.POST,
Response.TEXT_PLAIN,
Yes, I agree, meta information is not necessarily stored as separate objects
@dmzaytsev well, the idea of a "fork" is that it may return something or may return nothing. In our case, we always have to return something, since there is a "take" we're decorating and it always returns a response. So, conceptually it's wrong to call it a fork (FkRest
), because we will always return a response. That's why I suggested to make it a "take" and call it TkExplained or TkRest if you wish.. But the main question here is what output format we should produce. We have to find a standard for that.
Are you suggest to use one Take for all services? if no how we catch meta info from all TkExplained ?
@dmzaytsev I think that each "take" has to be decorated by its own instance of TkExplained
. how to create a "directory" of all takes? Maybe there has to be a single entry point that returns the description of itself and then a list of other resources available beneath it... we should find out how it's done in RESTful world usually. let's not guess.
@yegor256 another question how we can describe the payload ? It maybe json or xml. The usual approach for this - to create a class which describes the model. But what about if we generate XML/JSON on the fly e.g.
return Json.createObjectBuilder ()
.add ("balance", this.balance)
.build ();
@yegor256 btw the same way we can make a SOAP service, not only REST