regaez / grav-plugin-api Goto Github PK
View Code? Open in Web Editor NEWA REST API plugin for GravCMS
License: MIT License
A REST API plugin for GravCMS
License: MIT License
Change PageResource
and PageCollectionResource
to extend the new Resource
and CollectionResource
abstract classes, respectively.
This should result in less code duplication since all the resources currently share functions that behave similarly.
The blueprints.yaml
file needs to be updated to allow for configuration of the plugin via the form interface.
At the moment, only the attributes which are included by default (api.yaml
specifies limited fields) are shown in the API specification file. The specification should be updated to include all possible attributes.
This way, people will know which values are valid to add to the fields
array within the /pages
configuration object.
Document development procedures, such as:
This should assist with knowledge transfer for anyone looking to contribute to the plugin's development.
The GET /config
endpoint should change to GET /configs
to match the other endpoints format.
It currently returns a non-standard response when compared to the /users
or /pages
endpoint.
It should be changed to return:
{
"items": [], // an array containing ConfigResource objects
"meta": {
"count": 4
}
}
And a ConfigResource
should also be shaped in such a way:
{
"type": "config",
"id": "api",
"attributes": {
// actual config settings
},
"links": {
"related": {
"self": "http://localhost:8080/api/config/site"
}
}
Requests must provide valid authentication details for the user
information they are attempting to update. For example, Alice should not be able to edit details about Bob.
The GET /plugins
endpoint currently returns a non-standard response when compared to the /users
or /pages
endpoint.
It should be changed to return:
{
"items": [], // an array containing PluginResource objects
"meta": {
"count": 7
}
}
And a PluginResource
should also be shaped in such a way:
{
"type": "plugin",
"id": "api",
"attributes": {
"enabled": true,
// other plugin config settings
},
"links": {
"related": {
"self": "http://localhost:8080/api/plugins/api"
}
}
The children
property should be moved out of the PageResource attributes
and added to the links
hypermedia.
For example:
"links": {
"self": "http://localhost:8080/parent-page",
"children": [
"http://localhost:8080/parent-page/child-1",
"http://localhost:8080/parent-page/child-2"
],
"related": {
"self": "http://localhost:8080/api/pages/parent-page",
"children": [
"http://localhost:8080/api/pages/parent-page/child-1",
"http://localhost:8080/api/pages/parent-page/child-2"
],
"resource": "http://localhost:8080/api/pages/"
}
}
Similarly, a child
page should have a parent
link:
"links": {
"self": "http://localhost:8080/parent-page/child-1",
"parent": "http://localhost:8080/parent-page",
"related": {
"self": "http://localhost:8080/api/pages/parent-page/child-1",
"parent": "http://localhost:8080/api/pages/parent-page",
"resource": "http://localhost:8080/api/pages/"
}
}
Similarly, a child
page should have a siblings
field for pages at the same level:
"links": {
"self": "http://localhost:8080/parent-page/child-1",
"parent": "http://localhost:8080/parent-page",
"siblings": [
"http://localhost:8080/parent-page/child-2"
],
"related": {
"self": "http://localhost:8080/api/pages/parent-page/child-1",
"parent": "http://localhost:8080/api/pages/parent-page",
"siblings": [
"http://localhost:8080/api/pages/parent-page/child-2"
],
"resource": "http://localhost:8080/api/pages/"
}
}
If the config setting enabled
is false, then the entire API should be disabled.
Currently, the /api
route will show links to all endpoints. This should be changed so it only returns enabled endpoints.
{
"page": "http://localhost:8080/api/pages/",
"user": "http://localhost:8080/api/users/",
"plugin": "http://localhost:8080/api/plugins/",
"config": "http://localhost:8080/api/configs/"
}
If you only have the page
resource type enabled:
{
"page": "http://localhost:8080/api/pages/"
}
We should create a docs/AUTHENTICATION.md
file which explains the following:
Basic
auth.htaccess
workaroundI noticed that in some of the file there are use
statements importing classes which are not actually used. These should be removed.
When calling GET /api/users
there is an error:
Message: array_merge(): Argument #2 is not an array
From src/Handlers/UsersHandler.php on line 41
At the moment, you can make a PATCH
or POST
request and set a page to use a non-existent page template. This would cause a twig rendering error and break the page.
We should validate that the template can be used (based on the currently active theme?) when attempting to change this, and throw a 400 Bad Request
if the new template is invalid.
Add a docs/specification.yaml
file documenting the current plugin's API specification as per OpenAPI 3.0.2 standards.
Change UserResource
and UserCollectionResource
to extend the new Resource
and CollectionResource
abstract classes, respectively.
This should result in less code duplication since all the resources currently share functions that behave similarly.
Create a PATCH /plugins/{id}
authenticated endpoint that allows an admin to change a plugin's settings.
The GravApi\Config\Config
class is instantiated in a non-sensical way: the api.php
class passes $settings
to the GravApi\Api
class, which then passes this to create a new Config::instance($settings)
.
This is entirely unnecessary since we could just use Grav::instance()
in the Config
constructor to get the required plugin config information, thereby removing the need to pass $settings
.
Also, Config
is currently causing problems with the AuthMiddleware
because it has a mix of array
and stdClass
for some reason. Therefore, in the middleware, the $this->config–>auth
check is not reliable due to not handling these different types. Creating some Settings
classes to standardise the structure and some functions to access could simplify the AuthMiddleware
and greatly improve the reliability of the configuration info.
Not to mention that this config file is able to be manipulated by users, so could be imported with an invalid format!
Note: issue #34 could be resolved as part of this one, too.
Perhaps the UserResource object should not expose fields such as access
or state
... unless the request is authenticated for that user, or an admin?
We currently always filter out hashed_password
so that it is not exposed publicly.
The API should return a 404 response for any paths requests with the /api
route that don't exist, rather than displaying Grav's HTML 404 page.
For example, https://www.mysite.com/api/some-undefined-endpoint
should return something like:
HTTP Status: 404
Content-Type: application/json
{
"message": "API endpoint not found",
"documentation": "https://github.com/regaez/grav-plugin-api/tree/master/docs"
}
Create a PATCH /configs/{id}
endpoint that allows an authenticated user to change a config settings.
When you create a new page "test", there is currently no way to define its folder prefix/page order, e.g. pages/03.test
. It will only create pages/test
.
This means that a new page doesn't automatically show up in navigation for themes relying on page ordering.
Twig variables/functions are not rendered correctly when updating or creating a new page.
{
"route": "/test",
"template": "default",
"header": {
"custom_field": "WORLD"
},
"content": "HELLO {{page.header.custom_field}}!"
}
"content": "<p>HELLO {{page.header.custom_field}}!</p>"
"content": "<p>HELLO WORLD!</p>"
It would be useful to be able to fetch pages by taxonomy filtering.
The plugin is currently not available through the Grav Repository and therefore also not through the GPM. Adding it requires some small extra steps in this repository which can be found here: https://learn.getgrav.org/16/advanced/grav-development#theme-plugin-release-process
How should the API manage site media? Should there be another endpoint that will allow uploading/deleting images etc?
Need to investigate how Grav internally handles media.
There should be some documentation written on the various fields in the plugin's api.yaml
file, explaining what each one does and how you can configure the plugin.
This should be explained in a docs/CONFIGURATION.md
file.
I'm planning to use this project in my application, What is the status of this project? Is it still being maintained?
Currently, we only have Basic
authentication type available to secure the API. There is an OAuth login plugin which allows authentication with several different providers.
It could be valuable to investigate whether or not we can integrate with this plugin to allow authentication of API request using Bearer
type and an OAuth access token.
It is possible to define custom fields in a user account in Grav. If you add a custom field to the fields filter list in api.yaml
config, then you can return the values of the custom fields in the UserResource
response. They will be null
if not set.
However, we only allow to set/update specific fields, such as title
, fullname
, state
, access
, email
, groups
, etc.
The UsersHandler
class should be extended to allow these custom fields to be set on the UserResource
.
Expose an authenticated endpoint, POST /plugins
which allows an admin to install a new plugin on the site.
Required fields:
id
: the "plugin name" as per GPMThey also have the option of providing an attributes
field which will be applied after the installation of the plugin. If not provided, then the plugin will use its default configuration.
{
"id": "{{plugin_name}}",
"attributes": {
// some initial configuration settings
"enabled": false
}
}
The API could trigger custom events, such as:
onApiPageGet
onApiPageCreate
onApiPageUpdate
onApiPageDelete
onApiUserCreate
onApiUnauthorisedRequest
... etc
These could be very useful to allow easy communication back to Grav\Plugin\GravApi
, in order to trigger some specific plugin actions after an Api event. Perhaps even for external plugins to hook into, such as the Admin plugin exposes, to allow 3rd party extensions over the API.
For example, onApiPageGet
might be a useful hook if you wanted to add a tracking plugin to monitor API traffic, or maybe onApiPageUpdate
if you want to bust the cache when a page is updated.
At the moment, the API handles the request and then the plugin immediately calls exit, stopping any further execution by Grav. This would probably need to change, to allow any other plugins to tap into the custom events.
Investigate into setting up something like CircleCI or Travis CI to build and validate each PR against the test suite before allowing to merge, in order to help prevent any broken master
branch state.
Need to write more tests first though!
Add a postman collection json
export file to the docs section, in order to easily be able to share/load all the possible API endpoint requests and their respective configurations.
Perhaps the setFilter
function could be moved into the abstract Resource
class and made to be generic, so it's not repeatedly defined in all the different resource types, e.g.
protected function setFilter()
{
$filter = Config::instance()->{$this->getResourceType()}->get->fields;
if (!empty($filter)) {
$this->filter = $filter;
}
}
Then would need to adjust mapping so that getResourceType()
returns the correct value for the config... currently would return user
not users
etc
Hi, now if auth: true
all users with access can post, patch and delete pages. Is it complicated to provide different permissions for users and groups for page taxonomies? For example, the blogger group can add/edit/delete only pages with {'@taxonomy':{'category': 'blog'}
.
Thanks
Currently, there is no way to upload media such as images/pdfs etc to a page. A separate resource could be useful to separate the media from the page's data. Perhaps an endpoint such as:
POST /api/media
, orPOST /api/images
, orPOST /api/data
The current config setup doesn't easily allow for configuring nested endpoints. For example, if we have POST /api/pages/searches
, currently there are only config exposed for the methods for /api/pages
. But we don't want to use the POST config, because that gives permissions to allow a user to create a new resource, when a search action is actually reading existing pages data, so it's actually more suitable to be a GET request.
Using a GET config in the code for a POST request is potentially confusing. Perhaps it would be better to rename the endpoint config to be use case (read/create/update/delete) rather than method (get/post/patch/delete).
Or perhaps the config should support nested endpoints within an endpoint config, e.g.
endpoints:
/pages:
get:
enabled: true
auth: false
endpoints:
/searches:
post:
enabled: false
auth: false
Only authenticated users with valid admin
privileges should be able to change a user's access rights.
The readme file is currently the default template for a Grav plugin. It needs to be updated with more relevant information.
Need to figure out the best way to get/create/modify a modular page. Currently, the /pages
endpoint only really supports non-modular...
Setup xdebug
in the docker image and expose the debugging port so we can connect and debug the application from VSCode.
The following error message is output when trying to run the PageResourceTest::testGetResourceAttributesReturnsPageData()
function:
[UnexpectedValueException] RecursiveDirectoryIterator::__construct():
Unable to find the wrapper "theme" - did you forget to enable it when you configured PHP?
The app pulls a string array from the plugin config, which is editable by the user. This could therefore be malformed and not what is expected. This should be validated first and any unsuitable values should be discarded.
Should the whole filter be discarded, or just the "incorrect" values? Leaning towards retaining a partial filter, rather than returning all Resource attributes if only one filter field is incorrect.
Add a Zappr config to add extra checks for PRs. This should help standardise contributions' format, if any ever happen.
At the moment, PageResource
assumes it is returning an image media object. This should be extended to handle any type of supported media.
There is an issue in Grav causing the UserResource
tests to fail. Once getgrav/grav#2620 is resolved and released, then the version of Grav should be updated and the tests uncommented.
There needs to be tests written to cover the functionality of:
PagesHandler
UsersHandler
ConfigHandler
PluginsHandler
It could be nice to allow the ability to specify roles for the API endpoints from within the plugin config.
For example, a user might require the admin.super
role in order to be able to use DELETE /pages
, but does not require any role to use GET /pages
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.