APIを使用したアプリを作ってみる
背景
- APIを使用したアプリケーションが増えてきている
- APIを使用する、作るエンジニアの仕事も増えている
- APIを扱う技術の需要が増えそう
目次
0.環境確認
- OS: Windows10 home
- IDE : Eclipse(Photon 4.8)
- ビルドツール : Gradle
- サーバーサイド言語 : Java(1.8)
- フレームワーク : SpringBoot(2.2.7)
- JavaScript ライブラリ : jQuery(3.3.1)
- テンプレートエンジン : thymeleaf
1.APIの確認
以下のサイトからAPIの使用を確認します。
https://zip-cloud.appspot.com/doc/api-
仕様を確認します。
- https://zip-cloud.appspot.com/api/search をベースにする
- リクエストパラメータ
パラメータ名 項目名 必須 備考 zipcode 郵便番号 ○ 7桁の数字。ハイフン付きでも可。完全一致検索。 callback コールバック関数名 - JSONPとして出力する際のコールバック関数名。UTF-8でURLエンコードした文字列。 limit 最大件数 - 同一の郵便番号で複数件のデータが存在する場合に返される件数の上限値(数字) ※デフォルト:20 - レスポンスパラメータ
フィールド名 項目名 備考 status ステータス 正常時は 200、エラー発生時にはエラーコードが返される message メッセージ エラー発生時に、エラーの内容が返される。 results zipcode(郵便番号)
prefcode(都道府県コード)
address1(都道府県名)
address2(市区町村名)
address3(町域名)
kana1(都道府県名カナ)
kana2 (市区町村名カナ)
kana3(町域名カナ)複数の場合、配列となる - (例)郵便番号「7830060」で検索する場合
- リクエストURL https://zip-cloud.appspot.com/api/search?zipcode=7830060
- レスポンス
{ "message": null, "results": [ { "address1": "北海道", "address2": "美唄市", "address3": "上美唄町協和", "kana1": "ホッカイドウ", "kana2": "ビバイシ", "kana3": "カミビバイチョウキョウワ", "prefcode": "1", "zipcode": "0790177" }, { "address1": "北海道", "address2": "美唄市", "address3": "上美唄町南", "kana1": "ホッカイドウ", "kana2": "ビバイシ", "kana3": "カミビバイチョウミナミ", "prefcode": "1", "zipcode": "0790177" } ], "status": 200 }
2.プロジェクトの作成
別の記事で詳細に紹介しているので、そちらを参照ください。
GradleのSpringBootプロジェクトを作成する
3.バックエンドの実装
- build.gradle
build.gradle
//中略
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
compile("com.fasterxml.jackson.core:jackson-databind")
}
- Controllerクラス
- パターン1:Json形式の文字列で受け取り
FrontController.java
@Controller
public class FrontController {
@Autowired
private FrontService frontService;
@RequestMapping({ "/", "/index" })
public String index() {
return "index";
}
@ResponseBody
@RequestMapping(value = "/getAddress" ,method = RequestMethod.POST, produces="application/json;charset=UTF-8")
public String getAddress(@RequestBody(required = false) AddressForm addressForm) {
return frontService.getAddress(addressForm.getZipcode());
}
}
- Serviceクラス
FrontService.java
public interface FrontService {
public String getAddress(String zipCode);
}
FrontServiceImpl.java
@Service
public class FrontServiceImpl implements FrontService {
/** 郵便番号検索API リクエストURL */
private static final String URL = "https://zip-cloud.appspot.com/api/search?zipcode={zipcode}";
@Override
public String getAddress(String zipCode) {
String zipCodeJson = restTemplate.getForObject(URL, String.class, zipCode);
return zipCodeJson;
}
}
- formクラス
AddressForm.java
@Data
public class AddressForm {
/** 郵便番号 */
String zipcode;
}
4.フロントエンドの実装
- html
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>address</title>
<script type="text/javascript" th:src="@{/jquery/jquery-3.3.1.js}"></script>
<script th:src="@{/js/index.js}"></script>
</head>
<body>
<form name="getAddress">
<input id="zipcode" type="text">
<button type="button" id="getAddressBtn">住所取得</button>
<div id="dispAddress"></div>
</form>
</body>
</html>
- JavaScript
index.js
$(function() {
$('#getAddressBtn').on('click', function() {
var params = {
"zipcode" : $('#zipcode').val()
};
$.ajax({
url : 'getAddress',
type: 'POST',
contentType: "application/json",
data: JSON.stringify(params),
dataType : 'json',
async: false,
success: function (data) {
$("#dispAddress").empty();
var dispAddress = document.getElementById("dispAddress");
var table = document.createElement("table");
table.setAttribute("border","2");
table.setAttribute("cellpadding","15");
table.setAttribute("style","margin :15px");
$(data.results).each(function(index, result){
table.appendChild(createRow("郵便番号",result.zipcode));
table.appendChild(createRow("都道府県コード",result.prefcode));
table.appendChild(createRow("都道府県名",result.address1));
table.appendChild(createRow("市区町村名",result.address2));
table.appendChild(createRow("町域名",result.address3));
table.appendChild(createRow("都道府県名カナ",result.kana1));
table.appendChild(createRow("市区町村名カナ",result.kana2));
table.appendChild(createRow("町域名カナ",result.kana3));
});
dispAddress.appendChild(table);
}
});
});
});
function createRow(header , value){
var tr = document.createElement("tr");
var th = document.createElement("th");
th.append(header);
var td = document.createElement("td");
td.append(value);
tr.appendChild(th);
tr.appendChild(td);
return tr;
}
5.動作確認
6.おまけ
Json形式をDTOクラスに変換して受け取る方法
- Controllerクラス
FrontController.java
@Controller
public class FrontController {
@Autowired
private FrontService frontService;
@RequestMapping({ "/", "/index" })
public String index() {
return "index";
}
@ResponseBody
@RequestMapping(value = "/getAddress" ,method = RequestMethod.POST, produces="application/json;charset=UTF-8")
// 戻り値をString → ZipcodeDto に変更
public ZipcodeDto getAddress(@RequestBody(required = false) AddressForm addressForm) {
return frontService.getAddress(addressForm.getZipcode());
}
}
- Serviceクラス(修正)
FrontService.java
public interface FrontService {
// 戻り値をString → ZipcodeDto に変更
public ZipcodeDto getAddress(String zipCode);
}
- DTOクラス(追加)
ZipcodeDto.java
@Data
public class ZipcodeDto {
/** ステータス */
int status;
/** メッセージ */
String message;
/** 郵便番号情報リスト */
List<ZipcodeResultDto> results = new ArrayList<>();
}
- DTOクラス(追加)
ZipcodeResultDto.java
@Data
public class ZipcodeResultDto {
/** 郵便番号 */
String zipcode;
/** 都道府県コード */
String prefcode;
/** 都道府県名 */
String address1;
/** 市区町村名 */
String address2;
/** 町域名 */
String address3;
/** 都道府県名カナ */
String kana1;
/** 市区町村名カナ */
String kana2;
/** 町域名カナ */
String kana3;
}
- Service実装クラス
- ObjectMapperにURLを渡してDTOクラスに変換するパターン
FrontServiceImpl.java
@Service
public class FrontServiceImpl implements FrontService {
// ObjectMapperを追加
@Autowired
ObjectMapper objectMapper;
// URLのパラメータを正規表現に変更
private static final String URL = "https://zip-cloud.appspot.com/api/search?zipcode=%s";
@Override
public ZipcodeDto getAddress(String zipCode) {
ZipcodeDto zipcodeDto = null;;
try {
// ObjectMapperでURLと受け取りクラスを指定
java.net.URL url = new java.net.URL(String.format(URL,zipCode));
zipcodeDto = objectMapper.readValue(url, ZipcodeDto.class);
} catch (Exception e) {
e.getStackTrace();
}
return zipcodeDto;
}
}
- Service実装クラス
- restTemplateにMappingJackson2HttpMessageConverterを設定して変換するパターン
FrontServiceImpl.java
@Service
public class FrontServiceImpl implements FrontService {
// restTemplateを追加
RestTemplate restTemplate = new RestTemplate();
private static final String URL = "https://zip-cloud.appspot.com/api/search?zipcode={zipCode}";
@Override
public ZipcodeDto getAddress(String zipCode) {
ZipcodeDto zipcodeDto = null;;
try {
// reatTemplateのmessageConverterにMappingJackson2HttpMessageConverter を追加
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
List<MediaType> supportedMediaTypes = new ArrayList<>(messageConverter.getSupportedMediaTypes());
supportedMediaTypes.add(MediaType.TEXT_PLAIN);
messageConverter.setSupportedMediaTypes(supportedMediaTypes);
restTemplate.setMessageConverters(Collections.singletonList(messageConverter));
zipcodeDto = restTemplate.getForObject(URL, ZipcodeDto.class, zipCode);
} catch (Exception e) {
e.getStackTrace();
}
return zipcodeDto;
}
}
7.まとめ
- APIを使用するのは簡単(認証機能付きはもう少し難しい)
- 他APIからデータ活用できる
- いろんなAPIを組み合わせて新しいサービスを作れそう。