Top 6 # Xem Nhiều Nhất Cách Viết Api Document Mới Nhất 2/2023 # Top Like | Hanoisoundstuff.com

Cách Viết Rails Api Document

Như các bạn đã biết, 1 ứng dụng API sẽ không có giao diện cho người dùng trên trình duyệt, thay vào đó sẽ là các dữ liệu kiểu JSON hoặc XML … được hiển thị mà thôi. Do đó, khi viết 1 ứng dụng API đòi hỏi người viết phải viết Documents (Tài liệu) kèm theo để hỗ trợ cho những Developers sử dụng chúng và đặc biệt là QA, những người sẽ gặp nhiều khó khăn hơn trong việc hiểu được tác dụng của các API.

Có nhiều cách để viết Documents, đơn giản nhất sẽ là viết bằng tay ra file Excel hoặc Word chẳng hạn. Chỉ rõ API này mục đích làm gì, URL để truy cập đến như thế nào, dữ liệu gửi Request là gì, Dữ liệu Response trả về là gì … Xong rồi thì gửi chúng cho bên Developers/QA có như cầu sử dụng để họ đọc. Cách này khá thủ công và tốn nhiều efforts trong khi giá trị mang lại cho những người sử dụng chúng lại chưa chắc đã cao, vì đơn giản chúng không có 1 Format thống nhất và rất dễ thiếu thông tin.

Hôm nay mình sẽ giới thiệu cho các bạn 1 Tool khá nổi tiếng trong việc viết API docs, đó là Swagger (UI). Cụ thể Swagger là gì thì các bạn có thể search để tìm hiểu, Swagger nên ở phạm vi bài viết này mình xin phép không giới thiệu lại, thay vào đó sẽ mình sẽ đi sâu vào cách triển khai Swagger theo cách “Khoa học” và “Developer” nhất có thể.

Quay lại 1 chút thì các bài viết trước đây khi hướng dẫn triển khai Swagger UI thường tiếp cận theo hướng copy UI của Swagger rồi “ném” vào Project của mình (clone lại Repository Swagger hoặc copy file CSS, JavaScript của Swagger) không thì viết sẵn 1 file XML (JSON) rồi render lại chúng ra View.

Còn cách mà “Khoa học” và theo hướng “Developers” ở đây mình muốn nói đến là:

Có khả năng tái sử dụng code, viết Docs cũng như viết Code, cái gì giống nhau là gọi lại dùng được

Dễ dàng mở rộng (Scale), ví dụ: khi thêm 1 trường vào Model hay đổi tên 1 trường chẳng hạn thì file Documents cũng tự động được update chẳng hạn

Tổ chức Trees (Cây thư mục) rõ ràng và khoa học

Trong Rails thì có 2 Gem thường được dùng để Implement Swagger là: swagger-docs và swagger-blocks. Sự khác biệt lớn nhất giữa 2 Gem này là swagger-blocks được support đến v2.0 của Swagger Specification còn swagger-docs chỉ dừng lại ở v1.2, và theo thông tin trên Repo của swagger-docs thì họ chưa có kế hoạch update lên v2.0. Do đó trong Demo này mình sẽ triển khai với gem swagger-blocks.

Note: cả 2 gem kể trên đều không sinh ra giao diện UI/UX theo kiểu Swagger mà chỉ sinh ra 1 file .json phù hợp với format của Swagger UI mà thôi, do đó để có giao diện như Swagger mang lại, chúng ta cần 1 Gem nữa là swaggeruiengine.

Bắt đầu, tạo 1 ứng dụng Rails API bằng cách gõ các lệnh sau trên Terminal:

Sau đó add thêm 2 Gem mình giới thiệu phía trên vào Gemfile rồi bundle chúng:

Note: khi triển khai thực tế mình gặp phải 1 vấn đề khi call API bằng tool Postman – tool hỗ trợ test các Request API – thì Oki nhưng khi Deploy lên Server và call API qua lại giữa các Server thì bị trả về 404, sau 1 hồi search thì tìm hiểu ra là do thiếu config CORS. Để khắc phục thì bạn chỉ cần add thêm vào Gem như sau:

và config cho Rails như sau:

Trên Repo của gem Swagger-Blocks có giới thiệu khá chi tiết về cách Setup Swagger, tuy nhiên mình thấy 1 số điểm chưa thực sự “dry” code cho lắm, do đó mình sẽ custom lại Trees (cấu trúc) của Swagger trong Project của mình 1 chút để tận dụng được những cái sài chung (tái sử dụng code í mà) như kiểu các Paramerter hay được gọi đi gọi là hoặc là các Response phổ biến (lỗi 404 hay 500 chẳng hạn). Đồng thời cũng giúp chúng ta dễ dàng mở rộng code khi cần thiết trong tương lai.

Cấu trúc thư mục của Swagger khi đó sẽ như thế này:

So sánh với tài liệu trên Repo của Swagger-Blocks thì cách tổ chức của mình có 1 vài điểm mà cá nhân mình nghĩ sẽ rành mạch và rõ ràng hơn.

