Swaggerの各フィールドの詳細

Info

info:
  title: Sample API
  description: A short description of API.
  termsOfService: http://example.com/terms/
  contact:
    name: API support
    url: htttp://www.example.com/support
    email: support@example.com
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 1.0.0

servers

servers:
  - url: https://dev.sample-server.com/v1
    description: Development server
  - url: https://stg.sample-server.com/v1
    description: Staging server
  - url: https://api.sample-server.com/v1
    description: Production server

Path

paths:
  /users:
    get:
      tags:
        - users
      summary: Get all users.
      description: Returns an array of User model
      parameters: []
      response:
        '200': # http status
          description: A Json array of User model
          content:
            application/json: # レスポンスの形式指定
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User' # 参照するモデル
                example: 
                  - id: 1
                    name: Jane Doe
                  - id: 2
                    name: Jane Doe
    post:
      tags:
        - users
      summary: Create a new User
      descrpption: Create a new User
      parameters: []
      requestBody:
        description: user to create
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
            example:
              id: 3
              name: Richard Roe
      responses:
        '201':
          description: CREATED
  /users/{userId}:
    get:
      tags:
        - users
      summary: Get user by ID.
      description: Returns a single User model
      parameters: # リクエストパラメター
        - name: userId
          in: path # パラメータをパス内に含める
          description: user id
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: A single User model
          content:
            application/json:
              schema:
                type: object
                items:
                  $ref: '#/components/schemas/User'
                example:
                  id: 1
                  name: John Doe

components
L 定義したモデルは $ref: ‘#/components/schemas/User’ というように参照する
L modelエリアに表示され、構造やサンプル値が参照できる

components:
  schemas:
    User:
      type: object # 型
      required:
        - id
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
    Product:
      type: object
      required:
        - id
        - price
      properties:
        id:
          type: integer
          format: int64
          example: 1
        name:
          type: string
          example: Laptop
        price:
          type: integer
          example: 1200

security
メソッド定義部分に鍵マークが表示される

security:
  - api_key []
  - users_auth:
    - write:users
    - read:users

externalDocs

exeternalDocs:
  description: Find more info here
  url: https://example.com

tags:

tags:
  - name: users
    description: Access to users
  - name: products
    descrption: Access to Products

なるほど、実際に書いてみると全然違うな…

Swaggerの基本構造を学びたい

sample.yaml

openapi: 3.0.0
info:
  ...
servers:
  ...
paths:
  ...
components:
  ...
security:
  ...
tags:
  ...
exeternalDocs:
  ....

openapi: バージョンを記載(必須)
info: APIのメタデータ(必須) title, description, termsOfService, contact, license, version
servers: APIを提供するサーバを記述(配列で複数記述可能, 任意)
paths: APIで利用可能なエンドポイントやメソッドを記述(必須)
L put(tag, summary, description, operationId, requestBody(description, contents(application/json, xml, x-www-form-urlencoded), required), responses)
L post(tags, summary, description, operationId, requestBody(description, contents(application/json, xml, x-www-form-urlencoded), required)), response)
L get (tags, summary, description, operationId, requestBody(description, contents(application/json, xml, x-www-form-urlencoded), required)), response, security)
L get (tags, summary, description, operationId, parameters, response)
components: APIで使用するオブジェクトスキーマを記述(必須)
L schimas: type, properties(type(integer, string, array), format(int64, int32, date-time), example, required)
security: API全体を通して使用可能なセキュリティ仕様を記述する(OAuth)
tags: name, description, externalDocs, APIで使用されるタグのリスト。各種ツールによってパースされる際は、記述された順序で出力される。タグ名はユニークでなければならない。(任意)
externalDocs: 外部ドキュメントを記述する(API仕様書)

なるほど、swaggerの仕様を理解するだけで大分違うな…

OpenAPI, Swagger入門

OpenAPI: RESTful APIの仕様を記述するフォーマット
Swagger: OpenAPIを使用するツール

## Swagger Editor
$ git clone https://github.com/swagger-api/swagger-editor.git
$ cd swagger-editor
$ npm start

http://192.168.56.10:3001/

なんだこれは…

OpenAPIに慣れたい

swaggerのbasic structure
https://swagger.io/docs/specification/basic-structure/

$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar require zircote/swagger-php
$ php composer.phar exec openapi -h

openapiファイルの作成
$ vendor/bin/openapi -o ${出力先} –format ${出力フォーマット} ${スキャン対象ディレクトリ}
$ vendor/bin/openapi -o openapi.json –format json app/Http/Controller/Api

