The Web Services API
Joomla serves data not only as HTML pages but also through an API — as JSON, for mobile apps and for exchanging data with other systems. The API has its own entry point, api/index.php, and its own third part of a component in the api folder. First we look at the built-in API, then add blog posts to it.
The built-in API
| Request | What it does |
|---|---|
GET /api/index.php/v1/content/articles | The list of articles |
GET /api/index.php/v1/content/articles/1 | One article |
POST /api/index.php/v1/content/articles | Create an article |
PATCH /api/index.php/v1/content/articles/1 | Change an article |
DELETE /api/index.php/v1/content/articles/1 | Delete an article |
The token
API requests are signed with a token. In the panel open your profile (Users → Manage, then your own account), the Joomla API Token tab, and copy the token. The plugins "API Authentication - Web Services Joomla Token" and "User - Joomla API Token" must be enabled.
curl http://joomla.test/api/index.php/v1/content/articles \
-H "X-Joomla-Token: your_token"The response is JSON with the list of articles. The request runs with the permissions of the token owner.
What your own component needs
plugins/webservices/hello/ the plugin: declares the addresses
├── hello.xml
├── services/provider.php
└── src/Extension/Hello.php
api/components/com_hello/ the API part of the component
└── src/
├── Controller/
│ └── PostsController.php
└── View/
└── Posts/
└── JsonapiView.phpAll files are created by hand. Add a section to the component manifest:
<!-- administrator/components/com_hello/hello.xml -->
<api>
<files folder="api">
<folder>src</folder>
</files>
</api>The plugin with routes
The plugin manifest and provider are the same as for the content plugin, only with the webservices group and the namespace My\Plugin\WebServices\Hello. The class:
// plugins/webservices/hello/src/Extension/Hello.php
namespace My\Plugin\WebServices\Hello\Extension;
defined('_JEXEC') or die;
use Joomla\CMS\Event\Application\BeforeApiRouteEvent;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\SubscriberInterface;
final class Hello extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
'onBeforeApiRoute' => 'registerRoutes',
];
}
public function registerRoutes(BeforeApiRouteEvent $event): void
{
$event->getRouter()->createCRUDRoutes(
'v1/hello/posts',
'posts',
['component' => 'com_hello'],
);
}
}createCRUDRoutes() declares five addresses at once: list, single record, create, change, delete. The second argument is the controller name. The BeforeApiRouteEvent event class exists in Joomla 5; in Joomla 4 the handler receives the router as an argument.
The controller
// api/components/com_hello/src/Controller/PostsController.php
namespace My\Component\Hello\Api\Controller;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\Controller\ApiController;
class PostsController extends ApiController
{
protected $contentType = 'posts';
protected $default_view = 'posts';
}All the work is already written in ApiController. It takes models from the administrator part of the component: PostsModel for the list and PostModel for a single record.
The view
// api/components/com_hello/src/View/Posts/JsonapiView.php
namespace My\Component\Hello\Api\View\Posts;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
class JsonapiView extends BaseApiView
{
protected $fieldsToRenderList = ['id', 'title', 'created'];
protected $fieldsToRenderItem = ['id', 'title', 'body', 'created'];
}The two lists define which fields go into the response: for the list of posts and for a single post.
The result
Install the plugin through Discover and enable it. Then run:
curl http://joomla.test/api/index.php/v1/hello/posts \
-H "X-Joomla-Token: your_token"The response is JSON in the JSON:API format: a data array where every post has type, id and attributes with the title and the date. The address v1/hello/posts/1 returns one post together with its text.
Common mistake
An API token grants the same permissions as the account of its owner. A super user token baked into a mobile app or a script on someone else's server means full access to the site for anyone who finds it. Create a separate user with the minimum permissions needed for the exchange and keep the token like a password.