Age++

38歳になった。もう、完全にアラフォー。まごうことなきアラフォー。38歳ともなれば、精神的にだいぶ大人になっているもんだと思っていたけど、特に変わった気はしない。こんなもんか。

今年は本業が忙し過ぎて、個人開発がまったくやれていない。むしろ、ストレス解消のために、空いた時間はゲームをやっている。ゲームで遊んでいる最中は、頭を空っぽにできて良い感じ。日中は本業、夜は個人開発という生活だと、脳を休める時間がないので、こういった時間は重要だ。

その個人開発では Flutter が凄く気になっていたけど、触ってみたらイマイチ Dart が好きになれず。でも独自描画なので、Xamarin.Forms や ReactNative よりも、iOSAndroid で同じ UI が実現しやすいのは魅力的。でも Dart が…。という感じでブレブレ。

独自描画といえば、Switch で遊んでいる影響もあり、Unity もかなり気になっている。Unity なら C# だし。個人開発では、まったく新しい技術に挑戦するよりは、今までのスキルを生かせる技術を選ぶほうが、エタりにくいと思う。ゲームクリエイターは幼少期の夢でもあったので、Unity アリだな。ただ、カジュアルゲームレッドオーシャンか。むしろ血の海だ。幼少期の憧れ JRPG は個人でやるには規模が大きすぎるな。という感じで、こちらでもブレブレだ。

個人開発以外だと、コロナのせいで旅行も外食も行けなくなって、楽しみがマンガとゲームくらいしかない。店で食べるのが一番旨いだろう、というこだわりがあるので、テイクアウトは性に合わない。外出はちょっとしたレジャー兼ねていたからなぁ。ワクチン接種し終わるまでは行きづらい。

2021 年後半も進捗ダメかもな。

OpenAPI Specification の JSON から PDF を生成する

はじめに

OpenAPI Specification の JSON から、API の PDF ドキュメントを生成したい。

openapi-generator で直接 PDF を出力することはできないけど、AsciiDoc を挟むことで、最終的に PDF ドキュメントを生成できそうだったので試してみた。

OpenAPI Generator をインストール

Invoke-WebRequest -OutFile openapi-generator-cli.jar https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/5.1.0/openapi-generator-cli-5.1.0.jar

OpenAPI Specification の JSON から AsciiDoc ファイルを生成

openapi-generator から直で AsciiDoc を出力できるようになっていた。

java -jar openapi-generator-cli.jar generate -i openapi.json -g asciidoc -o .\asciidoc

Ruby Installer で Ruby をインストール

AsciiDoc を PDF に変換するツール asciidoctor-pdf は Ruby 製なので、まずは Ruby をインストール必要がある。

rubyinstaller.org

asciidoctor-pdf をインストール

gem install asciidoctor-pdf

TTF ファイルを用意

デフォルトだと PDF の日本語が文字化けしたので、お好みの日本語フォントをダウンロードして使う。

jikasei.me

スタイルファイルを作成

asciidoctor-pdf が用意した日本語フォントを使えるようにするために、デフォルトのスタイルファイルを修正する。

github.com

font:
  catalog:
    GenShinGothic:
      normal: GenShinGothic-Light.ttf
      italic: GenShinGothic-Light.ttf
      bold: GenShinGothic-Medium.ttf
      bold_italic: GenShinGothic-Medium.ttf
base:
  font_family: GenShinGothic
literal:
  font_family: GenShinGothic

PDF 作成

日本語フォントが置かれたフォルダと、修正したスタイルファイルを指定して、asciidoctor-pdf を実行。

asciidoctor-pdf index.adoc -a pdf-style=my-theme.yml -a pdf-fontsdir=fonts -o index.pdf

おわりに

openapi-generatorr から直で PDF まで出せたら最高だけど、さすがにそれは望み薄か。CLI のツールで欲しい。

アルスラーン戦記(15)

アンドラゴラスが自力で帰還したので、パルス軍をアンドラゴラスが率いるのは予想通りだけど、アルスラーンが追い出されるのは予想外だった。

ダリューンナルサスアンドラゴラスから嫌われていたから、アルスラーンと一緒に追い出されると思いきや、まさかアルスラーンと引き離されそうになるとはね。パルス王家ではなくアルスラーンに仕えてる面々なので、半ば無理矢理アルスラーンを追っていってひと安心。

王の命令に背く形になってしまったので、圧倒的な功績を上げないとエクバターナの地を踏めない状況になったが、さてここからどうやって5万以上の兵を集めるんだろうか。ほとんどの兵は既にアンドラゴラスの指揮下だし。

アオアシ(24)

