はじめに
http-client
はfortranでHTTPプロトコルを用いて情報を取得できるパッケージになります。
http-client
はfortran-curl
を利用しており、fortran-curl
はlibcurl
を利用しています。
環境構築
http-client
はfortran-curl
とlibcurl
を利用していることから、自力でコンパイルを行うのは面倒なので公式サイトで推奨しているfpm
を使ってコンパイルを行います。その前段階として環境構築を行います。
fpmのダウンロード
fpmはpythonで作成されているが、Linuxで一番簡単なのはバイナリデータをダウンロードして組み込むことです。MacOSの場合はHomebrew
、Windowsの場合はWinget
で行うとよい。Anaconda
もあり。pythonからpipでインストールしても可。(環境によってはパスを張る必要がある。)
gitやlibcurlやlibcurlのヘッダーをインストール
# Ubuntu 22.04
sudo apt install git libcurl4-openssl-dev
# CentOS Stream 9
dnf install git libcurl-devel
※Windowsの場合はlibcurlやlibcurlのヘッダーどうすれば適切に実行できるのか不明。おとなしくMSYS2やWSL2使ってください。
gitの設定
git config --global user.name "<user>"
git config --global user.email "<e-mail>"
git config --global http.proxy "<[protocol://][user[:password]@]proxyhost[:port]>" #必要なら
http-clientの使用方法
ここではこの中のジオイド高を求めるAPIを用いて、httpリクエストを行い、json形式の文字列を取得し、そこからジオイド高を取得することを行う。APIの詳細については上記のURLを参照してください。
fpmの設定
fpmの詳しい使い方については
こちらを見ていただくとして一連の構築手順を提示する。
プロジェクトの作成
fpm new geoid_api
を実行すると、カレントディレクトリにgeood_apiディレクトリが作成される。中身は以下の通り、
.
├── .git
├── app
│ └── main.f90
├── src
│ └── geoid_api.f90
├── test
│ └── check.f90
├── fpm.toml
└── README.md
appディレクトリにあるものはメインルーチンが入っているソースコードを入れる。
srcディレクトリにあるものはモジュール形式で格納されているものを入れる。
testディレクトリにあるものは、srcディレクトリのモジュールをテストするためのメインルーチンが入っているソースコードが入る。
fpm.toml
dependencies項に今回使用するパッケージ名を指定する。
httpリクエストをするパッケージ名はhttp
、jsonを扱うパッケージ名はjson-fortran
なのでそのように記入する。
名前の見つけ方については、それぞれのgithubのコードのfpm.toml
に名前が記載されているのでそれを見るか使い方を見る。
[dependencies]
http = { git = "https://github.com/fortran-lang/http-client" }
json-fortran = { git = "https://github.com/jacobwilliams/json-fortran" }
stdlib = "*"
ソースコード
以下の通り作成する。
program main
use, intrinsic :: iso_fortran_env, only: real64
use geoid_api, only: get_geoidHeight
implicit none
real(real64) :: lon, lat, geoidHeight
! 国土地理院の座標
lon = 140.084556_real64 ! f0.8
lat = 36.104611_real64 ! f0.8
geoidHeight = get_geoidHeight(lon, lat)
print *, lon, " ", lat, " ", geoidHeight
end program main
module geoid_api
use, intrinsic :: iso_fortran_env, only: real64
use http, only: response_type, request
use json_module, only: json_file
use stdlib_strings, only: to_string, strip
use stdlib_str2num, only: to_num
implicit none
private
public :: get_geoidHeight
contains
impure elemental function get_geoidHeight(lon, lat) result(geoidHeight)
real(real64), intent(in):: lon !! lon
real(real64), intent(in) :: lat !! lat
real(real64) :: geoidHeight !! ジオイド高[m]
type(json_file) :: json_f
type(response_type) :: response
character(:), allocatable :: lon_str, lat_str, geoidHeight_str
character(*), parameter :: outputType = 'json'
character(*), parameter :: baseurl = 'https://vldb.gsi.go.jp/sokuchi/surveycalc/geoid/calcgh/cgi/geoidcalc.pl'
character(:), allocatable :: url
! 文字列に変換
!allocate (character(len=12) :: lon_str) ! 140.08455600 f12.8型->12文字
!allocate (character(len=12) :: lat_str) ! 36.10461100 f12.8型->12文字
!write (lon_str, '(f0.8)') lon ! 左詰めにするためf0で設定
!write (lat_str, '(f0.8)') lat ! 左詰めにするためf0で設定
lon_str = strip(to_string(lon, '(f12.8)'))
lat_str = strip(to_string(lat, '(f12.8)'))
!url = baseurl//'?'//"outputType="//outputType//"&latitude="//trim(lat_str)//"&longitude="//trim(lon_str)
url = baseurl//'?'//"outputType="//outputType//"&latitude="//lat_str//"&longitude="//lon_str
response = request(url=url)
if (.not. response%ok) then
print *, 'Error message:', response%err_msg
stop
end if
print *, 'Response Code :', response%status_code
print *, 'Response Length :', response%content_length
print *, 'Response Method :', response%method
print *, 'Response Content :', response%content
!content ※lat,lon,geoidが文字列で格納されているので注意
!--------------
! { "OutputData":
! {
! "latitude": "36.10461100" ,
! "longitude": "140.08455600",
! "geoidHeight": "40.1986"
! }
! }
call json_f%initialize()
call json_f%deserialize(response%content)
call json_f%get(path='OutputData.geoidHeight', val=geoidHeight_str)
call json_f%destroy()
! 文字列からrealに
!read (geoidHeight_str, *) geoidHeight
geoidHeight = to_num(geoidHeight_str, geoidHeight)
end function get_geoidHeight
end module geoid_api
数値を文字列に、文字列を数値に変換する際面倒なことを行っているがstdlib
を利用することにした、注意すべき点は、response%content
はhttpリクエストで返却された本体部分になっており、改行を含めた文字列がそこに格納されている。call json_f%deserialize(response%content)
により、json文字列をjsonのポインタに変換し格納する。
ビルド
fpm build
buildディレクトリにgithubからダウンロードしたものやコンパイルしたものが一式格納されている。
インストール
fpm install --prefix .
binディレクトリにgeoid_apiプログラムが作成される。
実行
$ ./bin/geoid_api
Response Code : 200
Response Length : 94
Response Method :GET
Response Content :{"OutputData":{"latitude":"36.104611000","longitude":"140.084556000","geoidHeight":"40.1986"}}
140.08455599999999 36.104610999999998 40.198599999999999
詳しい使い方
このサイトのProcedures
とDerived Types
のうちglobalになっているものだけを見るとよい。
現時点で、globalで存在するものは以下の通り
Procedures
- append_pair: pair_type型に関係する
- get_pair_value: pair_type型に関係する
- pair_has_name: pair_type型に関係する
- request: response_type型を返す
Derived Types
- pair_type: headers等を格納する型
- request_type
- response_type
プロキシについて
直接プロキシを設定する項目は今のところないが、libcurl
を利用しているので環境変数で設定する。~/.curlrc
は読み込まないので注意
環境変数
- http_proxy=scheme://[user:passwd@]proxy.server:port
- HTTPS_PROXY
- https_proxy
- ALL_PROXY
- NO_PROXY
- no_proxy
- CURL_CA_BUNDLE: CA証明書のパス
※http_prxoyは小文字のみ、それ以外は両方OK。両方ある場合は小文字優先。
※proxyにBasic認証がある場合はuser:passwdを入れる。userやpasswdに記号(" # < > ` { } ? =など)が入っている場合はURLエンコードを忘れずに。