Closed ayeshLK closed 3 weeks ago
With the above proposal, openapi-tool generates the following service type with all the HTTP annotation details:
@http:ServiceContractConfig {
basePath: "/socialMedia"
}
@http:ServiceConfig {
auth: [
{
fileUserStoreConfig: {},
scopes: ["admin"]
}
]
}
public type Service service object {
*http:ServiceContract;
@http:ResourceConfig {
name: "users"
}
resource function get users() returns socialMedia:User[]|error;
@http:ResourceConfig {
name: "user",
linkedTo: [
{name: "user", method: http:DELETE, relation: "delete-user"},
{name: "posts", method: http:POST, relation: "create-posts"},
{name: "posts", method: http:GET, relation: "get-posts"}
]
}
resource function get users/[int id]() returns @http:Payload {mediaType: "application/org+json"} socialMedia:User|socialMedia:UserNotFound|error;
@http:ResourceConfig {
name: "users",
linkedTo: [
{name: "user", method: http:GET, relation: "get-user"},
{name: "user", method: http:DELETE, relation: "delete-user"},
{name: "posts", method: http:POST, relation: "create-posts"},
{name: "posts", method: http:GET, relation: "get-posts"}
]
}
resource function post users(socialMedia:NewUser newUser) returns http:Created|error;
@http:ResourceConfig {
name: "user"
}
resource function delete users/[int id]() returns http:NoContent|error;
@http:ResourceConfig {
name: "posts"
}
resource function get users/[int id]/posts() returns socialMedia:PostWithMeta[]|socialMedia:UserNotFound|error;
@http:ResourceConfig {
name: "posts",
linkedTo: [
{name: "posts", method: http:POST, relation: "create-posts"}
]
}
resource function post users/[int id]/posts(socialMedia:NewPost newPost) returns http:Created|socialMedia:UserNotFound|socialMedia:PostForbidden|error;
};
The implementation will look like this: (The service type is imported via a separate package, the service type can be in the same package as well)
service socialMedia:Service "/social-media" on new http:Listener(8080) {
resource function get users() returns socialMedia:User[]|error {
return [];
}
resource function get users/[int id]() returns socialMedia:User|socialMedia:UserNotFound|error {
return {id: 1, name: "John Doe", email: "johndoe@gmail.com"};
}
resource function post users(socialMedia:NewUser newUser) returns http:Created|error {
return http:CREATED;
}
resource function delete users/[int id]() returns http:NoContent|error {
return http:NO_CONTENT;
}
resource function get users/[int id]/posts() returns socialMedia:PostWithMeta[]|socialMedia:UserNotFound|error {
return [];
}
resource function post users/[int id]/posts(socialMedia:NewPost newPost) returns http:Created|socialMedia:UserNotFound|socialMedia:PostForbidden|error {
return http:CREATED;
}
}
In the above service declaration,
So for this service declaration, the openapi should be generated from the service type rather than the service declaration. Please note that the service type is a subtype of http:ServiceContract
, this makes sure that the normal service types are not going to break with the changes. So, we should only generate the OAS from the service type which is a subtypes of http:ServiceContract
The HTTP related changes are WIP in this branch: https://github.com/ballerina-platform/module-ballerina-http/tree/service-type-support
You can use this timestamped version for testing: 2.11.1-20240607-135600-e67eb21
The current open-api spec generation is using the compiler syntax tree. But when we use a service contract type, we cannot access the syntax tree if the service type is outside the package (having service type in a separate package is a use case).
Even though we implement a generator using the semantic model, it is not possible for get the values of annotations using the existing APIs since the annotations are not constant.
If we consider the idea behind the service contract, then we actually know the open-api spec from the type itself. So, the open-api tool should be able to generate a spec from the service type as well(This is a non-goal of the proposal). If that is possible, we can actually generate and embed the open-api spec into the service contract type and whenever we need a open-api spec from the service implementation using a service contract type, we should be able to get it directly from the type.
This approach has two major issues:
We are planning to utilise the static resources rather than constant annotations. We need APIs to read and write the resources at compile time, this issue has been tracked via https://github.com/ballerina-platform/ballerina-lang/issues/43041
Description:
Related to proposal: #6378