Quay lại
Cách sử dụng Swagger trong Laravel

Hi mọi người chắc hẳn trong quá trình làm việc với 1 team dev thường sẽ bao gồm cả Backend và Frontend đúng không ? Vậy thì làm sao để 2 bên có sự tương tác với nhau , làm sao để FE có thể biết được những API nào đã làm xong có ghép ghép để sử dụng, Mình sẽ đưa ra các trường hợp để các bạn hiểu rõ hơn về Swagger nhé.

TH1: Hãy tưởng tượng team Frontend thì làm việc trong Miền Nam còn Backend team thì làm ở Hà Nội vậy thì làm sao để 2 bên có sự tương tác với nhau , làm sao để FE có thể biết được những API nào đã làm xong có ghép ghép để sử dụng ?

TH2: Khi bạn đang xây dựng một thống cho khách hàng gồm rất nhiều API, một ngày đẹp trời bạn nghỉ việc, những thông tin về API đó bạn không có tạo ra document để người vào sau sẽ tiếp tục làm cho bạn thì sẽ rất khó để maintain, cần phải tự đọc code của bạn để suy luận ra cần pải truyền vào những tham số như nào.. vv?

Th3: Bạn tách hệ thống của bạn ra làm nhiều module , các module phải call api qua lại cho nhau , nếu không có 1 tài liệu để ghi lại api của từng module thì thực sự rất khó để kết hợp đúng không nào?

Như bạn đấy đó việc viết lại doc api thực sự rất cần thiết đúng không nào ? Vậy bài hôm nay mình sẽ hướng dẫn các bạn làm để nào để viết lại các doc api trong laravel nhé , trong bài này mình sẽ hướng dẫn sử dụng Swagger để giải quyết vấn đề này nhé ! let goooo

Cách cài đặt Swagger trong Laravel

l5-swagger package, cung cấp hỗ trợ để tạo tài liệu OpenAPI cho Laravel. Package này có thể tạo các tệp JSON hoặc YAML với tài liệu dựa trên các chú thích PHP. Sử dụng lệnh này để cài đặt nó trong các phiên bản Laravel mới nhất

composer require darkaonline/l5-swagger

Sau khi install hãy publish Swagger bằng lệnh sau:

php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"

File cấu hình chính cho package là config/l5-swagger.php.Theo mặc định, bạn có thể mở giao diện tài liệu bằng đường dẫn sau: api/documentation. Để mà Swagger có thể đọc các api mà bạn đã viết thì bạn cần phải tùy chỉnh đường dẫn path 1 chút hãy mở file config lên và tìm kiếm documentations -> default -> paths -> annotations hãy thêm path mà chứa chú thích swagger mà bạn đã stored vào đây, ví dụ của mình là :

/*
* Absolute paths to directory containing the swagger annotations are stored.
*/
'annotations' => [
  base_path('Project/Infrastructure/Primary/WebApi/Controllers'),
],

Ngoài ra, nếu bạn muốn có thể thực hiện các truy vấn thử nghiệm đối với API của mình bằng giao diện mà swagger cung cấp, thì bạn phải đặt biến môi trường L5_SWAGGER_CONST_HOST trong tệp .env của mình. 

L5_SWAGGER_CONST_HOST="http://localhost:8000"

Bạn có thể genarate document bằng lệnh này:

php artisan l5-swagger:generate

Lệnh này sẽ chỉ genarate documention mặc định. Nếu bạn có nhiều documentions, hãy sử dụng lệnh sau để genarate tất cả:

php artisan l5-swagger:generate --all

Annotations(Chú thích) được sử dụng nhiều nhất

Ở đây mình sẽ liệt kê các annotations được sử dụng nhiều nhất và mô tả của chúng mà bạn có thể sử dụng trong các dự án của mình:

  • Info – thêm thông tin về toàn bộ dự án;
  • Tag – tạo thẻ để phân tách các endpoints theo phần;
  • Get – GET request;
  • Post – POST request;
  • Delete – DELETE request;
  • Post – POST request;
  • Put – PUT request;
  • Response – response trả về;
  • Schema – các thuộc tính JSON hoặc tham số thuộc tính, có thể được sử dụng lại trong các schemas khác 
  • Property – mô tả a field;
  • Items – mô tả các phần tử của mảng;

