openapi-generatorを使いたい2

openapi.yaml

openapi: 3.0.3
info:
  description: "GET/POST IPv4 Address"
  version: "1.0.0"
  title: "openapi-rust"
tags:
  - name: "IP"
paths:
  /ip:
    get:
      responses:
        "200":
          description: "Get Global IPv4 address of the system"
          content:
            application/json:
              schema:
                type: object
                properties:
                  IPv4_address:
                    type: string
                    format: ipv4
                  checked_at:
                    type: string
                    format: date-time
        "500":
          description: "Internal Server Error"
    post:
      requestBody:
        description: "IPv4 address to register"
        content:
          application/json:
            schema:
              properties:
                IPv4_address:
                  type: string
                  format: ipv4
      responses:
        "200":
          description: "The new IPv4 address has been registered"
        "500":
          description: "Internal Server Error"

$ sudo npm install @openapitools/openapi-generator-cli -g

Makefile

generate:
  openapi-generator-cli generate \
    -i ./openapi.yaml \
    -g rust-server \
    -o .

なんか上手くいかないです

openapi-generatorを使いたい

openapi.yaml

openapi: 3.0.2
info:
  version: 0.1.0
  title: example
servers:
  - url: 'http://192.168.56.10:8080/example'
paths:
  /hello:
    get:
      description: Hello World
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Hello'
      tags:
        - example
components:
  schemas:
    Hello:
      type: object
      properties:
        message:
          type: string
          example: 'Hello World'
      x-tags:
        - example

application.yaml

inputSpec: 'openapi.yaml'
generatorName: spring
outputDir: modules/application
additionalProperties:
  configPackage: 'com.mamezou_tech.example.controller.configuration'
  modelPackage: 'com.mamezou_tech.example.controller.model'
  apiPackage: 'com.mamezou_tech.example.controller.api'
  invokerPackage: 'com.mamezou_tech.example.controller.api'
  groupId: 'com.mamezou_tech.example-service'
  dateLibrary: java8
  java8: true
  library: spring-boot
  artifactId: 'example-application'
  artifactVersion: '0.1.0'
  snapshotVersion: 'true'
  useTags: true

$ sudo docker run -it –rm -v `pwd`:/build -v example:/root/.m2 maven:3.8-eclipse-temurin-17-focal bash
$ curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/6.0.0/openapi-generator-cli-6.0.0.jar -o /tmp/openapi-generator-cli.jar
$ cd /build
$ java -DsupportingFiles -jar /tmp/openapi-generator-cli.jar batch application.yaml
[main] INFO o.o.codegen.cmd.GenerateBatch – Batch generation using up to 4 threads.
Includes: /build
Root: /build
[pool-1-thread-1] Generating spring (outputs to /build/modules/application)…
################################################################################
# Thanks for using OpenAPI Generator. #
# Please consider donation to help us maintain this project 🙏 #
# https://opencollective.com/openapi_generator/donate #
################################################################################
[pool-1-thread-1] Finished generating spring…
[SUCCESS] Batch generation finished 1 generators successfully.
$ cd modules/application
$ mvn install

なんだろう、spring bootが多いな

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がよくわかってない。

Swagger Codegenとドライバ・スタブコード

Swagger Codegenを使用するとAPIコンシューマのドライバコードやAPIプロバイダのスタブコードを自動生成できる。
Swagger UIでインターフェース仕様書を作成し、APIコンシュマー、プロバイダを自動生成する

スタブコードとは?
– テスト実行時に呼び出し先が未完成の時に代替えとして使用する
– 値を返すダミー(本物に似ているが中身はない)
– スタブとは切り株という意味
– 呼び出し元コードから見て下位

ドライバ(代替)とは
– テスト実行時に、呼び出し元が未完成等の時に代替えとして使用
– ダミー(本物に似ているが中身はない)
– 対象コードから見てドライバは上位に当たる

呼び出す側がドライバで呼び出される側がスタブって意味か

OpenAPI generatorとは?

OpenAPIはREST APIの定義を記述する規格
APIサーバがどのような挙動をするかを記した設計書
従来はSwagger Specificationと呼ばれた

### メリット
・決まったフォーマットで規定できる
・そのままAPIドキュメントになる
・API定義からサーバ・クライアントのコード生成ができる

サンプル
https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore.yaml

### OpenAPI Generator
何らかの構造を定義して、定められた形式で定義
どのエンドポイントがどんなリクエストを受け付けてどんなレスポンスを返すのか

### OpenAPI
info, servers, paths, tags/externalDocs, components

Swagger Toolなどで生成する

### OpenAPI Generatorのはじめ方
openapi-generator generate -i ./openapi.yml -g php -o./php-api-client

### OpenAPIを使ってみる
openapi.yaml

openapi: "3.0.3"

info:
  title: "Sample API"
  version: "1.0.0"

paths:
  "/message":
    get:
      summary: "Sample API get operation"
      descrption: "Sample API get operation"
      responses:
        "200":
          description: "Success operation"
          content:
            application/json:
              schema:
                type: string
                example: "Hello World !"

$ sudo docker run –rm -v “${PWD}:/home/vagrant/dev/test” openapitools/openapi-generator-cli generate \
-i /home/vagrant/dev/test/openapi.yaml \
-g php-laravel \
-o /home/vagrant/dev/test/php-laravel

-attribute paths.’/message'(get).descrption is unexpected

ん? どういうことだ?
yamlファイルを作成してから、openapiでコードを生成する?
いまいち流れがわからん?

OpenAPI Generator から コードを作成することができるのね。

[Go] BitflyerのAPIを取得したい

### Bitflyerからの取得

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	uri := "https://api.bitflyer.com/v1/gethealth"
	req, _ := http.NewRequest("GET", uri, nil)

	client := new(http.Client)
	resp, _ := client.Do(req)
	defer resp.Body.Close()

	byteArray, _ := ioutil.ReadAll(resp.Body)
	fmt.Println(string(byteArray))
}

$ go run gethealth.go
{“status”:”NORMAL”}

### Jsonの扱い
GoでJsonの受け取り方
1. 構造体を定義

type User struct {
	Name string `json:"name"`
	Age int `json:"age"`
	Job string `json:"job"`
}
func main() {
	userStr :=
	 `{
	    "name": "tokumaru",
	    "age": 20,
	    "job": "student"
	  }`

	var user User
	json.Unmarshal([]byte(userStr),&user)

	fmt.Println(user.Name)
}

// 構造体を定義
type User struct {
	Name string `json:"name"`
	Age int `json:"age"`
	Job string `json:"job"`
}

$ go run test.go
tokumaru

↓上記をつなげる
### Bitcoinの価格を取得
bitcoinは小数点なので、float64で定義する。
表示する際は、fmt.Printf(“%.0f\n”,ticker.Ltp)として、小数点以下を切り捨てる

package main

import (
	"fmt"
	"encoding/json"
	"io/ioutil"
	"net/http"
)

func main() {
	uri := "https://api.bitflyer.com/v1/getticker"
	req, _ := http.NewRequest("GET", uri, nil)

	client := new(http.Client)
	resp, _ := client.Do(req)
	defer resp.Body.Close()

	byteArray, _ := ioutil.ReadAll(resp.Body)

	var ticker Ticker
	json.Unmarshal([]byte(byteArray),&ticker)

	fmt.Printf("%.0f\n",ticker.Ltp)
}

// 構造体を定義
type Ticker struct {
	Code string `json:"product_code"`
	Ltp float64 `json:"ltp"`
}

$ go run test.go
5014562

これをHTMLで表示させたい