Theo Swagger hướng dẫn thì mỗi Documents sẽ ứng với 1 Controller, cách viết này khá dễ hiểu, nhưng các bạn có thế dễ dàng nhận ra là Controller sẽ bị phình to “cực kỳ” nhanh nếu đặt Docs trong đó. Và Controller cũng không phải là là 1 nơi lý tưởng để xử lý Docs. Do đó, chúng ta hãy tách ra thành 1 Module riêng biệt – chuyển xử lý Docs. Cụ thể ở đây mình sẽ để vào trong thư mục concern/swagger rồi sau đó Include lại vào Controller.

Sẽ có rất nhiều Parameter dùng chung, ví dụ: userID được dùng chung khi get thông tin của User cũng như update thông tin user chẳng hạn. Do đó mình tạo ra 1 file chúng tôi để chứa những thứ dùng chung, khi cần dùng thì sẽ include lại vào file Docs (ở đây là user_api.rb)

Tương tự, sẽ có rất nhiều Response Error được dùng chung, kiểu lỗi 401 – not authorize hay là 404 – not found Records do đó mình tạo ra 1 file error_response.rb để viết chung, khi cần lại include vào file chứa Docs (ở đây là user_api.rb)

Response Success 200 tuy mỗi API sẽ trả về 1 thông tin khác nhau, nhưng không phải là không có điểm chung. Chẳng hạn, các API sau đều trả về thông tin của User sau khi Request thành công đó là: API show, API edit thông tin của User và API login. Do đó, chúng ta phải tìm cách tái sử dụng Code. May thay, với Swagger chúng ta có thể sử dụng $ref để gọi tới 1 schema được định nghĩa trước đó (ở đây là: user_schema.rb trong modes/concern/swagger)

Chú ý cần tạo Router cho Documents để còn biết URL mà xem trên trình duyệt.

Sau khi tạo Router, thì chúng ta cũng tạo ra 1 controller ứng với router này và định nghĩa các thông số cơ bản của API Documents như:

Version Swagger sử dụng -Tittle, Description của API

Đường dẫn mặc định của API

Kiểu dữ liệu sinh ra của API (thường là Json hoặc có thể là XML) ….

Trong method index của api_docs_controller các bạn nhớ gọi method để render ra những thông tin API mà mình muốn viết Docs.

Đến đây là các bạn có thể bật server lên và vào URL: localhost:3000/api_docs.json để xem thanh quả rồi.

Chúng ta sẽ dùng gem swagger_ui_engine và config 1 chút để có giao diện Swagger UI cho dữ liệu json mình vừa tạo ra ở bên trên như sau:

Xong. Tới đây bạn có thể restart lại server, truy cập lại URL localhost:3000/api_docs để thấy thành quả.

Inline Documentation For Restful Web Apis

Structure parameter like:

@apiDefine

is used to define a reusable documentation block. This block can be included in normal api documentation blocks. Using @apiDefine allows you to better organize complex documentation and avoid duplicating recurrent blocks.

A defined block can have all params (like @apiParam), except other defined blocks.

@api

@api {method} path [title]

Required!

Without that indicator, apiDoc parser ignore the documentation block.

The only exception are documentation blocks defined by @apiDefine, they not required @api.

Usage: @api {get} /user/:id Users unique ID.

Name Description

method

Request method name: DELETE, GET, POST, PUT, … More info Wikipedia HTTP-Request_methods

path Request Path.

title

optional

A short title. (used for navigation and article header)

Example:

/** * @api {get} /user/:id */

@apiBody

@apiBody [{type}] [field=defaultValue] [description]

Describe the request body passed to your API-Method.

Usage: @apiBody {type} {key: value}

Name Description

{type}

optional

Parameter type, e.g. {Boolean}, {Number}, {String}, {Object}, {String[]} (array of strings), …

{type{size}}

optional

Information about the size of the variable. {string{..5}} a string that has max 5 chars. {string{2..5}} a string that has min. 2 chars and max 5 chars. {number{100-999}} a number between 100 and 999.

{type=allowedValues}

optional

Information about allowed values of the variable. {string="small"} a string that can only contain the word “small” (a constant). {string="small","huge"} a string that can contain the words “small” or “huge”. {number=1,2,3,99} a number with allowed values of 1, 2, 3 and 99.

Can be combined with size: {string {..5}="small","huge"} a string that has max 5 chars and only contain the words “small” or “huge”.

field

Fieldname.

[field]

Fieldname with brackets define the Variable as optional.

field[nestedField]

Mandatory nested field.

=defaultValue

optional

The parameters default value.

description

optional

Description of the field.

Examples:

/** * @api {get} /user/:id * @apiParam {Number} id Users unique ID. */ /** * @api {post} /user/ * @apiParam {String} [firstname] Optional Firstname of the User. * @apiParam {String} lastname Mandatory Lastname. * @apiParam {String} country="DE" Mandatory with default value "DE". * @apiParam {Number} [age=18] Optional Age with default 18. * * @apiParam (Login) {String} pass Only logged in users can post this. * In generated documentation a separate * "Login" Block will be generated. * * @apiParam {Object} [address] Optional nested address object. * @apiParam {String} [address[street]] Optional street and number. * @apiParam {String} [address[zip]] Optional zip code. * @apiParam {String} [address[city]] Optional city. */

@apiDefine

@apiDefine name [title] [description]

