0
0

初心者がREST APIについてまとめてみた。

Last updated at Posted at 2024-07-31

はじめに

研修期間中は、リクエストごとにURLを変えていましたが、どうやらREST APIってのがあるらしい、、
ということで、簡単にまとめてみました。

※誤りありましたら、ご指摘いただけますと幸いです。

REST APIとは

RESTと呼ばれる(Representational State Transfer)、Webサービスの設計におけるアーキテクチャスタイルの一つをもとに設計されたAPIを指します。

RESTでは、次に挙げる6つの原則が定められています。

  1. クライアント-サーバーアーキテクチャ(Client-Server Architecture)
    クライアントとサーバーの役割を明確に分けることによって、両者の独立した開発・運用を可能にします。

  2. ステートレス(Statelessness)
    クライアントから送られる各リクエストには、必要な情報が全て含まれており、サーバーはリクエスト間でクライアントの状態を保持しません。(クライアントからのリクエストはサーバーの状態に依存しないということ)これにより、スケーラビリティとシステムの信頼性が向上します。

  3. キャッシュ可能(Cacheable)
    適切なHTTPヘッダー(例えばCache-Control)を使って、レスポンスのキャッシュ可能性をクライアントに通知します。これにより、通信におけるデータ量が抑えられ、ネットワークの負荷が下がります。

  4. 統一インターフェース(Uniform Interface)
    予め決められた方法でデータのやり取りを行うことを指します。リソースに対する操作は、 HTTPメソッド (GET, POST, PUT, DELETE等)を通じて行ったり、リソースは様々な形式(JSON, XMLなど)で表現され、クライアントはこれらの形式でリソースを理解します。

  5. レイヤードシステム(Layered System)
    レイヤードアーキテクチャとも呼ばれ、システムは複数の階層に分離して構築され、各階層は独自の役割を持ちます。

  6. コードオンデマンド(Code on Demand, optional)
    サーバーはクライアントに、クライアント側で実行できるコード(現在はJavaScriptが多い)を送信し、クライアント側の実装コストを下げます。
    ちなみにこの原則のみはあくまで任意となっています。

コードの比較

実際のコードを見てみましょう。
今回は、テンプレートエンジン(Thymeleaf)を使用してHTMLを返す実装と、REST APIを用いた実装の比較になります。

パッケージ指定とインポート文は省略しています

HTMLを返すコントローラクラス

java
@Controller
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping
    public String getAllUsers(Model model) {
        List<User> users = userService.getAllUsers();
        model.addAttribute("users", users);
        return "user-list"; // Thymeleafテンプレート名(user-list.html)
    }

    @RequestMapping("/{id}")
    public String getUserById(@PathVariable Long id, Model model) {
        User user = userService.getUserById(id).orElse(null);
        model.addAttribute("user", user);
        return "user-detail"; // Thymeleafテンプレート名(user-detail.html)
    }

    @RequestMapping("/toCreate")
    public String showCreateUserForm(Model model) {
        model.addAttribute("user", new User());
        return "user-form"; // Thymeleafテンプレート名(user-form.html)
    }

    @RequestMapping("/create")
    public String createUser(@ModelAttribute User user, Model model) {
        userService.createUser(user);
        return "redirect:/users"; // ユーザーリストページにリダイレクト
    }

    @RequestMapping("/edit/{id}")
    public String showEditUserForm(@PathVariable Long id, Model model) {
        User user = userService.getUserById(id).orElse(null);
        if (user != null) {
            model.addAttribute("user", user);
            return "user-form"; // Thymeleafテンプレート名(user-form.html)
        } else {
            return "redirect:/users"; // ユーザーリストページにリダイレクト
        }
    }

    @RequestMapping("/update/{id}")
    public String updateUser(@PathVariable Long id, @ModelAttribute User user, Model model) {
        userService.updateUser(id, user);
        return "redirect:/users"; // ユーザーリストページにリダイレクト
    }

    @RequestMapping("/delete/{id}")
    public String deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return "redirect:/users"; // ユーザーリストページにリダイレクト
    }
}

REST APIを基にしたコントローラクラス

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

    @Autowired
    private UserService userService;

    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }

    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return userService.getUserById(id)
                .map(ResponseEntity::ok)
                .orElseGet(() -> ResponseEntity.notFound().build());
    }

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User createdUser = userService.createUser(user);
        return ResponseEntity.ok(createdUser);
    }

    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.updateUser(id, user)
                .map(ResponseEntity::ok)
                .orElseGet(() -> ResponseEntity.notFound().build());
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        if (userService.deleteUser(id)) {
            return ResponseEntity.noContent().build();
        } else {
            return ResponseEntity.notFound().build();
        }
    }
}

違いについて

上記の2種類のコードの大きな違いを2点解説します。

@Controller@RestController

@RestController は、@Controller@ResponseBodyの組み合わせとして機能します。@ResponseBodyが付与されると、メソッドの戻り値を JSONXML などの形式にシリアライズします。

ちなみにJSON(JavaScript Object Notation)方式で送られるデータはこんな感じ。

json
{
  "name": "山田太郎",
  "email": "yamada.tarou@example.com"
}

JSONはデータ記述言語のひとつであり、Java, PHP, Ruby, Python など、様々な言語間のデータ交換で使用されています。

②URLの対応付け

作成・取得・更新・削除を行うにあたって、前者では@RequestMappingを使用して、各処理とURLが紐づいていました。

しかし後者は、各処理が@RequestMapping("/api/users")というURLと、@GetMapping@PostMapping等に紐づいています。

では、そのように処理を区別しているかというと、ここで登場するのが HTTPリクエストメソッド になります。

HTTPリクエストメソッドには「GET」なら取得、「POST」なら作成、「PUT」なら更新、「DELETE」なら削除のように、どのようなやり取りを行うか、という情報が含まれており、この情報を基に処理を決定する形になります。

まとめ

REST APIという共通の枠組みを用いて開発が行えることで、シンプルで理解しやすい開発が可能になります。

API実装において、REST APIは主流になってきているので、もっと細かい部分もキャッチアップが必要だと感じました。

参考文献

0からREST APIについて調べてみた
「RESTとはなんぞや?」を4原則から考えてみる
REST APIとは?6つのルールを初心者向けにわかりやすく解説!
REST APIとは何か?初心者にもわかりやすく解説します!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0