Skip to content

otaaaviio/disc-laravel

Repository files navigation

Discord Clone

Table of Contents

Introduction

This is a simple discord clone with real time chat, authentication and guilds (servers) with channels system. The objetive of this project is show a websocket example with Laravel Reverb. Also, demonstrate examples of how use Laravel Sanctum and application of the SOLID principles.

Stack

Installation

To execute this project, you need to have installed Docker in your machine. After that, follow the steps:

  1. Clone the repository
git clone https://github.com/otaaaviio/disc-laravel.git
  1. Enter on project folder
cd disc-laravel
  1. In src folder, execute the bin for setup:
./bin/setup.sh

ps: This step should take a while, because the docker will download the images and install the dependencies.

  1. Access in your browser the address:
http://0.0.0.0:80
  1. In .env, you need change this variables for production:
REVERB_APP_ID=
REVERB_APP_KEY=
REVERB_APP_SECRET=

For the next times, you can use this for stop or start the containers:

./bin/start.sh
./bin/stop.sh

Tests

This project contains units and integration tests. Always this branch is pushed, will execute tests in GitHub Actions. Also, to you execute tests, use the command:

./vendor/bin/sail test

ps: You need run the containers before execute the tests.

First time in the project

When you set up the project with setup.sh, will run seeder with 2 users:
Adm user:

email: [email protected]
password: password

Normal user:

email: [email protected]
password: password

With these credentials, you can access the application in different browsers and experience the real-time chat functionality.

Documentation

I used the scramble for the api documentation. You can see accessing the address:

http://0.0.0.0:80/docs/api

In this documentation, you can see the endpoints, request and response examples.

About implementation

Services:

I used service abstraction, to separate the business logic from the controller and have a better maintenance.

Repositories:

About repositories, I don't like use repository pattern in simple laravel projects, because in majority cases, the eloquent is enough, and we don't change the framework project.
In larger projects, where there might be a need to change the framework, the repository pattern is a good choice.

Websockets:

I used Laravel Reverb to implement the websockets. It's not hard to implement, but debug this should be a little hard if you don't have familiarity with websockets.
Even though it's a relatively new technology, it's a good choice to learn and apply in your personal or professional projects.

Jobs:

I used jobs to send the mail to new users, with welcome message. And use a different connection to send the mail.

Tests:

I used Pest for tests. It's a simple and clean test framework. I like it because it's easy to read and write tests.

Docker:

I used the Laravel Sail with some modifications for this project, like change the images and add vite container.

FrontEnd:

I used Vue for frontend, just for my familiarity with this framework. And I focus in the backend, so the frontend is simple and functional.

Contributing and Examples

You can fork this project and make a pull request with your changes. I will be happy to review and accept your contribution. If you follow the current project pattern, everything will work fine. :D
A example to you follow, with this you can maintain the project clean and organized, with easy maintenance:

Resource to lead with responses to client:

class ModelResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
        // here you can edit what you want to return
        ];
    }
}

Request to validate the request data:

class ModelRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            // some rules you want validated
        ];
    }
}

Exceptions to lead with errors in a clean way and eay to understand:

class ModelException extends Exception
{
    public function __construct($message = '', $code = StatusCode::HTTP_INTERNAL_SERVER_ERROR, ?Throwable $previous = null)
    {
        parent::__construct($message, $code, $previous);
    }

    public static function someError(): self
    {
        return new self(
            'Some error message here',
            StatusCode::HTTP_ERROR
        );
    }

    public function render($request): JsonResponse
    {
        return response()->json([
            'message' => $this->getMessage(),
        ], $this->getCode());
    }
}

Controller to receive request and return answer to client:

public function store(ModelRequest $request)
{
    // this will clean fields that are not in the rules
    $data = $this->validated();

    //here you process the request, within show the business logic 
    $modelResource = $this->service->create($data);

    // here you can style the response and return 
    return response()->json([
    'message' => 'Some message here',
    'model' => $modelResource
    ], StatusCode::HTTP_CREATED);
}

Service to lead with business logic and return the resource to controller:

public function create(array $data)
{
    // here you process the data and return the resource and treat errors with custom exceptions
    
    if($error) {
        // this is useful to maintain the handling of errors in the same place
        throw CustomException::someError();
    }
    
    return ModelResource::make($model);
}

For Websockets, you can add new events to project, like:

class SomeEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public Model $model
    ) {
        //
    }

    // channel where the event will be broadcast
    public function broadcastOn(): Channel
    {
        return new Channel('channel.'.$this->model->id);
    }

    // data to send in event
    public function broadcastWith(): array
    {
        return [
            'model' => $this->model
        ];
    }

    // person event name to access in client side
    public function broadcastAs(): string
    {
        return 'some-event';
    }
}

With websockets you can add real-time features to your project, like chat, notifications and others. For more infos, you can see the Laravel Documentation

Contact

If you have any questions, you can contact me by email or linkedin:

[email protected]

https://www.linkedin.com/in/otaaaviio/

About

A simple discord clone with laravel reverb

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published