7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Phoenixお気軽API開発③:軽量APIにて実装した一覧REST APIにDBを接続する

Last updated at Posted at 2020-03-31

fukuoka.ex/kokura.exのpiacereです
ご覧いただいて、ありがとうございます :bow:

前作の軽量APIでの参照REST API実装を元に、DB接続を実装してみます

DBは、ローカルPostgreSQLやCloud SQLとかでは無く、Elixir標準のインメモリ&ローカルファイルDB「Mnesia」でサクっと済ませます(これ以降のどこかで、外部APIやGraphQLでサクっとやってもいいかも知れない)

本コラムの検証環境

本コラムは、以下環境で検証しています(Windowsで実施していますが、Linuxやmacでも動作する想定です)

あと下記コラムシリーズの続きとして実施するので、未実施であれば、事前に実施しておいてください(近々、ボイラープレート生成のmixコマンドとしてOSS化は考えています)

PHP的ハックを応用してNode.js Express/Go的な軽量APIをPhoenixで実現してみた
|> Express/Go的なPhoenix軽量APIの上に参照系REST APIを実装する

手順①:Mnediaテーブル作成、データ投入

まず、Mnesiaを起動し、テーブル作成します

このテーブルは、ファイル化して永続化してあるので、インメモリ時のような、Phoenixを落とすとDBが消えてしまうといったことがありません

iex> :mnesia.create_schema( [ node() ] )
:ok
iex> :mnesia.start
:ok
iex> :mnesia.create_table( :members, [ attributes: [ :id, :name, :age, :team, :position ], disc_copies: [ node() ] ] )
{:atomic, :ok}

次に、データ投入用コードを用意します

lib/basic.ex
defmodule Basic do
  def inserts() do
    :mnesia.transaction( fn -> :mnesia.write( { :members, 1, "enぺだーし", 49, "有限会社デライトシステムズ", "代表取締役、性能探求者" } ) end )
    :mnesia.transaction( fn -> :mnesia.write( { :members, 2, "ざっきー", 45, "公立大学法人 北九州市立大学", "准教授、カーネルハッカー" } ) end )
    :mnesia.transaction( fn -> :mnesia.write( { :members, 3, "つちろー", 34, "カラビナテクノロジー株式会社", "リードエンジニア、アプリマイスター" } ) end )
    :mnesia.transaction( fn -> :mnesia.write( { :members, 4, "piacere", 43, "カラビナテクノロジー株式会社", "CTO、福岡Elixirプログラマ、重力プログラマ、技術顧問" } ) end )
  end
end

データ投入します

iex> recompile
Compiling 1 file (.ex)
:ok
iex> Basic.inserts
{:atomic, :ok}

手順②:DBアクセッサモジュールを作り、select処理を追加

PJフォルダ内のlibフォルダ配下にutilフォルダを掘り、下記コラムと同一のDBアクセスモジュールを作ります

Excelから関数型言語マスター3回目:WebにDBデータ表示【Mnesia編】
https://qiita.com/piacerex/items/a7558adc6856e3577dc6

lib/util/db_mnesia.ex
defmodule DbMnesia do
	def select( table_name ) do
		:mnesia.start
		table_atom = table_name |> String.to_atom
		:mnesia.wait_for_tables( [ table_atom ], 1000 )
		columns = :mnesia.table_info( table_atom, :attributes ) 
			|> Enum.reduce( [], fn( item, acc ) -> acc ++ [ Atom.to_string( item ) ] end )
		columns_spec = 1..Enum.count( columns ) 
			|> Enum.reduce( { table_atom }, fn( x, acc ) -> Tuple.append( acc, :"$#{ x }" )  end )
		rows = :mnesia.transaction( fn -> 
			:mnesia.select( table_atom, [ { columns_spec, [], [ :"$$" ] } ] ) end ) |> elem( 1 )
		%{
			columns: columns, 
			command: :select, 
			connection_id: 0, 
  			num_rows: Enum.count( rows ), 
			rows: rows
		}
	end
end
lib/util/db.ex
defmodule Db do
	def query( sql ) when sql != "" do
		Regex.named_captures( ~r/select( *)(?<columns>.*)( *)from( *)(?<tables>.*)/, sql )[ "tables" ]
		|> DbMnesia.select
	end
	def columns_rows( result ) do
		result
		|> rows
		|> Enum.map( fn row -> Enum.into( List.zip( [ columns( result ), row ] ), %{} ) end )
	end
	def rows( %{ rows: rows } = _result ), do: rows
	def columns( %{ columns: columns } = _result ), do: columns
end

手順③:index.json.eex内でDBデータ取得

上記で投入したDBデータを取得し、JSON化していきます

まず、1件JSON返却を、DBデータ列から作るようにします

lib/basic_web/templates/api/v1/users/data.json.eex
%{
  name:     data[ "name" ], 
  age:      data[ "age" ], 
  team:     data[ "team" ], 
  position: data[ "position" ]
}

次に、DBデータ取得し、for式の中で、データ1件ずつをdata指定してテンプレート展開を繰り返します

lib/basic_web/templates/api/v1/users/index.json.eex
json = File.read!( "lib/basic_web/templates/api/v1/users/data.json.eex" ) 
datas = Db.query( "select * from members" ) |> Db.columns_rows

for data <- datas do
  json |> Code.eval_string( [ params: params, data: data ] ) |> elem( 0 )
end

手順④:動作確認

これで準備完了です

RESTクライアントで「GET http://localhost:4000/api/v1/users」のアクセスを行うと、以下のように、DBからデータ取得した行が、一覧としてJSON返却されます
image.png

終わり

JSONテンプレートでDBデータ取得を行い、一覧REST APIにてJSON返却できるようにしました

次回は、DBモジュールをwhere対応しつつ、1件ずつのDB値取得に対応します

p.s.このコラムが、面白かったり、役に立ったら…

image.pngimage.png にて、どうぞ応援よろしくお願いします:bow:

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?