Cách sử dụng Swagger trong Laravel

1. Thêm thông tin vào dự án

Trước khi generating document đầu tiên, bạn nên thêm thông tin dự án vào chú thích @Info. Mình thường sử dụng lớp app/Http/Controllers/Controller.php để làm điều này. Ví dụ:

/**
* @OA\Info(
* description="This is an example API",
* version="1.0.0", * title="Example API" * )
*/
class Controller extends BaseController {
  //.....
}

2. Các chú thích được dùng để mô tả api

Hãy xem các chú thích để mô tả cho api sẽ trông như thế nào ?. Tất cả các request phải được mô tả bằng cách sử dụng một trong các chú thích sau đây, bao gồm các phương thức như là @Get, @Post, @Put, @Delete. Trong mỗi chú thích, bạn có thể đặt giá trị của các tham số đó

  • path – đường dẫn URL endpoint;
  • tags – chỉ định các tags ở đây nếu bạn muốn gắn thẻ ở endpoint này;
  • summary – Mô tả ngắn;
  • description – Mô tả chi tiết;

Ngoài ra còn một số chú thích quan trong nữa mà bạn cần lưu ý

  • @Parameter – mô tả một tham số sẽ được chuyển vào truy vấn hoặc headers;
  • @RequestBody – mô tả nội dung yêu cầu cho các truy vấn PUT, POST và DELETE;
  • @Response – mô tả mọi phản hồi có thể xảy ra và mã trạng thái của chúng;
  • @Security – mô tả thông tin xác thực.

Tất nhiên, đây không phải là danh sách đầy đủ các chú thích được hỗ trợ mà chỉ là những chú thích được sử dụng nhiều nhất. Đây là một ví dụ về tài liệu cho endpoint /api/user. Theo mặc định, Laravel có api này, vì vậy bạn có thể mô tả nó:

/**
     * @OA\Get(
     *     path="/api/user",
     *     summary="Get current user",
     *     description="Returns information about the current user if the request is authenticated",
     *     @OA\Response(
     *         response=200,
     *         description="Everything OK"
     *     ),
     *     @OA\Response(
     *         response=403,
     *         description="Access Denied"
     *     )
     * )
*/

Ở đó các tham số cho security parameters vẫn bị thiếu mình sẽ bổ sung sau nhé, bạn tạm thời có thế đặt đoạn code trên vào class app/Http/Controllers/Controller.php cho ví dụ này. Sau đó bạn có thể sử dụng lệnh dưới đây để genarate ra api doc cho mình:

php artisan l5-swagger:generate

Sau khi bạn chạy lệnh trên thì hãy vào browser gõ http://localhost:8000/api/documenation để thấy giao diện cho developer.

3. Mô tả về @QA\Parameters

Dưới đây là các thực thể có thể sử dụng trong @Parameter

  • Path – parameter, dùng trong query path, ví dụ: /user/{id};
  • Query – parameters, dùng trong query path, nhưng nó là dạng =>/user?id=1;
  • Header – parameters headers;
  • Cookie – parameters cookie.

Bạn phải chỉ định các đối số cho chú thích @Parameter này:

  • name –  tên của parameter;
  • in – kiểu của parameter (path, query, header, or cookie);
  • description – một mô tả của parameter;
  • required –  parameter is required hay không;
  • deprecated – đánh dấu các parameters có dùng nữa hay không.

Hãy cùng nhìn một ví dụ dưới để hiểu hơn nhé , các bạn để ý trường name nhé vì nó được dùng để gửi lên server đó

/**
 *     @OA\Parameter(
 *         name="verbosity",
 *         description="Set the verbosity of the output",
 *         in="query",
 *         required=false
 *     ),
 */

