はじめに
タイトルの通りです
定義を設定するだけで、CRUDのRESTWebapiを作れるシステムです
似たようなもので、FirebaseのRealtimeDatabaseやFireStoreがありますが
色々と制限が多く、バリデーションが難しいようだったので作ってみました
Java(Spring Boot)とMongoDBで作りました
ここで使ったシステムです
エンジニア・プログラマにしか使えないSNSを作ってみた話
2020/07/20 ソースコード公開
https://github.com/HawkClaws/versatileapi
フロー図
フロー詳細
WebApi定義を登録
管理者用WebApiを使用し、API定義を登録します
登録例
apiUrl:APIのURL
apiSecret:認証に使用するシークレットキー
jsonSchema:バリデーションに使用するJsonSchema
methodSettings:各メソッドの設定
{
"apiSecret": "",
"apiUrl":"number_battle",
"jsonSchema": {
"additionalProperties":false,
"type": "object",
"properties": {
"name": {
"description": "名前",
"type": "string",
"maxLength": 30
},
"secondNumber": {
"description": "2番目に大きいと予想した数字",
"type": "number"
}
},
"required": [
"name",
"secondNumber"
]
},
"methodSettings": [
{
"httpMethod": "GET",
"behavior": "Allow"
},
{
"httpMethod": "POST",
"behavior": "Allow"
},
{
"httpMethod": "PUT",
"behavior": "NotImplemented"
},
{
"httpMethod": "DELETE",
"behavior": "NotImplemented"
}
]
}
WebApiを実行
1.URIからリソース・API定義・リソースIDを特定
2.WebApi定義を取得(もちろんOnMemoryキャッシュする)
3.定義を使用してJsonSchemaバリデーション・認証・許可されているメソッドをチェック
4.各メソッドのAPIを実行
ソースコード
@RequestMapping(value = "/api/**")
public ResponseEntity<Object> versatileApi(HttpServletRequest request)
throws IOException, InterruptedException, ExecutionException {
//URLからリソース(DBテーブル)やリソースのID特定
RepositoryUrlInfo info = urlConverter.getRepositoryInfo(request.getRequestURI());
String method = request.getMethod();
String body = request.getReader().lines().collect(Collectors.joining("\r\n"));
writeLog(request, body);
ResponseEntity responseEntity = null;
try {
//JsonSchemaバリデーション・認証・許可されているメソッドをチェック
responseEntity = versatileService.checkUseApi(info.repositoryKey, info.id, method, body,
request.getHeader(ConstData.AUTHORIZATION));
} catch (JsonParsingException e) {
return new ResponseEntity<>(gson.toJson("JsonParseError:" + e.getMessage()), new HttpHeaders(),
HttpStatus.BAD_REQUEST);
}
if (responseEntity != null)
return responseEntity;
Object response = null;
//各メソッドの処理を実行
switch (method) {
case HttpMethods.GET:
response = versatileService.get(info.id, info.repositoryKey, request.getQueryString());
if (response == null || Objects.equal(response, "")) {
return new ResponseEntity<>(response, new HttpHeaders(), HttpStatus.NOT_FOUND);
} else {
return new ResponseEntity<>(response, new HttpHeaders(), HttpStatus.OK);
}
case HttpMethods.POST:
response = versatileService.post(info.id, info.repositoryKey, request.getQueryString(), body,
request.getRemoteAddr());
return new ResponseEntity<>(response, new HttpHeaders(), HttpStatus.CREATED);
case HttpMethods.PUT:
response = versatileService.put(info.id, info.repositoryKey, request.getQueryString(), body,
request.getRemoteAddr());
return new ResponseEntity<>(response, new HttpHeaders(), HttpStatus.OK);
case HttpMethods.DELETE:
response = versatileService.delete(info.id, info.repositoryKey, request.getQueryString());
return new ResponseEntity<>(response, new HttpHeaders(), HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>("", new HttpHeaders(), HttpStatus.NOT_IMPLEMENTED);
}
以上、このような感じです
おまけ
投稿者の中で2番目に大きい数値を当てるゲーム
一番大きい数値を予想して、それより小さい数字、他の数字より大きい数字を当てる
心理的??ゲームです。いや、運ゲーかも
####エンドポイント
https://versatileapi.herokuapp.com/api
数値を当てる
POST /number_battle
結果を見る
GET /number_battle/all?$orderby=secondNumber desc&$skip=1&$limit=1