#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 -
仕様を確認します。
-
リクエストパラメータ
| パラメータ名 | 項目名 | 必須 | 備考 |
| ---- | ---- | ---- | ---- |
| zipcode | 郵便番号 | ○ | 7桁の数字。ハイフン付きでも可。完全一致検索。 |
| callback | コールバック関数名 | - | JSONPとして出力する際のコールバック関数名。UTF-8でURLエンコードした文字列。 |
| limit | 最大件数 | - | 同一の郵便番号で複数件のデータが存在する場合に返される件数の上限値(数字) ※デフォルト:20 |
- レスポンスパラメータ
| フィールド名 | 項目名 | 備考 |
| ---- | ---- | ---- |
| status | ステータス | 正常時は 200、エラー発生時にはエラーコードが返される |
| message | メッセージ | エラー発生時に、エラーの内容が返される。 |
| results | zipcode(郵便番号) <br> prefcode(都道府県コード)<br> address1(都道府県名) <br> address2(市区町村名)<br>address3(町域名) <br>kana1(都道府県名カナ)<br>kana2 (市区町村名カナ) <br>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
}
- リクエストURL
#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を組み合わせて新しいサービスを作れそう。