Ngoài ra, bạn có thể sử dụng Authentication token trong header để gửi lên server

/**
 *     @OA\Parameter(
 *         name="Authentication",
 *         description="Provides user authentication token",
 *         in="header",
 *         required=true
 *     ),
*/

Bây giờ, bạn có thể chạy thử và xem kết quả:

4. Mô tả về @QA\JsonContent

Bạn có thể sử dụng dữ liệu JSON trong responses và thậm chí trong requests. Bạn chú ý 1 điều này cho mình nhé  không có sự khác biệt giữa form-data và JSON request body trong Laravel miễn là bạn không gửi file. Bạn có thể mô tả nội dung JSON bằng chú thích @JsonContent. Chú thích này có thể chứa một hoặc nhiều @Property để mô tả từng trường JSON. Chú thích @Property có thể chứa các tham số sau:

  • property – tên của field;
  • type – kiểu dữ liệu của field. hỗ trợ các types như là: integer, number, string, boolean, object, array;
  • description – mô tả của field;
  • format – thông tin bổ sung về dữ liệu. Nó phụ thuộc vào kiểu field;
  • example – ví dụ để hiện thị;
  • nullable – xác định xem tham số có thể chứa giá trị null hay không;

Các định dạng string number được sử dụng nhiều nhất là float và double. Các định dạng string là date, date-time, password, binary, byte, email, uuid, uri, hostname, ipv4, ipv6 và các định dạng khác. Đây chỉ là những thông số được sử dụng nhiều nhất. Ngoài ra, nó có thể chứa các thuộc tính khác. Ví dụ: hãy mô tả tham số name dưới dạng JSON:

/**
 *         @OA\JsonContent(
 *              @OA\Property(
 *                  property="name",
 *                  description="Set the name of the output",
 *                  type="string",
 *                  nullable="true"
 *              )
 *         )
 */

5. Mô tả về @QA\Response

Như các bạn biết đấy hầu hết các reponse trong API REST là JSON. Ví dụ: API của chúng ta trả về thông báo lỗi này:

{
    "message": "Unauthenticated"
}

Các chú thích trong Swagger sẽ trông như thế này:

 /**
 *     @OA\Response(
 *         response=403,
 *         description="Access Denied",
 *         @OA\JsonContent(
 *             @OA\Property(
 *                  property="message",
 *                  type="string",
 *                  description="An error message",
 *                  nullable=false,
 *                  example="Unauthenticated"
 *             )
 *         )
 *     )
 *

5.1 Cách sử dụng bearer token trong swagger (jwt)

Như các bạn đã biết để call được đến các API, chúng ta cần phải cung cấp 1 token đúng không nào ? Các bạn đừng lo swagger đã cung cấp 1 giao diện để chúng ta có thể thao tác trực tiếp chỉ cần nhập token 1 lần là có thể sử dụng cho toàn bộ API của chúng ta mà không cần phải nhập token cho những lần gọi API tiếp theo , để làm được điều này thì các bạn phải config 1 chút , đầu tiên hãy mở file l5-swagger.php trong folder /config sau đó tìm đến chỗ securityDefinitions -> securitySchemes thêm đoạn code này vào trong mảng nhé :

'bearer_token' => [ // Unique name of security
    'type' => 'apiKey', // Valid values are "basic", "apiKey" or "oauth2".
    'description' => 'Enter token in format (Bearer )',
    'name' => 'Authorization', // The name of the header or query parameter to be used.
    'in' => 'header', // The location of the API key. Valid values are "query" or"header".
    'scheme' => 'bearer',
],

Ok sau thì thêm và load lại browser thì các bạn sẽ thấy được giao diện như này:

Để mà chạy được thì các bạn cần phải nhập trong input value là : Bearer + token nhé

OK đến bước sử dụng nó trong các chú thích nữa là xong rồi , trong mỗi chú thích @post , @get, @delete, @put bạn

cần phải thêm thuộc tính security={{"bearer_token":{}}} nữa nó sẽ như thế này:

    /**
     * 
     * @OA\Get(
     *     path="/approval-workflow",
     *     tags={"Approval workflow"},
     *     operationId="index",
     *     summary="Get list approval workflow",
     *     description="Get list approval workflow",
     *     security={{"bearer_token":{}}},
     *     @OA\Response(
     *         response=200,
     *         description="successful",
     *          @OA\JsonContent()
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="An error occurred"
     *     ),
     *     @OA\Response(
     *          response=401,
     *          description="Unauthenticated",
     *     ),
     * )
     */

