フロントエンドとバックエンドでWebアプリケーションを分けたり、知っているといろいろと便利なRestAPIを作ってみたので書いておく。Spirngをこれから勉強するような人はWebアプリを作る前にRestAPIを作ってみるといいかもしれない。

作るAPI

User(name, email)を持つEntityをCRUDするAPIを作成する。Springのドキュメントが参考になった。

作るAPIは以下の通り。

  • GET /api/users => 全User取得 (getUsers)
  • GET /api/users/{id} => idのUserを取得 (getUser)
  • POST /api/users => Userを追加 (createUser)
  • PUT /api/users/{id} => Userの更新 (updateUser)
  • DELETE /api/users/{id} => idのUserを削除 (deleteUser)

ソースコードはここ

DBの設定

RDBはMariaDBを使うが、インストールについては省略。

データベースとテーブルは次の通り。

CREATE DATABASE sample_db;
CREATE TABLE users (
id int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
email varchar(255) NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO users(id, name, email) VALUES(1, 'ishii', 'ishii@ishii.tech');

application.propertiesに接続情報を設定。

spring.datasource.url=jdbc:mysql://localhost/sample_db
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

dependency

Spring Initializrでjpa, web, lombok, mysqlを選択してプロジェクトを作る。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

下準備

Entitiy, Repository, Serviceを作る。

@Data
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
private String email;
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
@Service
@Transactional
public class UserService {
@Autowired
UserRepository userRepository;

public User findUser(Long id){
return userRepository.findOne(id);
}
public List<User> findUsers(){
return userRepository.findAll();
}
public User save(User user) {
return userRepository.save(user);
}
public void delete(Long id) {
userRepository.delete(id);
}
}

Controller

Userをやり取りするためのControllerを作る。HTTPリクエストに対応する処理を記述する。Userのところをリソース名に置き換えれば他のリソースにも使いまわせそう。Responseコードを今回は指定しなかったが厳密に実装する場合は指定すると良いかも?

@RestController
@RequestMapping("/api/users")
public class UserController {

@Autowired
UserService userService;

@RequestMapping(method = RequestMethod.GET)
public List<User> getUsers() {
return userService.findUsers();
}

@RequestMapping(method=RequestMethod.GET, value="{id}")
public User getUser(@PathVariable("id") Long id) {
return userService.findUser(id);
}

@RequestMapping(method=RequestMethod.POST)
public User createUser(@Validated @RequestBody User user) {
return userService.save(user);
}

@RequestMapping(method=RequestMethod.PUT, value="{id}")
public User updateUser(@PathVariable("id") Long id, @RequestBody User user) {
user.setId(id);
return userService.save(user);
}

@RequestMapping(method=RequestMethod.DELETE, value="{id}")
public void deleteUser(@PathVariable("id") Long id) {
userService.delete(id);
}

}

@RestControllerがRestAPIを作るためのアノテーションで、@Controller + @ResponseBody + JSONでやり取りができるようになる。spring-boot-starter-webがJacksonで受け取るところと表示するところをうまく処理してくれる。

他のアノテーションはよく出てくるので省略。

動作確認

作った5つのメソッドを呼び出してみる。

全User取得(getUsers)

$ curl localhost:8080/api/users
[{"id":1,"name":"ishii","email":"ishii@ishii.tech"}]

1件しか表示されていないが、複数件あった場合は複数表示される。JsonがArrayになっていることが確認できる。

Userを追加(createUser)

$ curl -XPOST -H "Content-Type:application/json" http://localhost:8080/api/users -d '{
"name":"ishii2","email":"ishii2@ishii.tech"
}'
{"id":2,"name":"ishii2","email":"ishii2@ishii.tech"}

idのUserを取得(getUser)

$ curl localhost:8080/api/users/1
{"id":1,"name":"ishii","email":"ishii@ishii.tech"}

Userの更新(updateUser)

$ curl -XPUT -H "Content-Type:application/json" localhost:8080/api/users/1 -d '{
"name":"aaaaa","email":"aaaaa@ishii.tech"
}'
{"id":1,"name":"aaaaa","email":"aaaaa@ishii.tech"}

$ curl localhost:8080/api/users/1
{"id":1,"name":"aaaaa","email":"aaaaa@ishii.tech"}

idのUserを削除(deleteUser)

$ curl -XDELETE localhost:8080/api/users/1
$ curl localhost:8080/users
[{"id":2,"name":"ishii2","email":"ishii2@ishii.tech"}]

まとめ

RestAPIの作り方を調べてたら、HATEOASというものを見つけたりといろいろと勉強になった。全てにはまるAPIの作り方は無いみたいなのでしっかり設計が必要になりそう。API自体の実装はすご~く簡単だけどEntityのリソースをURIにマッピングして自然な感じのAPIを設計するのはかなり難しいな~と感じているところです。

おわり。

参考

  1. http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
  2. https://spring.io/understanding/REST
  3. https://spring.io/guides/gs/rest-service/
  4. http://projects.spring.io/spring-restdocs/
  5. http://spring.io/guides/tutorials/bookmarks/
  6. http://qiita.com/taiyop/items/78d3a0614be9be77ce41