Skip to content

Commit

Permalink
#9 add swagger, cron and readme
Browse files Browse the repository at this point in the history
  • Loading branch information
IlyasAkbergen committed Jan 15, 2025
1 parent 98438c6 commit ca2ef5e
Show file tree
Hide file tree
Showing 26 changed files with 1,177 additions and 100 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
APP_NAME=Laravel
APP_NAME="News Aggregator"
APP_ENV=dev
APP_KEY=base64:pz1gU5Un7JAHTnHHhoS80lh/2GGTf2JufhTFKfUOO0Q=
APP_DEBUG=true
Expand Down
1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ FROM php:8.4-fpm

# Install dependencies
RUN apt-get update && apt-get install -y \
git \
unzip \
libpq-dev \
librabbitmq-dev \
Expand Down
17 changes: 10 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
default: setup

setup: copy-env up install migration seed test
setup: copy-env up install migration seed test up-workers

copy-env:
cp .env.example .env

install:
docker compose run --rm php sh -c "composer install"
docker compose exec php sh -c "composer install"

migration:
docker compose run --rm php sh -c "php artisan migrate"
docker compose exec php sh -c "php artisan migrate"

seed:
docker compose run --rm php sh -c "php artisan db:seed"
docker compose exec php sh -c "php artisan db:seed"

up:
docker compose up -d

up-workers:
docker compose up -d queue-worker cron

test:
docker compose run --no-deps --rm php sh -c "touch database/database.sqlite && composer install && composer test"
docker compose exec php sh -c "touch database/database.sqlite && composer install && composer test"

phpstan:
docker compose run --no-deps --rm php sh -c "composer install && composer phpstan"
docker compose exec php sh -c "composer install && composer phpstan"

fetch_articles:
docker compose run --no-deps --rm php sh -c "php artisan articles:fetch"
docker compose exec php sh -c "php artisan articles:fetch"
99 changes: 33 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,33 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>

<p align="center">
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>

## About Laravel

Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:

- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).

Laravel is accessible, powerful, and provides tools required for large, robust applications.

## Learning Laravel

Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.

You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.

If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.

## Laravel Sponsors

We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).

### Premium Partners

- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[WebReinvent](https://webreinvent.com/)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
- **[Jump24](https://jump24.co.uk)**
- **[Redberry](https://redberry.international/laravel/)**
- **[Active Logic](https://activelogic.com)**
- **[byte5](https://byte5.de)**
- **[OP.GG](https://op.gg)**

## Contributing

Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).

## Code of Conduct

In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).

## Security Vulnerabilities

If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [[email protected]](mailto:[email protected]). All security vulnerabilities will be promptly addressed.

## License

The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
### Setup
```sh
make
```

#### Manually Fetch Articles
##### Articles are fetched automatically every minute, so you don't need to do this
```sh
make fetch_articles
```

#### Api documentation - Swagger
http://localhost:8080/api/documentation

Default User credentials:
```log
[email protected]
password
```

- get token from `/api/login` endpoint
- click on `Authorize` button on top right corner
- paste the token in the input box with `Bearer ` prefix

#### Run tests
```sh
make test
```

#### Run phpstan
```sh
make phpstan
```
73 changes: 69 additions & 4 deletions app/Http/Controllers/Api/ArticlesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,71 @@

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\Api\GetArticlesRequest;
use App\Http\Resources\ArticleResource;
use App\Models\Article;
use App\UseCase\GetArticles\GetArticlesUseCase;
use App\UseCase\GetArticles\RequestModel;
use DateMalformedStringException;
use DateTimeImmutable;
use Domain\Exception\ExternalException;
use Domain\Repository\ArticleRepositoryInterface;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Ramsey\Uuid\Uuid;
use OpenApi\Attributes as OA;

class ArticlesController extends Controller
class ArticlesController extends BaseApiController
{
/**
* @throws DateMalformedStringException
* @throws ExternalException
*/
#[OA\PathItem(
path: '/api/articles',
get: new OA\Get(
security: [['sanctum' => []]],
tags: [ 'Articles'],
parameters: [
new OA\Parameter(name: 'page', in: 'query', required: true),
new OA\Parameter(name: 'per_page', in: 'query', required: true),
new OA\Parameter(name: 'search', in: 'query'),
new OA\Parameter(name: 'date_from', in: 'query'),
new OA\Parameter(name: 'category_id', in: 'query'),
new OA\Parameter(name: 'source_id', in: 'query'),
],
responses: [
new OA\Response(
response: 200,
description: 'Successful operation',
content: new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
properties: [
new OA\Property(
property: 'data',
properties: [
new OA\Property(
property: 'meta',
properties: [],
type: 'object',
),
new OA\Property(
property: 'records',
type: 'array',
items: new OA\Items(
ref: '#/components/schemas/ArticleResource',
),
),
],
type: 'object',
),
],
type: 'object',
),
),
),
],
),
)]
public function index(GetArticlesRequest $request, GetArticlesUseCase $useCase): JsonResource
{
$responseModel = $useCase(new RequestModel(
Expand All @@ -50,6 +95,26 @@ public function index(GetArticlesRequest $request, GetArticlesUseCase $useCase):
]);
}

#[OA\PathItem(
path: '/api/articles/{id}',
get: new OA\Get(
security: [['sanctum' => []]],
tags: [ 'Articles'],
parameters: [
new OA\Parameter(name: 'id', in: 'path', required: true),
],
responses: [
new OA\Response(
response: 200,
description: 'Successful operation',
content: new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(ref: '#/components/schemas/ArticleResource'),
),
),
],
),
)]
public function show(string $id, ArticleRepositoryInterface $articleRepository): JsonResource
{
$article = $articleRepository->find(Uuid::fromString($id));
Expand Down
30 changes: 28 additions & 2 deletions app/Http/Controllers/Api/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,41 @@

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\Api\LoginRequest;
use App\Models\User;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
use OpenApi\Attributes as OA;

class AuthController extends Controller
class AuthController extends BaseApiController
{
/**
* @throws ValidationException
*/
#[OA\PathItem(
path: '/api/login',
post: new OA\Post(
requestBody: new OA\RequestBody(
content: new OA\MediaType(
mediaType: 'multipart/form-data',
schema: new OA\Schema(ref: '#/components/schemas/LoginRequest'),
)
),
tags: [ 'Auth'],
responses: [
new OA\Response(
response: 200,
description: 'Successful login',
content: new OA\JsonContent(
properties: [
new OA\Property(property: 'token', type: 'string'),
],
)
),
],
),
)]
/**
* @throws ValidationException
*/
Expand Down
19 changes: 19 additions & 0 deletions app/Http/Controllers/Api/BaseApiController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use OpenApi\Attributes as OA;