<?php

use OpenApi\Annotations as OA;

class OpenApi {}

class MyController {

	public funtion getResource(){
		
	}
}

https://zircote.github.io/swagger-php/guide/
The idea is to add swagger-php annotations or attributes next to the relevant PHP code in your application. These will contain the details about your API and swagger-php will convert those into machine-readable OpenAPI documentation.

require("vendor/autoload.php");

$openapi = \OpenApi\Generator::scan(["project"]);

header('Content-Type: application/x-yaml');
echo $openapi->toYaml();

annotation:あるデータに対して関連する情報(メタデータ)を注釈として付与すること

/**
 * @OA\Get(
 * tags={"Common"},
 * path="/api/user",
 * @OA\Response(
 *		response="200".
 *		description="success",
 *		@OA\JsonContent(ref="#/components/schemas/user_responder")
 * ),
 * @OA\Response(
 *		response="204",
 *		description="there is no authorized user",
 *		@OA\JsonContent(ref="#/components/schemas/204_no_content")
 *		)
 *	)
 */

schema:

/**
 * @OA\Schema(
 *	schema="user_responder",
 *	required={"id", "name", "email","created_at"},
 *	@OA\Property(
 *		property="id",
 *		type="integer",
 *		description="userId",
 *		example-"1"
 *	),
 *	@OA\Property(
 *		property="name",
 *		type="string",
 *		description="username",
 *		example="sample taro"
 *	),
 *
 *)
 */

annotationはパスとレスポンスで、schemaは入力値を定義しとるんかな。
どちっかというと、swaggerがよくわかってない。

openapi-generatorを利用

$ npm init
$ npm install –include=dev openapi-generator-cli
npm ERR! code E404
npm ERR! 404 Not Found – GET https://registry.npmjs.org/openapi-generator-cli – Not found
npm ERR! 404
npm ERR! 404 ‘openapi-generator-cli@*’ is not in this registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, http url, or git url.

npm ERR! A complete log of this run can be found in:
あれ? イマイチよくわからない

PostgreSQLでリレーション関係のあるテーブルを作りたい

create table person (
	id int,
	first_name varchar(50),
	last_name varchar(50),
	gender varchar(7),
	birth_day date
);

testdb=# \d person
Table “public.person”
Column | Type | Collation | Nullable | Default
————+———————–+———–+———-+———
id | integer | | |
first_name | character varying(50) | | |
last_name | character varying(50) | | |
gender | character varying(7) | | |
birth_day | date | | |

### テーブルに制約をつける

create table person (
	id BIGSERIAL not null primary key,
	first_name varchar(50) not null,
	last_name varchar(50) not null,
	gender varchar(7) not null,
	birth_day date not null,
	email varchar(150)
);

bigserial 整数を自動決定
primary key キーとして扱う
not null 空白を許可しない

### テーブルにデータを挿入

insert into person (
	first_name,
	last_name,
	gender,
	birth_day
) values ('Anne', 'Smith', 'Femail', DATE '1988-01-09');

insert into person (
	first_name,
	last_name,
	gender,
	birth_day,
	email
) values ('Jake', 'Jone', 'Male', DATE '1990-01-10', 'jake@gmail.com');

testdb=# select * from person;
id | first_name | last_name | gender | birth_day | email
—-+————+———–+——–+————+—————-
1 | Anne | Smith | Femail | 1988-01-09 |
2 | Jake | Jone | Male | 1990-01-10 | jake@gmail.com
(2 rows)

データの自動生成
https://mockaroo.com/

create table person (
	id BIGSERIAL not null primary key,
	first_name varchar(50) not null,
	last_name varchar(50) not null,
	gender varchar(7) not null,
	email varchar(150),
	date_of_birth date not null,
	country varchar(50) not null
);

$ \i /home/vagrant/dev/app/person.sql
$ select * from person;

create table person (
	id BIGSERIAL not null primary key,
	first_name varchar(50) not null,
	last_name varchar(50) not null,
	gender varchar(7) not null,
	email varchar(150),
	date_of_birth date not null,
	country varchar(50) not null,
	car_id BIGINT REFERENCES car (id),
	unique(car_id)
);
create table car (
	id BIGSERIAL not null primary key,
	make varchar(50) not null,
	model varchar(50) not null,
	price varchar(50) not null
);

BIGINT REFERENCESで関連づけるのか。なるほど、勉強になるね。

PHPの多重起動防止の書き方

実行時にロックファイルを作成して、実行が終わったら削除する

<?php