北野蓮がアシトの上位互換な部分を、まざまざと見せつけられた前半戦が終了。北野蓮はボランチなのに対し、アシトは左サイドバックなので、福田監督がアシトに期待する役割は北野蓮とは違うはず。アシトがラストピースだった理由がきっとある。やっぱアラバロールかなぁ。

まぁ、アシトはディフェンダーなので、攻撃よりもまず守備。阿久津がアシトに何を仕込んだのかが、後半戦で見られると思うと楽しみだ。

ASP.NET Core で gRPC と MVC の両方に対応できるか試した

はじめに

ASP.NET Core で gRPC と gRPC-Web を 1 つのアプリでホストできることは確認した。

tnakamura.hatenablog.com

gRPC と MVC はどうだろうか?試してみた。

gRPC サーバーに Web API を追加

GreeterController

using Microsoft.AspNetCore.Mvc;

namespace HelloGrpcWeb.Controllers
{
    [ApiController]
    [Route("api/greeter")]
    public class GreeterController : ControllerBase
    {
        [HttpGet("hello/{name}")]
        public IActionResult Hello(string name)
        {
            return Ok(new
            {
                Message = $"Hello {name}",
            });
        }
    }
}

Startup

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace HelloGrpcWeb
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddGrpc();

            // コントローラーを登録
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseGrpcWeb();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGrpcService<GreeterService>()
                    .EnableGrpcWeb();

                // コントローラーのルーティングを登録
                endpoints.MapControllers();

                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
                });
            });
        }
    }
}

クライアントに Web API を呼び出すサンプルを追加

gRPC と同じアドレスで Web API もホストする場合、HTTP/2 を使う必要がある。でないと、サーバー側で「HTTP/2 over TLS was not negotiated on an HTTP/2-only endpoint.」っていうエラーになり、リクエスト送信に失敗する。

using System;
using System.Net.Http;
using System.Threading.Tasks;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;

namespace HelloGrpcWeb.Client
{
    class Program
    {
        const string Address = "https://localhost:5001";

        static async Task Main(string[] args)
        {
            await Grpc();
            await GrpcWeb();
            await Mvc();

            Console.ReadLine();
        }

        static async Task Grpc()
        {
            var channel = GrpcChannel.ForAddress(Address);

            var client = new Greeter.GreeterClient(channel);

            var reply = await client.SayHelloAsync(new HelloRequest
            {
                FirstName = "Takefusa",
                LastName = "Kubo",
            });

            Console.WriteLine($"gRPC:{reply.Message}");
        }

        static async Task GrpcWeb()
        {
            var channel = GrpcChannel.ForAddress(Address, new GrpcChannelOptions
            {
                HttpHandler = new GrpcWebHandler(
                    new HttpClientHandler()),
            });

            var client = new Greeter.GreeterClient(channel);

            var reply = await client.SayHelloAsync(new HelloRequest
            {
                FirstName = "Takehiro",
                LastName = "Tomiyasu",
            });

            Console.WriteLine($"gRPC Web:{reply.Message}");
        }

        static async Task Mvc()
        {
            var client = new HttpClient
            {
                BaseAddress = new Uri(Address),
                // gRPC と同じアドレスを使う場合は
                // HTTP/2 を使う必要がある
                DefaultRequestVersion = new Version(2, 0),
            };

            var response = await client.GetAsync(
                "/api/greeter/hello/Douan");

            var body = await response.Content.ReadAsStringAsync();

            Console.WriteLine($"MVC:{body}");
        }
    }
}

実行結果

HTTP/2 ではあるが、Web API も呼び出せた。

f:id:griefworker:20210607114736p:plain

おわりに

gRPC と gRPC-Web、それに MVC を 1 つのアプリケーションでホストすることはできた。ただ、詰め込んだのはいいものの、MVC で実装した Web API を呼び出すには HTTP/2 が必要、というのが問題になるかもしれないな。

openapi-generator-cli でカスタムテンプレートを使う

openapi-generator-cli は jar ファイルをダウンロード。

Invoke-WebRequest -OutFile openapi-generator-cli.jar https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/5.1.0/openapi-generator-cli-5.1.0.jar

html2 ジェネレーターのテンプレート htmlDocs2 をダウンロードし、日本語化する。

github.com

-t でカスタムテンプレートのディレクトリを指定すれば、カスタムテンプレートを使って生成できる。

java -jar openapi-generator-cli.jar generate -i .\swagger.json -g html2 -t .\htmlDocs2 -o .\custom-html2

なないろ

バンプの新曲「なないろ」が iTunes Store で配信されていたので購入。今回はNHK連続テレビ小説「おかえりモネ」の主題歌らしい。軽やかなメロディで、朝から元気出そう。憂鬱な月曜日も、この曲を聴いてシャキッとできる気がする。心なしか、足どりも軽くなったような。

なないろ

なないろ