Defines a documentation block to be embedded within @api blocks or in an api function like @apiPermission.

@apiDefine can only be used once per block

By using @apiUse a defined block will be imported, or with the name the title and description will be used.

Usage: @apiDefine MyError

Name Description

name

Unique name for the block / value. Same name with different @apiVersion can be defined.

title

optional

A short title. Only used for named functions like @apiPermission or @apiParam (name).

description

optional

Detailed Description start at the next line, multiple lines can be used. Only used for named functions like @apiPermission.

Example:

/** * @apiDefine MyError */ /** * @api {get} /user/:id * @apiUse MyError */ /** * @apiDefine admin User access only * This optional description belong to to the group admin. */ /** * @api {get} /user/:id * @apiPermission admin */

For more details, see inherit example.

@apiDeprecated

@apiDeprecated [text]

Mark an API Method as deprecated

Usage: @apiDeprecated use now (#Group:Name).

Name Description

text Multiline text.

Example:

/** * @apiDeprecated */ /** * @apiDeprecated use now (#Group:Name). * * Example: to set a link to the GetDetails method of your group User * write (#User:GetDetails) */

@apiDescription

@apiDescription text

Detailed description of the API Method.

Usage: @apiDescription This is the Description.

Name Description

text Multiline description text.

Example:

/** * @apiDescription This is the Description. * It is multiline capable. * * Last line of Description. */

@apiError

@apiError [(group)] [{type}] field [description]

Error return Parameter.

Usage: @apiError UserNotFound

Name Description

(group)

optional

All parameters will be grouped by this name. Without a group, the default Error 4xx is set. You can set a title and description with @apiDefine.

{type}

optional

Return type, e.g. {Boolean}, {Number}, {String}, {Object}, {String[]} (array of strings), …

field

Return Identifier (returned error code).

description

optional

Description of the field.

Example:

/** * @api {get} /user/:id */

@apiErrorExample

@apiErrorExample [{type}] [title] example

Example of an error return message, output as a pre-formatted code.

Usage: @apiErrorExample {json} Error-Response: This is an example.

Name Description

type

optional

Response format.

title

optional

Short title for the example.

example

Detailed example, multilines capable.

Example:

/** * @api {get} /user/:id * @apiErrorExample {json} Error-Response: * HTTP/1.1 404 Not Found * { * "error": "UserNotFound" * } */

@apiExample

@apiExample [{type}] title example

Example for usage of an API method. Output as a pre-formatted code.

Use it for a complete example at the beginning of the description of an endpoint.

Usage: @apiExample {js} Example usage: This is an example.

Name Description

type

optional

Code language.

title

Short title for the example.

example

Detailed example, multilines capable.

Example:

/** * @api {get} /user/:id * @apiExample {curl} Example usage: * curl -i http://localhost/user/4711 */

@apiGroup

@apiGroup name

Should always be used.

Defines to which group the method documentation block belongs. Groups will be used for the Main-Navigation in the generated output. Structure definition not need @apiGroup.

Usage: @apiGroup User

Name Description

name

Name of the group. Also used as navigation title.

Example:

/** * @api {get} /user/:id * @apiGroup User */

@apiHeader

@apiHeader [(group)] [{type}] [field=defaultValue] [description]

Describe a parameter passed to you API-Header e.g. for Authorization.

Similar operation as @apiParam, only the output is above the parameters.

Usage: @apiHeader (MyHeaderGroup) {String} authorization Authorization value.

Name Description

(group)

optional

All parameters will be grouped by this name. Without a group, the default Parameter is set. You can set a title and description with @apiDefine.

{type}

optional

Parameter type, e.g. {Boolean}, {Number}, {String}, {Object}, {String[]} (array of strings), …

field

Variablename.

[field]

Fieldname with brackets define the Variable as optional.

=defaultValue

optional

The parameters default value.

description

optional

Description of the field.

Examples:

/** * @api {get} /user/:id * @apiHeader {String} access-key Users unique access-key. */

@apiHeaderExample

@apiHeaderExample [{type}] [title] example

Parameter request example.

Usage: @apiHeaderExample {json} Request-Example: { "content": "This is an example content" }

Name Description

type

optional

Request format.

title

optional

Short title for the example.

example

Detailed example, multilines capable.

Example:

/** * @api {get} /user/:id * @apiHeaderExample {json} Header-Example: * { * "Accept-Encoding": "Accept-Encoding: gzip, deflate" * } */

@apiIgnore

@apiIgnore [hint]

Place it on top of a block.

A block with @apiIgnore will not be parsed. It is usefull, if you leave outdated or not finished Methods in your source code and you don’t want to publish it into the documentation.

Usage: @apiIgnore Not finished Method

Name Description

hint

optional

Short information why this block should be ignored.

Example:

/** * @apiIgnore Not finished Method * @api {get} /user/:id */

@apiName

@apiName name

Should always be used.

Defines the name of the method documentation block. Names will be used for the Sub-Navigation in the generated output. Structure definition not need @apiName.

Usage: @apiName GetUser

Name Description

name

Unique name of the method. Same name with different @apiVersion can be defined. Format: method + path (e.g. Get + User), only a proposal, you can name as you want. Also used as navigation title.

Example:

/** * @api {get} /user/:id * @apiName GetUser */

@apiParam

@apiParam [(group)] [{type}] [field=defaultValue] [description]

Describe a parameter passed to you API-Method.

Usage: @apiParam (MyGroup) {Number} id Users unique ID.

For nested parameters, use square bracket notation ([]).

Name Description

(group)

optional

All parameters will be grouped by this name. Without a group, the default Parameter is set. You can set a title and description with @apiDefine.

{type}

optional

Parameter type, e.g. {Boolean}, {Number}, {String}, {Object}, {String[]} (array of strings), …

{type{size}}

optional

Information about the size of the variable. {string{..5}} a string that has max 5 chars. {string{2..5}} a string that has min. 2 chars and max 5 chars. {number{100-999}} a number between 100 and 999.

{type=allowedValues}

optional

Information about allowed values of the variable. {string="small"} a string that can only contain the word “small” (a constant). {string="small","huge"} a string that can contain the words “small” or “huge”. {number=1,2,3,99} a number with allowed values of 1, 2, 3 and 99.

Can be combined with size: {string {..5}="small","huge"} a string that has max 5 chars and only contain the words “small” or “huge”.

field

Fieldname.

[field]

Fieldname with brackets define the Variable as optional.

field[nestedField]

Mandatory nested field.

=defaultValue

optional

The parameters default value.

description

optional

Description of the field.

Examples:

/** * @api {get} /user/:id * @apiParam {Number} id Users unique ID. */ /** * @api {post} /user/ * @apiParam {String} [firstname] Optional Firstname of the User. * @apiParam {String} lastname Mandatory Lastname. * @apiParam {String} country="DE" Mandatory with default value "DE". * @apiParam {Number} [age=18] Optional Age with default 18. * * @apiParam (Login) {String} pass Only logged in users can post this. * In generated documentation a separate * "Login" Block will be generated. * * @apiParam {Object} [address] Optional nested address object. * @apiParam {String} [address[street]] Optional street and number. * @apiParam {String} [address[zip]] Optional zip code. * @apiParam {String} [address[city]] Optional city. */

@apiParamExample

@apiParamExample [{type}] [title] example

Parameter request example.

Usage: @apiParamExample {json} Request-Example: { "content": "This is an example content" }

Name Description

type

optional

Request format.

title

optional

Short title for the example.

example

Detailed example, multilines capable.

Example:

/** * @api {get} /user/:id * @apiParamExample {json} Request-Example: * { * "id": 4711 * } */

@apiPermission

@apiPermission name

Outputs the permission name. If the name is defined with @apiDefine the generated documentation include the additional title and description.

Usage: @apiPermission admin

Name Description

name

Unique name of the permission.

Example:

/** * @api {get} /user/:id * @apiPermission none */

@apiPrivate

@apiPrivate

Defines an API as being private to allow the creation of two API specification documents: one that excludes the private APIs and one that includes them.

Usage: @apiPrivate

Example:

/** * @api {get} /user/:id * @apiPrivate */

@apiBody

@apiQuery [{type}] [field=defaultValue] [description]

Describe a query parameter passed to your API-Method.

Usage: @apiQuery {Number} id Users unique ID.

Name Description

{type}

optional

Parameter type, e.g. {Boolean}, {Number}, {String}, {Object}, {String[]} (array of strings), …

{type{size}}

optional

Information about the size of the variable. {string{..5}} a string that has max 5 chars. {string{2..5}} a string that has min. 2 chars and max 5 chars. {number{100-999}} a number between 100 and 999.

{type=allowedValues}

optional

Information about allowed values of the variable. {string="small"} a string that can only contain the word “small” (a constant). {string="small","huge"} a string that can contain the words “small” or “huge”. {number=1,2,3,99} a number with allowed values of 1, 2, 3 and 99.

Can be combined with size: {string {..5}="small","huge"} a string that has max 5 chars and only contain the words “small” or “huge”.

field

Fieldname.

[field]

Fieldname with brackets define the Variable as optional.

field[nestedField]

Mandatory nested field.

=defaultValue

optional

The parameters default value.

description

optional

Description of the field.

Examples:

/** * @api {get} /user/:id * @apiQuery admin */

@apiSampleRequest

@apiSampleRequest url

Use this parameter in conjunction with the chúng tôi configuration parameter sampleUrl.

If sampleUrl is set, all methods will have the api test form (the endpoint from @api will be appended).Without sampleUrl only methods with @apiSampleRequest will have a form.

if @apiSampleRequest url is set in a method block, this url will be used for the request (it overrides sampleUrl when it starts with http).

If sampleUrl is set and you don’t want a method with a test form, then add @apiSampleRequest off to the documentation block.

Usage: @apiSampleRequest http://test.github.com

Name Description

url

Url to your test api server.

Overwrite the configuration parameter sampleUrl and append @api url: @apiSampleRequest http://www.example.com

Prefix the @api url: @apiSampleRequest /my_test_path

Disable api test if configuration parameter sampleUrl is set: @apiSampleRequest off

Examples:

This will send the api request to http://api.github.com/user/:id

Configuration parameter sampleUrl: "http://api.github.com" /** * @api {get} /user/:id */

This will send the api request to http://test.github.com/some_path/user/:id It overwrites sampleUrl.

Configuration parameter sampleUrl: "http://api.github.com" /** * @api {get} /user/:id * @apiSampleRequest http://test.github.com/some_path/ */

This will send the api request to http://api.github.com/test/user/:id It extends sampleUrl.

Configuration parameter sampleUrl: "http://api.github.com" /** * @api {get} /user/:id * @apiSampleRequest /test */

This will disable the api request for this api-method.

Configuration parameter sampleUrl: "http://api.github.com" /** * @api {get} /user/:id * @apiSampleRequest off */

This will send the api request to http://api.github.com/some_path/user/:id It activates the request for this method only, because sampleUrl is not set.

Configuration parameter sampleUrl is not set /** * @api {get} /user/:id * @apiSampleRequest http://api.github.com/some_path/ */

@apiSuccess

@apiSuccess [(group)] [{type}] field [description]

Success return Parameter.

Usage: @apiSuccess {String} firstname Firstname of the User.

Name Description

(group)

optional

All parameters will be grouped by this name. Without a group, the default Success 200 is set. You can set a title and description with @apiDefine.

{type}

optional

Return type, e.g. {Boolean}, {Number}, {String}, {Object}, {String[]} (array of strings), …

field

Return Identifier (returned success code).

description

optional

Description of the field.

Example:

/** * @api {get} /user/:id * @apiSuccess {String} firstname Firstname of the User. * @apiSuccess {String} lastname Lastname of the User. */

Example with (group), more group-examples at @apiSuccessTitle:

/** * @api {get} /user/:id * @apiSuccess (200) {String} firstname Firstname of the User. * @apiSuccess (200) {String} lastname Lastname of the User. */

Example with Object:

/** * @api {get} /user/:id * @apiSuccess {Boolean} active Specify if the account is active. * @apiSuccess {Object} profile User profile information. * @apiSuccess {Number} chúng tôi Users age. * @apiSuccess {String} profile.image Avatar-Image. */

Example with Array:

/** * @api {get} /users * @apiSuccess {Object[]} profiles List of user profiles. * @apiSuccess {Number} chúng tôi Users age. * @apiSuccess {String} profiles.image Avatar-Image. */

@apiSuccessExample

@apiSuccessExample [{type}] [title] example

Example of a success return message, output as a pre-formatted code.

Usage: @apiSuccessExample {json} Success-Response: { "content": "This is an example content" }

Name Description

type

optional

Response format.

title

optional

Short title for the example.

example

Detailed example, multilines capable.

Example:

/** * @api {get} /user/:id * @apiSuccessExample {json} Success-Response: * HTTP/1.1 200 OK * { * "firstname": "John", * "lastname": "Doe" * } */

@apiUse

@apiUse name

Include a with @apiDefine defined block. If used with @apiVersion the same or nearest predecessor will be included.

Usage: @apiUse MySuccess

Name Description

name

Name of the defined block.

Example:

/** * @apiDefine MySuccess * @apiSuccess {string} firstname The users firstname. * @apiSuccess {number} age The users age. */ /** * @api {get} /user/:id * @apiUse MySuccess */

@apiVersion

@apiVersion version

Set the version of an documentation block. Version can also be used in @apiDefine.

Blocks with same group and name, but different versions can be compared in the generated output, so you or a frontend developer can retrace what changes in the API since the last version.

Usage: @apiVersion 1.6.2

Name Description

version

Simple versioning supported (major.minor.patch). More info on Semantic Versioning Specification (SemVer).

Example:

/** * @api {get} /user/:id * @apiVersion 1.6.2 */

For more watch versioning example.

Tôi Đã Viết Api Document Cho Dự Án Như Thế Nào?

Xin chào các bạn, hiện tại sau khi dự án của mình hoàn thành được phase 1 thì công việc cần thiết bây giờ là phải viết lại tài liệu dự án để sau này dễ dàng bảo trì, phát triển hoặc bàn giao dự án cho đội phát triển tiếp theo.

Đầu tiên mình nghĩ nó cũng chỉ đơn giản thôi, nhưng mà không. Lúc bắt tay vào làm thì mới thấy nó có nhiều cái phức tạp, và cái hay ho nhất mà mình thu về được đó là việc viết API document. Sau một hồi mình viết document bằng “cơm” thì được anh em khai sáng cho một số Tools hỗ trợ việc viết API document.

Và trong bài viết này, mình xin phép được chia sẻ một công cụ khá hay cũng như sơ qua cách sử dụng Laravel Api Doc Generator. Hi vọng rằng bài viết này có thể hỗ trợ cho những bạn “lần đầu làm chuyện ấy” giống như mình.

Và sau một hồi tìm kiếm ở tận phương trời xa lắm, thì mình phát hiện ra là Laravel cũng có một công cụ hỗ trợ việc viết API Document.

Sơ qua 1 chút thông tin trên github của laravel-apidoc-generator:

Như các bạn có thể thấy thì commit mới nhất trên repo này là vào 15/6, tức là nó vẫn đang được phát triển liên tục.

Còn về số sao mà cộng đồng đánh giá thì rơi vào khoảng 2000 sao, không phải quá cao nhưng cũng là 1 mức đáng ngưỡng mộ đối với một repo opensource mới.

Yêu cầu cài đặt: tối thiểu PHP 7 và Laravel 5.5.

Cài đặt:

Cài đặt bằng composer:

composer required mpociot/laravel-apidoc-generator

Khai báo trong service provider trong file bootstrap/app.php:

Tạo file config: sau khi chạy câu lệnh này, trong thư mục config của project sẽ xuất hiện file apidoc.php

php artisan vendor:publish --provider= "MpociotApiDocApiDocGeneratorServiceProvider" --tag=apidoc-config

Thử vọc vạch 1 số thứ trong config xem sao?

Cách thức thực hiện:

Cài đặt các thứ đã xong xuôi hết rồi, giờ thì chạy xem thành quả của mình nào.

php artisan apidoc:generate

Sau khi quá trình này được hoàn tất, tài liệu HTML sẽ được ghi vào file: publicdocsindex.html

B2: Bật server và kiểm tra kết quả thu được

Tiếp theo, hãy bật server lên với câu lệnh

php artisan serve

Ở cột ngoài cùng bên trái là list những api được sử dụng trong project mà đã được lấy ra (trừ một số cái bị skip ở bước 1).

Phần còn lại là thông tin chi tiết của API đấy:

Phương thức: GET/POST/PATCH/PUT/DELETE

Route:

Example request & example response:

Có người từng nói “Miếng phô mai có sẵn chỉ có ở trên bẫy chuột”. Vì vậy chúng ta không thể dùng ngay như bên trên được (chỉ là demo một chút cho các bạn thôi) mà phải cất công cấu hình một chút cho phù hợp với project và nhu cầu của bản thân!

Giờ thì cùng xem file config/apidoc.php có những thông số gì nào?

All Rights Reserved

Cách Viết Specs Document Cơ Bản Và 7 Technique Để Viết Document Rõ Ràng, Dễ Hiểu

Nguồn bài viết : サンプル例に見る機能仕様書の基本的な書き方&読みやすくする7つのテクニック

Trong bài viết trước tác giả đã giải thích tầm quan trọng của document đối với communication trong dự án phát triển hệ thống IT, trong đó đã giới thiệu về 1 trong 3 loại document quan trọng là “Functional Specifications của Joel”. Trong bài viết này tác giả sẽ giải thích cụ thể về cách viết loại document này.

“Functional Specifications của Joel” là loại Specifications document về các màn hình và thao tác sử dụng software dựa trên quan điểm người dùng, là loại document chia sẻ thông tin giữa người dùng và người phát triển hệ thống. Vì không phải là document dành cho engineer nên tránh dùng nhiều từ ngữ chuyên ngành kĩ thuật khó hiểu.

Document gồm các mục sau

『Mở đầu』

Mục này sẽ viết vị trí các phần trong document và các lưu ý đối với người đọc khi đọc document. Ví dụ như trong document của Joel, ông viết là “Đây không phải là một document hoàn thiện”, nghĩa là document giống như 1 vật thể sống, sau này sẽ còn được cập nhật nhiều lần. Viết như thế này sẽ giúp người đọc tránh được hiểu lầm rằng đây là 1 document đã hoàn thiện không có sửa đổi gì nữa. Ngoài ra cũng có thể viết về mục đích của hệ thống, suy nghĩ nhắn nhủ với engineer…

『Scenario』

Để biết được hình ảnh của hệ thống khi thực tế sử dụng sẽ như thế nào thì cần viết scenario (story) theo cách nhìn của người dùng.

・Scenario là gì?

Scenario là văn bản viết các sự việc xảy ra theo mốc thời gian đúng theo trình tự triển khai của story. Những nhân vật sẽ xuất hiện và hành động của nhân vật đó, cùng với kết quả xử lí trả lại từ hệ thống được viết theo trình tự diễn ra 1 cách cụ thể.

・Cách viết scenario

Để người đọc không bị hiểu nhầm thì cần viết càng cụ thể càng tốt về tình huống sử dụng 1 cách dễ hiểu, ví dụ như đặt tên cho nhân vật, địa điểm sẽ xuất hiện.

Trường hợp nội dung quá phức tạp không thể viết hết trong 1 scenario thì nên chia ra theo đơn vị chức năng hoặc đơn vị màn hình, điều chỉnh cho phù hợp với từng hệ thống.

『Đối tượng ngoài』(hoặc là phạm vi ngoài)

Phần này sẽ viết những đối tượng ngoài phạm vi xử lí của hệ thống. Theo một ý nghĩa nào đó thì đây có lẽ là 1 trong những quan trọng nhất.

Trong quá trình làm dự án, khi phát hiện ra chức năng không có ghi trong document thì sẽ xảy ra 2 cách giải thích như sau:

Đây là chức năng cần thiết phải làm mà quên không viết vào document

Nếu không viết trong document thì chắc chắn là chức năng không cần làm

Trong hầu hết các trường hợp, 2 cách lý giải này sẽ gây ra hiểu nhầm , thường phía người dùng sẽ lý giải theo cách 1 còn team phát triển sẽ lý giải theo cách 2.

Để tránh gây ra hiểu nhầm như thế này thì nên viết những chức năng không làm vào mục “đối tượng ngoài” ở ngay phần đầu của document nơi dễ nhận thấy.

『Flow chart khái quát』(hoặc là Overview)

Đây sẽ là mục giải thích khái quát toàn bộ hình ảnh các chức năng của hệ thống trước khi đi vào các chức năng cụ thể. Có thể viết dạng flow chart hoặc bất cứ dạng nào khái quát được tổng thể toàn thể hệ thống. Thường có những loại như sơ đồ di chuyển màn hình, bản đồ flow nghiệp vụ, bản đồ usecase, list các chức năng…

Tất nhiên nếu văn bản có thể giải thích được đầy đủ cụ thể thì cũng không có vấn đề, quan trọng là nhìn từ quan điểm của người dùng có dễ hiểu hay không.

『Specification theo từng màn hình』(Specification chi tiết)

Phần này sẽ giải thích chi tiết các chức năng đã giải thích cơ bản ở phần “Khái quát”, là phần quan trọng nhất của 1 specification document.

Cần chú ý viết đủ, không sót các mục trong phạm vi đã nêu ra ở phần khái quát. Để làm được điều này cần phải chia mục 1 cách đầy đủ và hợp lí.

Màn hình có thể thực tế nhìn thấy nên là 1 đơn vị chia dễ hiểu và khó có thiếu sót. Ngoài ra còn có cách chia theo đơn vị chức năng , theo đơn vị input, output dữ liệu…

・Đặt tên cho các mục đã chia chi tiết

Khi đã chia các mục chi tiết rồi thì cần đặt tên cho chúng, nhằm giúp bất kì ai khi đọc document đều không bị hiểu nhầm mà có thể hiểu ngay được. Ví dụ như màn hình A, chức năng B, file C…đặt tên theo quy tắc cụ thể và ngắn gọn.

・Viết về các chức năng một cách cụ thể, chi tiết

Viết từng chức năng của hệ thống một cách cụ thể, chi tiết để người dùng có thể hiểu được. Bắt đầu từ chức năng cơ bản, rồi đến chức năng phụ trợ, hoạt động của màn hình, dữ liệu và file được export ra , các thao tác xảy khi có lỗi…nếu cần thiết sẽ có thêm các mục nhỏ trong từng chức năng.

Ở đây, quan điểm giải thích cũng là nhìn từ phía người dùng, xem người dùng nhìn hệ thống như thế nào rồi mới viết giải thích. Giải thích chi tiết này chính là điểm xuất phát quan trọng của document thực hiện, bởi trong quá trình thực hiện và test, để confirm mục đích và ý nghĩa của từng chức năng thì engineer cần xem lại document này rất nhiều lần.

『Những vấn đề chưa quyết định』(Hay To be determined – TBD)

Mục này sẽ viết những vấn đề hiện tại chưa thể giải quyết, quyết định được ngay, trong quá trình phát triển hệ thống rất hay nảy sinh ra những vấn đề như thế này. Để tránh việc bị thiếu trong quá trình viết thì khi nhận thấy vấn đề cần viết ngay lại chứ không chờ sau này mới tổng hợp lại.

『Technical memo』(Memo đặc biệt)

Phần này sẽ viết những ghi chú cho tầng độc giả đặc biệt. Người viết document hầu hết là người xuất thân từ ngành kĩ thuật. Document phải viết theo quan điểm của người dùng nhưng trong khi viết nhiều khi người viết nảy ra ý tưởng về cách giải quyết các vấn đề kĩ thuật. Nếu quên mất thì sẽ rất lãng phí nên cần tạo một mục gọi là “Technical memo” để ghi lại những ý tưởng như vậy.

【1】Viết câu ngắn gọn rõ ý

Viết từng câu càng ngắn càng tốt, nếu câu dài thì nên chia ra. Nên tránh cách viết mơ hồ, câu mang nhiều ý nghĩa, trong khả năng có thể viết câu ngắn gọn , ý nghĩa trọn vẹn trong 1 câu để người đọc dễ hiểu hơn.

Trong trường hợp nội dung nhiều không thể nói hết trong 1 câu thì dùng cách viết như “Nguyên tắc là…, tuy nhiên…”, đầu tiên nêu nội dung chủ đạo rồi sau đó thêm vào các trường hợp ngoại lệ, từ đó nêu rõ được ý muốn nói.

【2】Không tạo document template

Trong các doanh nghiệp hay tổ chức thường hay có những template cơ bản định hình các mục nên viết trong document, song điều này không được khuyến khích đối với người viết thông thường. Mỗi dự án phát triển lại có những nội dung, chức năng, quy mô, kiến trúc hệ thống khác nhau, từ đó mà những mục nên viết trong document cũng sẽ khác nhau. Vì vậy điều quan trọng là cần liệt kê được các mục cần có này khi thiết kế hệ thống.

Nếu cứ cố gắng tạo 1 template thì sẽ cần kết hợp các mục trong document của dự án 1 tỉ yen với dựa án 2 triệu yen, chỉ có cách đó mới tránh được việc thiếu sót khi liệt kê ra các mục cần thiết. Template cũng có thể tạo được, tuy nhiên chỉ giới hạn ở lĩnh vực và quy mô của đối tượng hệ thống cụ thể.

【3】『Tiêu đề, các đầu mục』chiếm 80% document

Để viết được document rành mạch dễ hiểu cần viết được nội dung 1 cách cụ thể, chi tiết, chia nhỏ các mục ra chứ không được viết gộp hết vào 1 mục. Chúng ta có thể sử dụng triệt để tiêu đề để làm được điều đó.

Tiêu đề chính là tên của 1 mục, có thể viết nội dung trước gắn tiêu đề sau, tuy nhiên nếu có thể thì nên xác định tiêu đề trước khi viết. Điều này sẽ giúp tránh được sai sót, giúp document rõ ràng dễ hiểu. Theo kinh nghiệm bản thân tác giả thì chỉ cần viết được hết ra các tiêu đề của đề mục là có cảm giác như đã hoàn thành 80% document rồi.

【4】Thứ tự các mục có thể quyết định sau

Ngay khi mới bắt đầu viết document thì sẽ có trường hợp chưa nhìn thấy được hình ảnh toàn cảnh, cấu trúc của document nên khi đó chưa cần quan tâm đến thứ tự các mục mà cứ viết hết ra những mục được cho là cần thiết. Sau đó đến 1 thời điểm nhất định sẽ nhìn ra được mối quan hệ giữa các mục, khi đó sắp xếp thứ tự cho chúng cũng chưa muộn.

【5】Những vấn đề chưa được quyết định gây băn khoăn

Nếu trong khi viết có những vấn đề chưa rõ ràng, chưa được quyết định thì cũng không nên băn khoăn mà dừng lại, chỉ cần đánh dấu chúng là “TBD – To be determined” là được. Những vấn đề này sẽ được giải quyết ở những cuộc họp hoặc điều tra, nghiên cứu riêng, khi đã được giải quyết rồi thì sẽ cập nhật lại document.

【6】Đùa vui trong chừng mực

Đặc biệt trong khi viết scenario thì để cho dễ hiểu và việc đọc trở nên thú vị hơn thì có thể sử dụng những câu đùa, tuy nhiên nên ở trong chừng mực và khi viết thì nên xem xét đối tượng đọc là ai.

Trong document của Joel có xuất hiện những câu đùa mà chỉ riêng những người trong một tổ chức mới hiểu được, song về cơ bản ở các document thì nên sử dụng ngôn ngữ formal tránh gây cảm giác là 1 tác phẩm mang xu hướng cá nhân hay thương hiệu riêng của cá nhân.

【7】Thường xuyên giữ cho document là 1 “thực thể sống”

Trong quá trình phát triển dự án người chịu trách nhiệm viết document cần phải thường xuyên cập nhật những thay đổi về chức năng, về những yêu cầu mới quyết định…điều này đồng thời tạo nên thành công cho document và cả dự án. Bởi như đã nói ở phía trên, việc này mang lại lợi ích trong nghiệp vụ phát triển dự án và tránh được những rủi ro không đáng có.

Dễ dàng tạo được những đoạn văn bản có tiêu đề

Dễ dàng chia sẻ được phiên bản online mới nhất 1 cách thường xuyên

Có thể thêm vào bảng hay biểu đồ.

Có thể xác định được lịch sử thay đổi cũng như các nội dung đã thay đổi

Những tool mà tác giả hay sử dụng

* A. Google document+「Table of contents」add-on

* B. Microsoft Word

* C. Markdown text+Subversion(hoặc là Git)

Đầu tiên là các tool tạo slide giống như Microsoft PowerPoint, bởi các slide tạo cảm giác mỗi slide là một đơn vị thông tin, nên sẽ không thể hiện được tính logic toàn bộ của document.

Ngoài ra với cùng lý do kể trên thì những tool như Microsoft Excel cũng nên tránh bởi chúng chia đơn vị theo sheet, theo cell gây khó khan trong việc thay đổi, sửa chữa vì document thường đi theo một mạch liên kết toàn thể.

Ai là người nên viết document

Theo Joel thì người nên viết document là program manager, người này sẽ đứng giữa team phát triển và người dùng để quyết định, điều chỉnh specification cho phù hợp.

Điều kiện của người viết document

Có thể viết được văn bản rõ ràng rành mạch, logic

Có thể đối thoại với người dùng và hiểu được người dùng

Xuất thân là nguời làm kĩ thuật hoặc có được kiến thức kĩ thuật trong 1 lĩnh vực cụ thể

Không viết document không thể hiện thực hóa trên phương diện kĩ thuật

Có thể đối thoại với team phát triển

Không nhất thiết cần là 1 programmer giỏi

Ít nhất cần có kiến thức cơ bản về thiết kế UI/UX

(Trường hợp phát triển sản phẩm của công ty) Cần có hiểu biết về đối tượng thị trường của sản phẩm  Khó ai có thể đáp ứng được tất cả những yêu cầu kể trên, song ít nhất thì cũng cần phải viết được văn bản rõ ràng dễ hiểu hợp logic

Trong bài viết lần này tác giả đã giải thích cụ thể cách viết document theo phong cách của Joel, làm giảm communication lost giữa người dùng và team phát triển, từ đó tăng năng suất cho toàn dự án.

All Rights Reserved