requestdesk / magento-core
RequestDesk Core - Shared functionality for RequestDesk Magento extensions
Package info
github.com/brentwpeterson/requestdesk-magento-core
Type:magento2-module
pkg:composer/requestdesk/magento-core
Requires
- php: ^8.1
- magento/framework: ^103.0
- magento/module-config: ^101.0
- magento/module-store: ^101.0
README
Shared foundation module for the RequestDesk Magento 2 extension family.
requestdesk/magento-core · v1.0.0 · OSL-3.0 · PHP ^8.1 · Magento framework ^103.0
⚠️ Status: tabled
This module is not required by anything today, and is not under active development.
RequestDesk_Blog is fully standalone — it declares no dependency on Core and implements its own API key and HTTP client. You can install, run, and ship Blog without Core.
Core is kept because of what it's meant to become (see Intended future purpose), not because of what it currently does. Before anyone installs it on a real store, read Known gaps — it has a TLS-verification defect and a Test Connection button that doesn't test the code path it appears to test.
Picking this back up is a deliberate decision, not a maintenance task. The section at the bottom explains what that decision is.
What it does today
Core provides three things to a Magento store:
- A single place to configure the RequestDesk connection — an admin config section with the API key, API URL, an enable toggle, and a debug-logging toggle.
- A reusable API client (
ApiClientInterface/ApiClient) that other RequestDesk modules can inject instead of writing their own HTTP code. - A dedicated log channel at
var/log/requestdesk.log, so RequestDesk traffic doesn't get lost insystem.log.
It has no frontend output, no database tables, no cron jobs, and no admin grids. It is plumbing.
Important: nothing currently consumes it
As of this writing, RequestDesk_Blog does not depend on Core. Blog declares no composer requirement on it, no module.xml sequence entry, and references no RequestDesk\Core class. Blog implements its own HTTP calls with Magento\Framework\HTTP\Client\Curl and reads its own API key from its own config path.
So in a live store today, Core's practical effect is: it adds a config section and a Test Connection button. ApiClient is unused surface area waiting for a consumer.
Installation
No RequestDesk module requires Core today, so there is currently no reason to install it on a production store. Documented for completeness and for local work on the module itself.
composer require requestdesk/magento-core bin/magento module:enable RequestDesk_Core bin/magento setup:upgrade
Then configure at Stores → Configuration → RequestDesk → General Settings.
Configuration
Admin tab RequestDesk (sort order 400), section requestdesk_core, labelled General Settings.
| Config path | Field | Notes |
|---|---|---|
requestdesk_core/api/enabled |
Enable RequestDesk | Default 0. ApiClient throws if this is off. |
requestdesk_core/api/api_key |
API Key | Obscured field, encrypted at rest via Magento\Config\Model\Config\Backend\Encrypted. |
requestdesk_core/api/api_url |
API URL | Default https://api.requestdesk.ai. |
requestdesk_core/debug/enabled |
Enable Debug Logging | Default 0. Logs request + response bodies. |
Access is gated by the ACL resource RequestDesk_Core::config, nested under Stores → Settings → Configuration.
Public API
RequestDesk\Core\Api\ApiClientInterface — inject this, not the concrete class. etc/di.xml binds it to RequestDesk\Core\Model\ApiClient.
| Method | HTTP call |
|---|---|
testConnection(): array |
GET /health — returns ['success' => bool, 'message' => string, 'data' => ...], never throws |
syncProducts(array $products): array |
POST /products/sync |
getBrandScore(array $productIds = []): array |
GET /brand-score[?product_ids=1,2,3] |
getProductSchema(int $productId): array |
GET /schema/product/{id} — JSON-LD |
getBlogPosts(int $limit = 10, int $offset = 0): array |
GET /blog/posts?limit=&offset= |
request(string $endpoint, string $method = 'GET', array $data = []): array |
Generic escape hatch |
Request behavior
Every call routes through request(), which:
- Throws if the integration is disabled or the API key is empty.
- Builds the URL as
{api_url}/api/v1/{endpoint}. - Sends
Authorization: Bearer {api_key},Content-Type: application/json,Accept: application/json,User-Agent: RequestDesk-Magento/1.0. - Times out at 30 seconds.
- Throws on any status >= 400, using
messageorerrorfrom the response body as the exception message. - Returns the deserialized JSON body on success.
PUT and DELETE are implemented by setting CURLOPT_CUSTOMREQUEST over a post()/get() call — a quirk of Magento's Curl wrapper, not a bug.
Helper
RequestDesk\Core\Helper\Config exposes isEnabled(), getApiKey() (returns the decrypted key), getApiUrl(), and isDebugEnabled(). Most consumers should use ApiClient and never touch the helper directly.
Admin: Test Connection
The Test Connection button in the config section posts to requestdesk/system/testconnection (Controller\Adminhtml\System\TestConnection), which reports either the connected company name, an invalid-key error, or the HTTP failure.
It handles the case where the admin form submits the masked key (****) rather than a real one, by falling back to the saved config value.
Known gaps
These are real and worth fixing before Core becomes a dependency anything else relies on.
The Test Connection button does not test what ApiClient does. They speak to different endpoints with different auth schemes:
| Endpoint | Auth header | |
|---|---|---|
ApiClient::request() |
{api_url}/api/v1/{endpoint} |
Authorization: Bearer {key} |
| Test Connection controller | {api_url}/api/public/magento/test |
x-requestdesk-api-key: {key} |
A green "Connected successfully!" therefore proves nothing about whether ApiClient can authenticate. One of these two is wrong, and which one depends on what the RequestDesk API actually accepts.
TLS verification is disabled in the Test Connection controller. CURLOPT_SSL_VERIFYPEER => false is hardcoded, with a comment noting it's for local Docker testing. It applies in production too.
Store scoping is declared but not honored. system.xml sets showInWebsite="1" on the API group, and Config::isEnabled() / getApiKey() accept an ?int $storeId argument — but both ignore it and read SCOPE_TYPE_DEFAULT. A website-scoped API key can be saved and will never be read.
Intended future purpose
Core exists for a role it does not yet fill. This section records that intent so the module isn't mistaken for dead code, and so whoever picks it up doesn't have to re-derive the reasoning.
The model is the vendor base module — Amasty_Base, Aheadworks_Core, and their equivalents. Those aren't just shared libraries; a base module typically owns:
- shared library and UI code the child modules reuse,
- a registry of installed vendor modules and their versions, with compatibility checks,
- license key storage, activation, and entitlement checks,
- update and notification surfaces in the admin.
The intended end state for RequestDesk is that Core becomes two things at once:
- The single interface to RequestDesk. One API credential, one HTTP client, one log channel. Every child module (Blog, and whatever follows) declares Core as a dependency and drops its own HTTP code.
ApiClientis already written for this; it just has no consumers. - The entitlement layer for a paid tier. Core owns the key and answers "what is this store licensed for." Free modules run without it; paid features check it.
Why it's tabled, and what unblocks it
The two goals above are ordered, not parallel — (1) is the prerequisite for (2), and that's the reason nothing can proceed today.
What makes a base module a workable license gate is that every child hard-depends on it: a composer require plus a module.xml sequence entry. A paid module then cannot run without the base, so the gate can't be bypassed by simply not installing it.
RequestDesk currently has the inverse. Blog is standalone and duplicates Core's job with its own key and its own curl. Nothing enforces Core's presence, so Core cannot gate anything — the licensing idea is unenforceable until the children actually depend on Core.
So the work that unblocks the paid tier is not licensing work. It is:
- decide whether Core or each child owns the API credential (Core, if any of this is to work),
- make Blog
requireCore and consumeApiClientinstead of its own curl, - fix the known gaps first — a shared client with TLS verification off and an unverifiable Test Connection button is worse than no shared client.
The one cost of waiting
Blog stores its API key at requestdesk_blog/api/api_key; Core stores its at requestdesk_core/api/api_key. Consolidating onto one credential means a config migration for existing Blog installs, or a fallback that reads Core's key and falls back to Blog's.
That cost is near-zero while Blog has few installs, and grows with adoption. It doesn't argue for doing the work now — it just determines when "later" stops being free.