$lock_file = "./test.lock";

if (!file_exists($lock_file)){
	$fp = fopen($lock_file, "w+");

	for($i = 0; $i < 50; $i++){
		sleep(1);
	}

	fclose($fp);
	unlink($lock_file);
} else {
	echo "Already running!!";
}

ただし、実行中にエラーがあることがあるので、排他ロックをするという方法もある。

$file = fopen("test.lock", "w+");

if (flock($file, LOCK_EX + LOCK_NB)){
	
	for($i = 0; $i < 50; $i++){
		sleep(1);
	}

	flock($file, LOCK_UN);
} else {
	echo "Already running!!";
}

LOCK_EX: 排他的なロック。このフラグ単体だけの場合、他プロセスがアクセスした時に解除されるまでブロックするという挙動になる

PostgreSQLに画像を保存する

テーブルを作成
$ CREATE TABLE test(image bytea);

bytea型はバイナリデータを保存。1Gまで可能
https://www.postgresql.jp/document/9.6/html/datatype-binary.html

画像データの登録

$dsn = "pgsql:dbname=testdb host=localhost port=5432";
$user = "user1";
$password = "password";

try {
	$dbh = new PDO($dsn, $user, $password);
	print('connection success<br>');

	$stmt = $dbh->prepare("insert into test (image) values (:image)");

	$fp = fopen("images.jpeg", "rb");
	$stmt->bindParam(':image', $fp, PDO::PARAM_LOB);
	$stmt->execute();

} catch(PDOException $e){
	print("Error:".$e->getMessage());
	die();
}

画像の表示

$dsn = "pgsql:dbname=testdb host=localhost port=5432";
$user = "user1";
$password = "password";

try {
	$dbh = new PDO($dsn, $user, $password);

	$stmt = $dbh->prepare("select image from test");
	$stmt->execute();
	$stmt->bindColumn("image", $image, PDO::PARAM_LOB);
	$stmt->fetch();
	header("Content-Type: image/jpeg");
	fpassthru($image);

	unset($db);
} catch(PDOException $e){
	print("Error:".$e->getMessage());
	die();
}

なるほど、DBに画像保存も可能なのね。
データサイズが気になるが、軽量な画像であれば良さそう

PostgreSQLにPDOでphpから接続する

### 接続

$dsn = "pgsql:dbname=testdb host=localhost port=5432";
$user = "user1";
$password = "password";

try {
	$dbh = new PDO($dsn, $user, $password);
	print('接続に成功しました');
} catch(PDOException $e){
	print("Error:".$e->getMessage());
	die();
}

### sql実行

$dsn = "pgsql:dbname=testdb host=localhost port=5432";
$user = "user1";
$password = "password";

try {
	$dbh = new PDO($dsn, $user, $password);
	print('接続に成功しました<br>');

	$sql = 'select * from department';
	foreach($dbh->query($sql) as $row){
		print($row['department_code'].":");
		print($row['department_name'].",");

	}
} catch(PDOException $e){
	print("Error:".$e->getMessage());
	die();
}

$ php index.php
接続に成功しました
a:営業部,b:総務部,d:経理部,e:人事部,f:物流部,

PDOはmysqlと然程変わらないですな

PostgreSQLのVACUUMとは?

PostgreSQLは削除フラグがついて見えなくなっているだけのため、削除データを定期的にきれいにする必要があり、この処理をVACUUMという。

$ psql –version
psql (PostgreSQL) 14.2 (Ubuntu 14.2-1.pgdg20.04+1)
$ sudo -u postgres psql
psql (14.2 (Ubuntu 14.2-1.pgdg20.04+1))
Type “help” for help.

postgres=# \l
postgres=# \c testdb;
testdb=# \d department;
testdb=# select * from department;

testdb=# delete from department where department_code = ‘c’;
testdb=# vacuum verbose department;
INFO: vacuuming “public.department”
INFO: scanned index “pk_department” to remove 1 row versions
DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
INFO: table “department”: removed 1 dead item identifiers in 1 pages
DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
INFO: index “pk_department” now contains 5 row versions in 2 pages
DETAIL: 1 index row versions were removed.
0 index pages were newly deleted.
0 index pages are currently deleted, of which 0 are currently reusable.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO: table “department”: found 1 removable, 5 nonremovable row versions in 1 out of 1 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 747
Skipped 0 pages due to buffer pins, 0 frozen pages.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
VACUUM

vacuum ${table_name} でテーブルをvacuumできる。
なるほど。

autovacuumの設定はpostgres.confで設定されている。