We are currently working at a open peer review platform for preprints. For this we developed a set of 3 plugins for OPS which depend on a custom API:
1. Open Peer Review plugin (not published yet) 1. customMetadata plugin (GitHub - felixhelix/customMetadata) 2. userComments plugin (not published yet)
The first two plugins use an API to allow editing of data in the submission and publication stage, the third one to allow user interaction on the preprint details page.
Both are essential for our open peer review service to work. However, in OPS 3.5 the option to create custom APIs is discontinued.
Describe the solution you’d like Touhidur Rahman already created a proof of concept solution Issues · pkp/pkp-lib · GitHub
Who is asking for this feature? As stated above, the feature is essential for our service to work. The open peer review platform is a project by the University Library of Cologne, funded by the German Research Foundation and realized in cooperation with several associations of social scientists.
This feature/behaviour already exists in the 3.3 and 3.4 release and only been removed in the current main which is upcoming 3.5 . As we refactor all the API routes to use the Laravel routing toolset and removed the Slim framework, the dependent code of this functionality also removed in the current main branch . We had the proof of concept ready immediately but did not find any use case of this functionality, so we did not move forward with it .
After the original forum post at Create API Handler OPS 3.5 which lead to this feature request, we had some discussion within the dev group and quite a few member was interested to bring this back and keep it in the upcoming main . That lead to the decision to bring back and reimplement this functionality which was kind of removed because of a regression.
Thanks @touhidur !
I managed to update our comments plugin, so that the API now works with 4.5 (cherry-picking your commit)
I did not start with updating our other plugins, however, but I think I can apply this procedure to the other plugins as well.
I also found two other plugins, that make use of a custom API:
One question: It seems to me that you can only override / extend an existing API controller, such as user or submission, but not create your own? Or did you just use one of those for simplicity?
One question: It seems to me that you can only override / extend an existing API controller, such as user or submission, but not create your own? Or did you just use one of those for simplicity?
@felixhelix To clarify this part if I understand correctly
What is possible :
Override/Modify an existing api routes on existing entity (e.g. users, submissions, etc) to provide different response or execute different actions . For example, http://BASE_URL/index.php/CONTEXT_PATH/api/v1/users/report provide a report data in CSV format but possible to override that behaviour to get different response or action .
Add one or multiple new route/s on existing entity (e.g. users, submissions, etc) that can handle different actions. For example, the example plugin provide such example like a totally new route on users entity as http://BASE_URL/index.php/CONTEXT_PATH/api/v1/users/testing/routes/add . Note that testing/routes/add does not exist on users entity by default .
What is not possible :
Plugins to have their very plugin specific own routes like http://BASE_URL/index.php/CONTEXT_PATH/plugins/generic/apiExample/api/v1/tests . see that part plugins/generic/apiExample which follows the plugin level convention of PLUGIIN_PREFIX/PLUGIN_CATEGORY/PLUGIN_NAME . We initially have this one included in the initial proof of concept implementation but removed it as it adds a lot of complexity to api router and handler .
If your question related to section What is not possible, then yes, thats not possible right now and removed from initial proof of concept . But if there is any use case which can be highly benefitted from it, we would love to have know about it .
@touhidur Thanks for your detailed reply! Yes, my question related to the section “what is not possible”: If I have a use case for this I will let you know
Yours,
Felix
Hook::add('APIHandler::endpoints::users', function(string $hookName, PKPBaseController $apiController, APIHandler $apiHandler): bool {
$apiHandler->addRoute(
'GET/POST/PUT/PATCH/DELETE', // HTTP Request METHOD
'some/route/path/to/add', // The route uri
function (IlluminateRequest $request): JsonResponse { // The closure/callback of route action handler when the route url got hit
return response()->json([
'message' => 'A new route added successfully',
], Response::HTTP_OK);
},
'name.of.the.route', // Name of the route
[Role::ROLE_ID_..., Role::ROLE_ID_..., ...] // The route accessable role from `Role::ROLE_ID_*`
);
return Hook::CONTINUE;
});
so for now, only can add API routes via injecting into the current routes stack via `$apiHandler->addRoute` but without any authorization policies and that will be available from 3.5.0-2 .
I am helping developing a plugin for OJS 3.5.x and have the same need for a custom API endpoint with sub-endpoints. So in short we would like to have something like api/v1/ourPlugin/someSubRoute/. As far as I understand it here, a very own custom API endpoint like this is not possible to achieve in the current version of OJS 3.5.x. Only something like e.g. api/v1/users/ourPlugin/someSubRoute/ or api/v1/submission/ourPlugin/someSubRoute/.
Before I got to know that this works, I developed a workaround to have our very own API route with a LoadHandler that displays different JSON data on a page, based on what route it was called on. Therefore we are able to have our own API routes like e.g. .../index.php/ourPlugin-api/someSubRoute/. The problem with this workaround is that while it works, we are unsure if we are allowed to use it as it e.g. doesn’t restrict access to specific API routes to specific Roles.
Now for our question. We understand, that having an own API endpoint is not really possible in OJS 3.5.x but we would prefer it over having something like users/ourRoute or submission/ourRoute. We however don’t want to have our plugin criticised in later stages of development for using our own custom API workaround. That’s why we want to decide on which approach we use as soon as possible, as we are still in the early stages of development. Therefore I would like to know if it is good to continue with our own workaround for our own API endpoint or if we should switch to the way it is described in this forum topic and thus use something like users/ourRoute or submission/ourRoute?
doesn’t restrict access to specific API routes to specific Roles.
Using the LoadHandler or the LoadComponentHandler, it should be possible to define role level access restriction, for example see the implementation of plagiarism/controllers/PlagiarismIthenticateHandler.php at main · pkp/plagiarism · GitHub . so I am bit confused why it does not work for you (perhaps I am misunderstanding something or actual use case) .
Therefore I would like to know if it is good to continue with our own workaround for our own API endpoint or if we should switch to the way it is described in this forum topic and thus use something like users/ourRoute or submission/ourRoute
I didn’t know it was possible to define role level access restriction so thank you and I will implement this.
for 3.5, if the LoadHandler or the LoadComponentHandler does not work, it suggest to stick with the conventional API routing approach but must make sure to have the proper authorization policies attached to it.
I understand this as follows: If our workaround with the LoadHandler works then we can continue using it and should only switch to the conventional API routing approach if we run into further issues correct?
Thank you again for taking your time and your reply!
If our workaround with the LoadHandler works then we can continue using it and should only switch to the conventional API routing approach if we run into further issues correct?
that is if need an API route url that does not match for with entity paths like users, submission etc as mentioned .
my suggestion as follow
if need API route and is useable with currently supported entity paths, use that with conventional approach and implementation.
if need API route but does not match with existing entity path or really don’t want to use that , use LoadHandler or the LoadComponentHandler .
for other purpose , use the LoadHandler or the LoadComponentHandler
For API routes, I suggest to stick with No 1 unless it’s really not feasible or really does not match the use case.
Most importantly , make sure that each of the usage case have proper Role/Policy attached to avoid any security/unauthorised issue/access introduced by the plugin .