Module Controllers

Introduction

In Concord CRM, the backend (Laravel) and front-end (Vue) are separate entities. The backend is responsible for storing and providing data, while the front-end processes and displays this data to the user.

When developing new modules, it's recommended to build a module API to enable interaction between the front-end and the backend. For instance, when the front-end needs to create an invoice, it sends an HTTP request to the backend. The backend then creates the invoice, sends an email, and returns the created invoice data, which the front-end displays to the user.

Creating modules involves building an API that integrates seamlessly with the existing features of Concord CRM. This ensures that new functionalities works fine within the established system.

Creating API Controller

To create an API controller, you should place the controller in the module app/Http/Controllers/Api directory, this will ensure to separate the API related controllers from any web controllers if needed to be added later.

// modules/Invoices/app/Http/Controllers/Api

namespace Modules\Invoices\Http\Controllers\Api;

use Modules\Core\Http\Controllers\ApiController;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Modules\Invoices\Models\Invoice;

class InvoiceStatusController extends ApiController
{
    public function update(string $id, string $status, Request $request) : JsonResponse
    {
        $invoice = Invoice::findOrFail($id);

        $this->authorize('update', $invoice);

        match($status) {
            'paid'  => $invoice->markAsPaid(),
            default => abort("Invalid Status", JsonResponse::HTTP_CONFLICT),
        };

        return $this->response(new InvoiceResource($invoice), JsonResponse::HTTP_OK);
    }
}

Refer to Laravel controllers documentation for more information if you are not familiar on how controllers work.

When using the resources feature in Concord CRM, you don't need to create controllers for the following actions:

Verb URI
GET /invoices
POST /invoices
GET /invoices/{invoice}
PUT/PATCH /invoices/{invoice}
DELETE /invoices/{invoice}

Registering API Routes

When you create a module with the module:make command, the scaffoling module code will already register the API related route groups and will create an routes/api.php file.

You should use this file to register any API routes for the module.

// modules/Invoices/routes/api.php

use Illuminate\Support\Facades\Route;
use Modules\Invoices\Http\Controllers\Api\InvoiceStatusController;

Route::middleware('auth:sanctum')->group(function () {
    Route::post('/invoices/{invoice}/{status}', [InvoiceStatusController::class, 'update']);
});

All routes registered in the api.php file, will be prefixed with api, for example, the route we registered above will be accessible under the /api/invoices/{invoice}/{status} endpoint.

Refer to Laravel routing documentation for more information if you are not familiar on how routing work.

Registering Web Routes

When you create a module using the module:make command, the web routes by default will be disabled, if you need to register web routes, in the module RouteServiceProvider.php file uncomment the web route registration.

The module map method should look like this:

/**
* Define the routes for the application.
*/
public function map(): void
{
    $this->mapApiRoutes();

    $this->mapWebRoutes();
}

In the module routes directory, there should be a web.php file responsible for registering all the web middleware routes.

// modules/Invoices/routes/web.php

use Illuminate\Support\Facades\Route;

Route::middleware(['auth', 'admin'])->group(function () {
    Route::get(...);
});

Making HTTP Requests

To make HTTP requests from the front-end, you can use Innoclapps.request(), please refer to the dedicated frontend documentation.

<template> {{ invoice ? invoice.number : ''}} </template>
<script setup>
    import { onMounted, ref } from "vue";

    const invoice = ref(null);

    async function fetchInvoice() {
        const { data } = await Innoclapps.request("/invoices/1");

        invoice.value = data;
    }

    async function updateInvoice() {
        const { data } = Innoclapps.request().put("/invoices/1", {
            number: 1,
        });

        invoice.value = data;
    }

    onMounted(fetchInvoice);
</script>

By calling Innoclapps.request() you will receive Axios instance pre-configured for Concord CRM with correct API prefix that you can use to make HTTP request to the specified route URL.