6. Sử dụng @QA\Schema

Trong ví dụ trên, mình đã mô tả trực tiếp các trường JSON trong chú thích @response. Nhưng trong trường hợp đó chỉ có một response. Nhưng trong nhiều trường hợp, bạn có thể có một tập hợp các fields được sử dụng ở nhiều trong api. Bạn có thể sử dụng chú thích @Schema để tránh trùng lặp mã. Nó cho phép mô tả tất cả các trường hoặc tham số bắt buộc ở một nơi và sau đó có thể tái sử dụng chúng.

Mỗi schema phải có một schema parameter name. Tên này sẽ được sử dụng để import schema. Ví dụ: bạn có thể mô tả schema với response successfull cho /api/user request:

/**
 * @OA\Schema(
 *    schema="UserSchema",
 *    @OA\Property(
 *        property="id",
 *        type="integer",
 *        description="User ID",
 *        nullable=false,
 *        example="1"
 *    ),
 *    @OA\Property(
 *        property="name",
 *        type="string",
 *        description="User Name",
 *        nullable=false,
 *        example="John"
 *    ),
 *    @OA\Property(
 *        property="email",
 *        type="string",
 *        description="User EMail",
 *        nullable=false,
 *        format="email"
 *    ),
 *    @OA\Property(
 *        property="email_verfied_at",
 *        type="string",
 *        description="User EMail verified date",
 *        nullable=true,
 *        format="date-time"
 *    ),
 *    @OA\Property(
 *        property="created_at",
 *        type="string",
 *        description="Date of user creation",
 *        nullable=false,
 *        format="date-time"
 *    ),
 *    @OA\Property(
 *        property="updated_at",
 *        type="string",
 *        description="Date of last updating user data",
 *        nullable=false,
 *        format="date-time"
 *    ),
 * )
 */

Bây giờ, bạn có thể thêm schema này vào response bằng cách sử dụng ref parameter. Sử dụng đường dẫn “#/components/schemas” cộng với tên của schema:

/**
 *     @OA\Response(
 *         response=200,
 *         description="Everything OK",
 *         @OA\JsonContent(
 *             ref="#/components/schemas/UserSchema"
 *         )
 *     ),
 */

Nó sẽ trông như thế này trên frontend:

Bạn có thể chuyển sang tab schema để hiển thị thông tin chi tiết hơn:

Trong ví dụ này, mình đã mô tả schema cho @JsonContent. Bạn cũng có thể sử dụng schema cho chính các thuộc tính, mảng, v.v.

7. Sử dụng @QA\Arrays

Các API thường trả về một mảng dữ liệu. Bạn có thể sử dụng chú thích @Property với kiểu mảng để mô tả chúng. Nhưng trong trường hợp này, chú thích phải chứa mục @Items  để mô tả các phần tử của một mảng. Hãy tưởng tượng rằng api của chúng ta trả về một danh sách người dùng trong một số trường hợp. Bạn có thể sử dụng đoạn mã sau để mô tả nó:

