Requirements:
The backend students who write interface documents for client colleagues have recalled the blood and tears of handwritten documents before using automated document tools on various occasions.
My story is different, because first of all, I am in the company is the head of the Android group, the history of the blood and tears of the client camp.
But the history of blood and tears is interlinked, there is no automated document days, the interface is the development process of the lowest efficiency link.
It is therefore decided to use swagger to build the process of generating documents from PHP annotations.
Background:
Our RESTful API Project uses the Phalcon framework, the overall structure is very simple, we only need to use Swagger Scan Controller directory.
Hereinafter referred to as our PHP API project for Php_api_project.
The server uses Nginx.
Build:
Let's say what the Final Document generation process will look like, so that you have a holistic understanding:
After the completion of the construction, the entire process, from the document generation to the front-end display, generally as follows:
1. Write the/** annotation in swagger format in PHP file * *
2. Use the Bin/swagger.phar command in swagger-php to scan the directory of PHP controller to generate Swagger.json files
3. Copy swagger.json file into Swagger-ui index.html specified directory
4. Open the URL where Swagger-ui is located and you can see the document. The individual APIs in the document can access the data directly from the Web site.
Implementing this requirement requires only swagger of the following two projects:
swagger-php: Tool for scanning PHP annotations. Contains a good example.
Swagger-ui: The Swagger.json file content that is generated by the scan tool is displayed on the Web page.
First download the two items to the Local:
$ git clone https://github.com/swagger-api/swagger-ui.git
$ git clone https://github.com/zircote/swagger-php.git
Document Generation tool deployment:
It's about deployment, and it's mainly about generating bin/swagger this command to generate Swagger.json files.
The main work is to use composer to solve the dependency on it.
Because the domestic direct with composer compare egg pain, so the best set of the domestic composer source.
In this way, the entire document generation tool is deployed with the following three lines of command:
$ cd swagger-php
$ composer Config Repo.packagist composer Https://packagist.phpcomposer.com
$ composer Update
As long as there is no error in the middle, even if the deployment completed. When you are finished, you can generate a document to try.
Under the examples directory under the Swagger-php project, there is a sample PHP project that has written various interface annotations in swagger format, and we try to generate a document.
Execute the following command:
$ cd swagger-php
$ mkdir json_docs
$ php./bin/swagger/examples-o json_docs/
The above command scans the PHP file comments in the examples directory and then generates Swagger.json files in the Json_docs directory.
This Swagger.json file is the API documentation file that the front-end Swagger-ui uses to showcase.
Note:swagger-php is just a tool and can be put anywhere.
front-end Swagger-ui deployment:
The deployment method is simple, three steps:
1. Copy the Dist folder in the Swagger-ui project to the Php_rest_api root directory.
NOTE1: Just copy the Dist folder. It's best to rename it, for simplicity, this is no longer renamed.
NOTE2: Our project root directory and Nginx configuration root are the same directory. In fact, you don't have to put it in the directory, just put it in a directory that spans across domains without cross-domain access. Why is there a cross-domain problem? I'll talk about it later.
2. Modify the index.html file under the Dist folder and specify the directory where Swagger.json resides
Just change one line to do it.
For simplicity, here you specify the Swagger.json directory directly in the Dist directory. Here are the preset conditions:
Suppose the host of the Php_api_project project is api.my_project.com;
Assume that the root of the Php_api_project project is its roots as specified in Nginx;
Suppose the Dist folder in Swagger-ui is placed in the root directory above;
Assume that the Swagger.json document is intended to be placed in the above Dist directory (Php_api_project/dist/swagger.json);
So in index.html, change the following fragment to this:
var url = window.location.search.match (/url= ([^&]+)/);
if (URL && url.length > 1) {
URL = decodeuricomponent (url[1]);
} else {
<!--This is the line that you created swagger . JSON can be accessed to the path-->
url = "Http://api.my_project.com/dist/swagger.json";
}
3. Copy Swagger.json to the above directory.
# put Swagger-php_dir this, replace your swagger-php record can
CP Swagger-php_dir/json_docs/swagger.json php_api_project/dist/
Once the above steps are complete, you will see the API documentation for examples that small project when you visit http://api.my_project.com/dist/index.html.
Write PHP Comments:
There are a number of relevant examples in the Example of the Swagger-php project, which can be copied and pasted.
More specific documentation of the relevant annotation rules, see here:
Http://bfanger.nl/swagger-explained/#/swaggerObject
Assuming that my Project controller directory is php_api_project/controller/, then I just need to scan this directory on it, without scanning the entire PHP project.
In order to generate some unified configuration in the Swagger.json, the Php_api_project/controller/swagger directory is established. The directory contains a php file with no code, which writes only comments.
I named this document swagger.php, the general content is as follows:
<?php
/**
* @SWG \swagger (
* schemes={"http"},
* host= "api.my_project.com",
* consumes={"Multipart/form-data"},
* produces={"Application/json"},
* @SWG \info (
* version= "2.3",
* title= "My Project Doc",
* description= "My Project interface document, v2-3.<br>
after everyone here happy to the interface to the!<br>
after everyone here happy to interface to the!<br>
after everyone here happy to the interface of the!<br>
"
* ),
*
* @SWG \tag (
* name= "user",
* description= "Customer action",
* ),
*
* @SWG \tag (
* name= "MainPage",
* description= "homepage module",
* ), * * @SWG \tag (
* name= "News",
* description= "Information", * ),
*
* @SWG \tag (
* name= "Misc",
* description= "Other interface",
* ),
*)
As shown above, my PHP file is not one line of PHP code, only annotations, in order to define some global swagger settings:
Schemes: Use protocol (can fill in a variety of agreements)
Host: Project address, which is used as the URL base for each interface and is spliced as an access address
Consumes: The MIME type that the interface receives by default, and the FormData in my example corresponds to the Post form type. Note that this is the project default value that can be overwritten in a single interface annotation.
Produces: interface default reply MIME type. API interfaces are more Application/json and application/xml.
@SWG \info: The contents of this fill are placed at the beginning of the document and used as a document description.
@SWG \tag:tag is used to categorize documents, the Name field must be unique. An interface can specify multiple tags, and it appears in multiple groups of categories. Tag can be used without having to define it here, but that's not a description. To say nothing is useless, to use it slightly is to understand everything.
Then you write a swagger format annotation for each interface. Let's just raise a chestnut:
/** * @SWG \post (path= "/user/login", tags={"user"}, * summary= "Login interface (username + password)", * description= "User login interface, account can be user name or mobile number . Reference (this will produce a link on the page to jump: [user Login Notes] (http://blog.csdn.net/liuxu0703/), * @SWG \ Parameter (name= "UserName", type= "string", Required=true, in= "FormData", * description= "Login username/mobile number" * ), * @SWG \parameter (name= "password", type= "string", Required=true, in= "FormData", * description= "Login password" * ), * @SWG \parameter (name= "Image_list", type= "string", Required=true, in= "FormData", * @SWG \schema (type= "Array", @SWG \items (ref= "#/definitions/image")), * description= "user albums. Well, nobody asks for a bunch of picture information when they log in. This is for example with structured data, @SWG \schema, this structure needs to be defined separately, as follows. " * ) * @SWG \parameter (name= "video", Type= "string", Required=true, in= "FormData", * @SWG \schema (ref= "#/definitions/video"), * description= "Users uh ... Video? Ditto, for example @SWG \schema. " * ), * @SWG \parameter (name= "Client_type", type= "integer", Required=false, in= "FormData", * description= The client type that called this interface: 1-android, 2-ios. Not required, so required wrote false " * ", * @SWG \ Parameter (name= "Gender", type= "integer", Required=false, in= "FormData", * default= "1", * description= "Sex: 1-male; 2-Female. Note that this parameter is written on the defaultis the default value of the parameter, but the value that will be filled out on the Swagger page by default, in order to facilitate access to the interface in swagger. " * ), *) / public function loginaction () { //PHP code  }/** * @SWG \get (path= "/user/mywebpage", tags={"User"}, * produces ={"Text/html"}, * summary= "user's personal page", * description= "This is not an API interface, this returns a page, so produces wrote text/html", * Swg\parameter (name= "UserId", type= "integer", required=true, in= "Query"), * @SWG \parameter (name= "Usertoken", type= "s Tring ", Required=true, in=" Query ", * description=" User token ", *), *)/Public Function MYWEBPA
Geaction () {//PHP code}
The rules are simple and clear, and we all understand the code. If you don't understand, go to the document ...
The login interface above has two structured data, one is an array of image types, and one is the structure of the video type.
(In fact, structured parameters can only be used when in= "body", but this does not prevent us from formatting the structured data into JSON when the string is passed in order to simplify the problem.) We just have to show this structure in the document.
This structured stuff swagger can also be defined with a PHP annotation:
<?php
/**
* @SWG \definition (type= "Object", @SWG \xml (name= "Image")) */
class Image {
/**
* @SWG \property ()
* @var String */public
$url;
/**
* @SWG \property (format= "Int32")
* @var int */public
$height;
/**
* @SWG \property (format= "Int32")
* @var int */public
$width;
}
<?php
/**
* @SWG \definition (type= "Object", @SWG \xml (name= "video")) */
class Video {
/**
* @SWG \property ()
* @var String */public
$url;
/**
* @SWG \property ()
* @var String */public
$thumb _url;
/**
* @SWG \property (format= "Int32")
* @var int */public
$length;
/**
* @SWG \property (format= "Int64")
* @var int */public
$size;
}
So that when these two classes are scanned by Swagger-php/bin/swagger, the other places can correctly refer to both the Image and the video as the name of the two structures.
The advantage of this is that in the interface parameter document, the structure is displayed so that the client knows what structure to pass.
My interface chestnuts do not write response rules because we use JSON as the return vector, and the error code is also included in this JSON structure. And most interfaces return the JSON format is very complex, with swagger response rules are basically impossible to describe.
Swagger's response rules are written according to HTTP response code (404, 401, etc.), in short, for our interface, this set of descriptive rules is not easy to use.
So I simply discarded the response description, directly using the swagger in-place request interface to see what was returned. The return information of the interface is generally described in the description.
Once the document has been written, you can call the Swagger-php/bin/swagger command to generate Swagger.json, and then copy it to the directory you specified in Swagger-ui to access the document.
Note:
We should have seen it, in fact, the annotation of the interface is not necessarily written on the interface, write a note from scratch, as well as generate documents. So don't dwell on where the notes are placed. For example swagger overall definition, tag definition, etc., written in any can be scanned into the PHP file can be.
A brief description of the commonly-described paragraph:
Here is a brief explanation of the translation, a more detailed description of the field, or to see the document. Post the document again:
Http://bfanger.nl/swagger-explained/#/swaggerObject
Interface Description (@SWG \get, @SWG \post, etc.) commonly-asked fields:
A
brief introduction to the Summary-string interface, which will be displayed on the interface header, cannot exceed 120 characters
description-string
interface details
externaldocs-string
External Document Link
operationid-string
globally unique interface identity
consumes-
MIME type received by the [string] interface
produces-[string] The
MIME type returned by the interface, such as the
protocol supported by the Application/json schemes- [string]
interface, is limited to: "http", "https", "ws", "WSS"
Parameters- [Parameter Object | Reference Object
argument list
Parameter description (@SWG \parameter) commonly-asked fields:
The name of the name-string
parameter. When passing through a path (in the value of "path") There are considerations, useless, lazy to read ...
where in-string parameters come from. Must fill in the value only: "Query", "header", "Path", "FormData", "Body"
description-string
parameter description. Better not be too Long
type-string
parameter type. Value is limited to: "string", "Number", "Integer", "Boolean", "Array", "File"
required-boolean
parameter must be. You must be true when you pass a path argument (in the value "path").
Default-*
defaults. It's a lot of rules when you're going to pass the parameters through path, and I don't use it. Read the document to your classmates.
the problems encountered:
cross-domain issues:
Swagger Cow x is where it can access the interface and display the output on the document, which is very handy for debugging and interfacing with interfaces. However, if you do not want to deploy Swagger-ui under an interface project, you will not be able to request results for cross-domain problems when you swagger-ui an in-place access interface. (Response headers:no Response from server; Response body:no content).
Here does not say how to solve the cross-domain problem, but to meet the above problems of the people a thought, know that the error is generated by the Cross-domain, it is a good solution.
Login Authentication:
If you want to put the document on a public network, it is not appropriate to expose your interface directly. Therefore, the access address of the document should be given a right of authentication.
Because of the low security requirements and the small number of people in the company's smaller development team, I used the HTTP basic auth provided by Nginx as a login authentication.
The old rules, put the official documents first:
https://www.nginx.com/resources/admin-guide/restricting-access-auth-basic/
It's a simple way to do this, and it's done in minutes. Not in detail, just two steps:
1. First use the HTPASSWD command to generate account names and passwords for students who need access to the document:
$ HTPASSWD-CB your/path/to/api_project_accounts.db admin password_for_admin
$ htpasswd-b your/path/to/api_ Project_accounts.db Liuxu 123456
$ htpasswd your/path/to/api_project_accounts.db xiaoming
The-C option indicates that if the account file (api_project_accounts.db) does not exist, the new. So you must add-c when you create the first account, then you must not add-C.
The-b parameter represents the plaintext specified password, which is the last input (Password_for_admin, 123456) in the first and second commands above. So if you don't want to specify it explicitly, you can do without-B, like the third command above, so you can enter an invisible password as in the sudo command.
The above command creates three accounts, admin, Liuxu, Xiaoming, and saves the account password in the Api_project_accounts.db file.
2. Then open HTTP Basic auth to this access address in Nginx's project configuration.
location/dist {
auth_basic "My API Project login";
Auth_basic_user_file your/path/to/api_project_accounts.db;
}
Remember to change the restart Nginx:
Nginx-s Reload
Such a simple login authentication is established.
Appendix:
Swagger Official Website:
http://swagger.io/
Swagger Project Address:
Https://github.com/swagger-api
Https://github.com/swagger-api/swagger-ui
Swagger PHP is a separate project:
https://github.com/zircote/swagger-php
Swagger Document reference Address:
Http://bfanger.nl/swagger-explained/#/swaggerObject