#[
OA\Info(
version: '1.0.0',
title: 'News Aggregator API',
)
]
class BaseApiController extends Controller
{

}
14 changes: 14 additions & 0 deletions app/Http/Requests/Api/GetArticlesRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace App\Http\Requests\Api;

use Illuminate\Foundation\Http\FormRequest;
use OpenApi\Attributes as OA;

/**
* @property string|null $page
Expand All @@ -14,6 +15,19 @@
* @property string|null $category_id
* @property string|null $source_id
*/
#[OA\Schema(
title: 'GetArticlesRequest',
required: ['page', 'per_page'],
properties: [
new OA\Property(property: 'page', type: 'integer'),
new OA\Property(property: 'per_page', type: 'integer'),
new OA\Property(property: 'search', type: 'string'),
new OA\Property(property: 'date_from', type: 'string'),
new OA\Property(property: 'category_id', type: 'string'),
new OA\Property(property: 'source_id', type: 'string'),
],
type: "object",
)]
class GetArticlesRequest extends FormRequest
{
public function authorize(): bool
Expand Down
10 changes: 10 additions & 0 deletions app/Http/Requests/Api/LoginRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,21 @@

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use OpenApi\Attributes as OA;

/**
* @property string $email
* @property string $password
*/
#[OA\Schema(
title: "LoginRequest",
required: ["email", "password"],
properties: [
new OA\Property(property: "email", type: "string"),
new OA\Property(property: "password", type: "string"),
],
type: "object",
)]
class LoginRequest extends FormRequest
{
public function authorize(): bool
Expand Down
15 changes: 15 additions & 0 deletions app/Http/Resources/ArticleResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,25 @@
use Domain\Entity\Article;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use OpenApi\Attributes as OA;

/**
* @property Article $resource
*/
#[OA\Schema(
title: 'ArticleResource',
properties: [
new OA\Property(property: 'id', type: 'string'),
new OA\Property(property: 'title', type: 'string'),
new OA\Property(property: 'description', type: 'string'),
new OA\Property(property: 'content', type: 'string'),
new OA\Property(property: 'url', type: 'string'),
new OA\Property(property: 'imageUrl', type: 'string'),
new OA\Property(property: 'author', ref: '#/components/schemas/AuthorResource', type: 'object'),
new OA\Property(property: 'source', ref: '#/components/schemas/SourceResource', type: 'object'),
new OA\Property(property: 'category', ref: '#/components/schemas/CategoryResource', type: 'object'),
],
)]
class ArticleResource extends JsonResource
{
public function __construct(Article $resource)
Expand Down
Loading

0 comments on commit ca2ef5e

Please sign in to comment.