PHONE APPLI APIでユーザプロフィール情報をエクスポートしよう


PHONE APPLIのアドベントカレンダー 12月23日分です。
( 案の定間に合いませんでした。 )

**非エンジニア**の shirai　です。

今回は PHONE APPPLI PEOPLE ( 弊社のサービス )の情報をAPIを使ってエクスポートする方法を書いていこうと思います。

# すごく大事
**今回紹介する内容は、個人で発信するものであり弊社でサポートがされる訳ではありません。**

## はじめに

### PHONE APPLI PEOPLEとは
多くは語りません。。。
ぜひ、こちらから確認してみて下さい。
https://phoneappli.net/product/service/papeople/

### PHONE APPLI PEOPLEのAPI

こちらでリリースノート・仕様書が公開されています。
こちらも是非🥺
https://note.com/pa_api/n/n8e8f87914d07


## 今回すること

PHONE APPLI PEOPLEには、連絡先情報や個人のスキルや資格・略歴など様々な情報が格納されています。
今回は、APIを利用してエクスポートしたいと思います！

### 使用するAPI
- /v1/users( ユーザ一覧取得API )
- /v1/users/{userId}/profile( プロフィール取得API )

### 今回の実行フロー

ユーザ一覧取得API
↓
プロフィール取得API
↓
JSON から CSV へ変換
↓
ファイル保存

＊
プロフィール取得APIを実行にユーザ識別子( userId )が必要なため、
userIdをユーザ一覧取得APIで取得し、プロフィールAPIを実行します。

＊＊
今回は、簡易的な実装のため以下条件で実施しています。

(1) APIのレスポンスは、正常系をベースに実装
APIのレスポンスが正常系以外の場合、リトライ処理などを実施する場合もありますが今回は全てスキップしています。

(2) 実行ユーザ数は100ユーザ
より多くのユーザ情報のエクスポートも可能ですが、100ユーザのみを取得する実装としています。

(3) 資格やスキルのエクスポートフォーマット
一部出力項目が APIで取得したフォーマットのままとなっています。
可読性を考慮すると、カンマ区切り等に変えた方が良いですが、今回は省略しています。

(4) エラー処理は最低限に

### 実際のコード( Java )

<details><summary>サンプルコード</summary>

```java
/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package api_sample_code;
import java.io.IOException;
import java.io.File;
import org.apache.commons.io.FileUtils;
import org.json.*;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Call;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import okhttp3.Response;


public class App {
	String API_Key = "ご自身のAPI KEYを代わりに入れて下さい。";
	final String HOST_PATH = "https://api.phoneappli.net/v1";

    public String getUsers() {
		String request_url = HOST_PATH + "/users";
		String query = "?select=userType,userId,loginId,fullname&page=0&pageSize=100&orderBy=employeeNum&orderDirection=asc";
		//selectでユーザタイプ、ユーザID、ログインID、氏名のみ取得

		OkHttpClient client = new OkHttpClient();
		Request request = new Request.Builder().url( request_url + query ).addHeader( "X-Pa-Api-Key" , API_Key ).build(); 
		Call call = client.newCall( request );


		try{
			Response response = call.execute();
			ResponseBody body = response.body();
			if( response.code() == 200){ //HTTP Stausu Codeが200で、正常にAPI実行できたことを確認。
				RateLimitChecker( response );
				return body.string();
			}
			return null;
		}catch( IOException e ){
			e.printStackTrace();
		}
		
        return null;
    }

	public void json2csv(String data){
		JSONObject output;
		JSONArray export_data = new JSONArray();
		try{
			output = new JSONObject(data);
			JSONArray items = output.getJSONArray( "items" );
			for( int i = 0; i < items.length(); i++ ){ //ユーザ一覧で取得したレコード数分ループ処理を行う
				JSONObject item = items.getJSONObject( i ); //各レコードの情報を取得
				Integer user_id = item.getInt( "userId" ); //特定のuser_idを取得する
				String user_type = item.getString( "userType" ); //特定のuser_idのユーザタイプを取得する。
				if(!user_type.equals( "REGULAR_USER" )){ // ユーザタイプが REGULAR_USER以外はマイプロフィールを保有できないので処理をスキップする
					System.out.println( "SKIP NOT REGULAR_USER" );
					continue;
				}

				String profile = getProfiles( user_id.toString() ); //プロフィール情報を取得する
				if( profile == null ){ //プロフィール取得エラーした場合、処理をスキップする。
					continue;
				}
				JSONObject json_profile = new JSONObject( profile ); //プロフィール情報をJSONへ変換する
				json_profile.put( "user_id" , user_id.toString() ); //user_idをプロフィール情報のJSONへ追加する
				json_profile.put( "login_id" , item.getString( "loginId" ) );//login_idをプロフィール情報のJSONへ追加する
				export_data.put( json_profile );

			}
			
			File output_file = new File( "export_user.csv" );
			String csv = CDL.toString( export_data ); //
			FileUtils.writeStringToFile( output_file , csv , "shift-jis" ); //ファイル保存
			System.out.println( "Data has been Writteen" );
			

		}catch(Exception e){
			e.printStackTrace();
		}
	}

	public String getProfiles( String user_id ){
		String request_url = HOST_PATH + "/users/" + user_id + "/profile";
		OkHttpClient client = new OkHttpClient();
		Request request = new Request.Builder().url( request_url ).addHeader( "X-Pa-Api-Key" , API_Key ).build();
		Call call = client.newCall( request );

		try{
			
			Response response = call.execute();
			ResponseBody body = response.body();
			if( response.code() == 200 ){ //HTTP Stausu Codeが200で、正常にAPI実行できたことを確認。
				RateLimitChecker( response );
				return body.string();
			}
			return null;
		}catch( IOException e ){
			e.printStackTrace();
		}
		return null;

	}

	//レート制限の確認
	public void RateLimitChecker( Response response ){
		int x_ratelimit_remaining = Integer.parseInt( response.header( "x-ratelimit-remaining" ));
		//残実行可能数が0以下の場合、1秒間リクエスト実行を止める。
		if( x_ratelimit_remaining <= 0 ){
			try {
				System.out.println( "1 second Sleep" );
				Thread.sleep( 1000 );  //1秒sleep
			} catch( InterruptedException e ){
				e.printStackTrace();
			}   
		}
		System.out.println( "Remaining Token " + x_ratelimit_remaining );
	}
    public static void main(String[] args) {
		//ユーザ情報を取得する。
		String user_json_data = new App().getUsers();
		if( user_json_data == null ){
			System.out.println( "Runtime Error" );
			System.exit( 0 );
		}
		//ユーザデータを JSON -> CSVへ変換しファイル保存を実行する。
		new App().json2csv( user_json_data );
		/*
		String profile_json_data = new App().getProfiles("311");
		System.out.println(profile_json_data);
		*/
    }
}

```
</details>


### 　実行してみよう
以下のように実行することで、export_user.csvを取得することが可能です。

```
@ sample_code % gradle compileJava

BUILD SUCCESSFUL in 589ms
1 actionable task: 1 executed
@ sample_code % gradle run        

> Task :app:run
Remaining Token 4
Remaining Token 4
.
.
.(一部省略)
.
Remaining Token 2
Remaining Token 4
Data has been Writteen
```