/**
 *     @OA\Response(
 *         response=201,
 *         description="Users List",
 *         @OA\JsonContent(
 *             @OA\Property(
 *                property="users",
 *                type="array",
 *                description="List of users",
 *                @OA\Items(
 *                    ref="#/components/schemas/UserSchema"
 *                )
 *             )
 *         )
 *     ),
 *

Bạn có thể đặt các thuộc tính trực tiếp vào chú thích @Items hoặc chỉ là một tham chiếu đến schema hiện có như được thực hiện trong ví dụ trên:

8. Sử dụng Enumerations

Enumerations cho phép bạn mô tả tất cả các giá trị có thể có cho bất kỳ thuộc tính nào. Chỉ cần mô tả thuộc tính như bình thường và sau đó sử dụng tham số enum để xác định các giá trị có thể. Ví dụ: hãy mô tả trường trạng thái có bốn giá trị: pending, processing, finished, and failed

/**
 *    @OA\Property(
 *        property="state",
 *        type="string",
 *        description="Processing state",
 *        nullable=false,
 *        enum={
 *             "pending",
 *             "processing",
 *             "finished",
 *             "failed",
 *          }
 *    ),
  */

Ví dụ trên nó sẽ được hiển thị như này:

Ngoài ra, bạn có thể mô tả field bằng cách sử dụng chú thích @Schema và sử dụng lại nó ở bất cứ đâu bạn muốn. Chỉ cần mô tả một property schema:

/**
 * @OA\Schema(
 *     schema="StateEnum",
 *     description="Processing State",
 *     type="string",
 *     enum={
 *         "pending",
 *         "processing",
 *         "finished",
 *         "failed",
 *     }
 * )
  */

Giờ đây, bạn có thể nhập schema này vào bất kỳ thuộc tính nào mà không cần viết cùng một mã nhiều lần:

/**
 *    @OA\Property(
 *        property="state",
 *        type="string",
 *        ref="#/components/schemas/StateEnum"
 *    )
  */

9. Sử dụng Object

Nếu bạn muốn mô tả bất kỳ object nào chứa các thuộc tính khác nhau, chẳng hạn như một phần tử của mảng, bạn có thể sử dụng kiểu object và chỉ cần thêm các thuộc tính con vào thuộc tính đối tượng. Hãy mô tả object với thông tin về người dùng có quyền quản trị viên như sau:

/**
 *    @OA\Schema(
 *       schema="AdminSchema",
 *       @OA\Property(
 *           property="id",
 *           type="integer",
 *           description="User ID",
 *           nullable=false,
 *           example="1"
 *       ),
 *       @OA\Property(
 *           property="name",
 *           type="string",
 *           description="User Name",
 *           nullable=false,
 *           example="John"
 *       ),
 *       @OA\Property(
 *           property="permissions",
 *           type="object",
 *           nullable=false,
 *           description="Permissions state",
 *           @OA\Property(
 *               property="can_create",
 *               type="boolean",
 *               nullable=false,
 *               description="Determines whether the user can create records",
 *           ),
 *           @OA\Property(
 *               property="can_delete",
 *               type="boolean",
 *               nullable=false,
 *               description="Determines whether the user can delete records",
 *           ),
 *      )
 *  )
  */

10. Combine Schemas

Các schema có thể làm rất nhiều điều thú vị. Bạn có thể kết hợp hai hoặc nhiều schema để mô tả các mảng có thể chứa nhiều loại đối tượng. Dưới đây là các tham số được sử dụng nhiều nhất để kết hợp schema

  • anyOf – có thể chứa bất kỳ schema cụ thể nào hoặc cả hai;
  • allOf – phải chứa tất cả các lược đồ được chỉ định;
  • oneOf – chỉ được chứa một trong các schemas đã chỉ định.

Các parameters này muốn có một mảng liên kết đến các schema. Ví dụ: hãy tưởng tượng rằng API của bạn có thể trả về thông tin về quản trị viên và người dùng thông thường trong cùng một danh sách. Bạn có thể mô tả mảng này bằng tham số anyOf

/**
 *         @OA\JsonContent(
 *             @OA\Property(
 *                property="users",
 *                type="array",
 *                description="List of users",
 *                @OA\Items(
 *                      anyOf={
 *                          @OA\Schema(ref="#/components/schemas/UserSchema"),
 *                          @OA\Schema(ref="#/components/schemas/AdminSchema"),
 *                      }
 *                )
 *             )
 *         )
 */

