概要
- AppSyncのデータソースにhttpエンドポイントが設定することで外部APIのレスポンス結果を利用することができるので、利用して見たのでメモ
前提
外部APIとして、OpenWeatherが提供する無料プランのAPIを利用する。APIの利用には Sing up してAPIキーを利用する必要があるので、発行しておく。
- OpenWather:https://openweathermap.org
利用するAPI
current weather data:https://openweathermap.org/current
リクエスト例
$ curl api.openweathermap.org/data/2.5/weather?q=Tokyo&appid={API key}
- レスポンス
- 以下のような形式でレスポンスが帰ってくるので、こちらをAppSyncを介して取得できるようにする
{
"coord": { "lon": 139.7531, "lat": 35.6854 },
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04d"
}
],
"base": "stations",
"main": {
"temp": 290.55,
"feels_like": 289.43,
"temp_min": 288.71,
"temp_max": 291.48,
"pressure": 1019,
"humidity": 55
},
"visibility": 10000,
"wind": { "speed": 1.03, "deg": 0 },
"clouds": { "all": 75 },
"dt": 1616214160,
"sys": {
"type": 1,
"id": 8077,
"country": "JP",
"sunrise": 1616186707,
"sunset": 1616230318
},
"timezone": 32400,
"id": 1861060,
"name": "Japan",
"cod": 200
}
AppSync APIの作成
- AWSコンソール上で、一から構築を選択し、APIの作成を行なってみた
スキーマ定義の作成
- openweather APIのレスポンスを、そのままGraphqlの型として作成した。作成し終わったらスキーマ定義を保存する
type Clouds {
all: String
}
type Coord {
lon: String
lat: String
}
type CurrentWeather {
coord: Coord
weather: [Weather]
base: String
main: Main
visibility: String
wind: Wind
clouds: Clouds
dt: String
sys: Sys
timezone: String
id: String
name: String
cod: String
}
type Main {
temp: String
feels_like: String
temp_min: String
temp_max: String
pressure: String
humidity: String
}
## クエリの実行
type Query {
currentWeather(q: String, appid: String): CurrentWeather
}
type Sys {
type: String
id: String
countory: String
sunrise: String
sunset: String
}
type Weather {
id: String
main: String
description: String
icon: String
}
type Wind {
speed: String
deg: String
}
# ルートスキーマ
schema {
query: Query
}
データソースの作成
以下のようにデータソースを作成する
- データソース名:openweathermap_api
- データソースのタイプ:HTTPエンドポイント
- エンドポイント:https://api.openweathermap.org
リゾルバーの設定
- 作成したスキーマ定義のQuery「currentWeather」のリゾルバー設定を行う。データソースは先ほど作成した、「openweathermap_api」を利用する
リクエストマッピングテンプレート
- resourcePathをapiのパス(/data/2.5/weather)に変更する。他はデフォルトで問題なし
{
"version": "2018-05-29",
"method": "GET",
"resourcePath": "/data/2.5/weather",
"params":{
"query":$util.toJson($ctx.args)
}
}
レスポンスマッピングテンプレート
- デフォルトのままで問題なし
## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
$util.error($ctx.error.message, $ctx.error.type)
#end
## If the response is not 200 then return an error. Else return the body **
#if($ctx.result.statusCode == 200)
$ctx.result.body
#else
$utils.appendError($ctx.result.body, "$ctx.result.statusCode")
#end
クエリを投げてみる
- 上記でAPIのレスポンス取得のための設定ができたので、AWSコンソール上からクエリを投げてみる。レスポンスに必要なパラメータのみ指定することが可能
query MyQuery {
currentWeather(appid: "{APIキー}", q: "Tokyo") {
weather {
description
}
name
main {
feels_like
humidity
pressure
temp
temp_max
temp_min
}
}
}
- レスポンス
- 指定した形式でレスポンス情報の取得ができた
{
"data": {
"currentWeather": {
"weather": [
{
"description": "broken clouds"
}
],
"name": "Tokyo",
"main": {
"feels_like": "288.95",
"humidity": "63",
"pressure": "1018",
"temp": "290.61",
"temp_max": "291.15",
"temp_min": "289.82"
}
}
}
}
クエリの追加
- クエリを新たに追加し、一つのデータソースで複数リゾルバーで利用することで、異なるURLへのリクエストが可能なので設定して試してみる
追加するAPI
$ curl http://api.openweathermap.org/geo/1.0/direct?q=Tokyo&appid={APIキー}
- レスポンス
[
{
"name": "Tokyo Prefecture",
"local_names": {
"ascii": "Tokyo Prefecture",
"en": "Tokyo",
"feature_name": "Tokyo Prefecture",
"fr": "Préfecture de Tokyo",
"ja": "東京都"
},
"lat": 35.6895,
"lon": 139.6917,
"country": "JP"
}
]
スキーマ定義
- 新たに下記のスキーマ定義を追加する
type Query {
currentWeather(q: String, appid: String): CurrentWeather
geoCoding(q: String, appid: String): [GeoCoding] # こちらを追加
}
# 追加
type GeoCoding {
name: String
local_names: localNames
lat: String
lon: String
country: String
}
# 追加
type localNames {
ascii: String
en: String
feature_name: String
fr: String
ja: String
}
リゾルバーの設定
- 追加したスキーマ定義のQuery「geoCoding」のリゾルバー設定を行う。データソースは最初に作成したものと同じ、「openweathermap_api」を利用する
リクエストマッピングテンプレート
- resourcePathをapiのパス(/geo/1.0/direct)に変更する。他はデフォルトで問題なし
{
"version": "2018-05-29",
"method": "GET",
"resourcePath": "/geo/1.0/direct",
"params":{
"query":$util.toJson($ctx.args),
}
}
レスポンスマッピングレンプレート
- デフォルトで問題なし
## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
$util.error($ctx.error.message, $ctx.error.type)
#end
## If the response is not 200 then return an error. Else return the body **
#if($ctx.result.statusCode == 200)
$ctx.result.body
#else
$utils.appendError($ctx.result.body, "$ctx.result.statusCode")
#end
再度クエリを投げてみる
- クエリにgeoCodingが追加されるので、パラメータを設定してクエリを投げてみる
query MyQuery {
currentWeather(appid: "{APIキー}", q: "Tokyo") {
weather {
description
icon
id
main
}
name
main {
feels_like
humidity
pressure
temp
temp_max
temp_min
}
}
geoCoding(appid: "{APIキー}", q: "Tokyo") {
country
lat
local_names {
ascii
en
feature_name
fr
ja
}
lon
name
}
}
- レスポンス
- geoCodingのAPIレスポンスについても取得ができた。Graphqlへの一回リクエストで複数APIのレスポンス情報が取得できた
{
"data": {
"currentWeather": {
"weather": [
{
"description": "light rain",
"icon": "10n",
"id": "500",
"main": "Rain"
}
],
"name": "Tokyo",
"main": {
"feels_like": "287.63",
"humidity": "88",
"pressure": "1017",
"temp": "288.95",
"temp_max": "289.82",
"temp_min": "288.15"
}
},
"geoCoding": [
{
"country": "JP",
"lat": "35.6895",
"local_names": {
"ascii": "Tokyo Prefecture",
"en": "Tokyo",
"feature_name": "Tokyo Prefecture",
"fr": "Préfecture de Tokyo",
"ja": "東京都"
},
"lon": "139.6917",
"name": "Tokyo Prefecture"
}
]
}
}