11. Sử dụng @QA/Post request

Bây giờ bạn đã biết tất cả các cách có thể giúp bạn tạo tài liệu API cho các dự án của mình. Ở trên bạn đã biết cách tạo tài liệu cho các request GET. Hãy xem cách tạo tài liệu cho các  request POST. Sự khác biệt chính ở đây, bạn có thể sử dụng chú thích @RequestBody với nội dung JSON để mô tả trường nào bạn muốn nhận. Ví dụ: hãy tạo tài liệu cho một API để thêm người dùng mới:

/**
 * @OA\Schema(
 *    schema="CreateUserRequest",
 *    @OA\Property(
 *        property="name",
 *        type="string",
 *        description="User Name",
 *        nullable=false,
 *        example="John"
 *    ),
 *    @OA\Property(
 *        property="email",
 *        type="string",
 *        description="User EMail",
 *        nullable=false,
 *        format="email"
 *    ),
 * )
 *
 * @OA\Post(
 *     path="/api/user",
 *     summary="Create a new user",
 *     description="Creates a new user by its name and email address",
 *     @OA\RequestBody(
 *        @OA\JsonContent(ref="#/components/schemas/CreateUserRequest")
 *     ),
 *     @OA\Response(
 *         response=201,
 *         description="Everything OK",
 *         @OA\Schema(ref="#/components/schemas/UserSchema")
 *     ),
 *     @OA\Response(
 *         response=500,
 *         description="Internal server error"
 *     )
 * )
 */

Tôi đã tạo một schema dành riêng cho request này bởi vì trong một dự án thực tế, bạn nên đặt nó vào lớp FormRequest và sau đó nó sẽ được liên kết đến 1 controller.

12. Sử dụng Tagging Endpoints

Bạn có thể phân loại các API của mình bằng các thẻ. Ví dụ: bạn có thể đặt tất cả các API để quản lý người dùng cùng nhau bằng cách sử dụng “Users” tag. Nên tạo tag đầu tiên nhé

/** 
* @OA\Tag(
 *     name="Users",
 *     description="API Endpoints of User Management"
 * )
 */

Sau đó, thêm tag vào mô tả API bằng tham số tags:

/**
 * @OA\Post(
 *     path="/api/user",
 *     summary="Create a new user",
 *     tags="Users",
*/

Và kết quả là

13.Swagger Annotations and Sub Classes

Điều này khá kỳ lạ, nhưng khi bạn extend một class có chú thích @Schema , thì lớp con của bạn sẽ kế thừa schema đó. Ví dụ: bạn có CreateArticleRequest với schema này

/**
 * @OA\Schema(
 *    schema="ArticleRequestSchema",
 *    @OA\Property(
 *        property="title",
 *        type="string",
 *        description="Article title",
 *        nullable=false,
 *    ),
 *    @OA\Property(
 *        property="content",
 *        type="string",
 *        description="Article content",
 *        nullable=false,
 *    )
 * )
 */

Nếu bạn tạo CreateNewsRequest extends CreateArticleRequest và thêm một schema trống có tên NewsArticleRequestSchema vào đó, schema này sẽ chứa tất cả các thuộc tính từ lớp cha.

Kết thúc

Trong bài viết này, tôi đã giải thích cách sử dụng Swagger trong Laravel với package l5-swagger. Như bạn có thể thấy, nó có thể rất thuận tiện. Cảm ơn các bạn đã đọc

nhé

ˈvalyo͞o

giá trị


danh từ

đánh giá, định giá hàng hóa, giá cả, giá tiền, giá trị, trị giá, trị số

@đăng, @nhận, @xóa, @đặt

lược đồ

gói

Sau đó, thêm tag vào mô tả API bằng tham số tags:

Bình luận (0)

Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough

Bài viết liên quan

Learning English Everyday