RestAPI
特徴
-
エンドポイントベース: 各リソースに対して個別のエンドポイントが存在します(例:
/users
,/posts
)。 - HTTPメソッドの使用: リソースの操作はHTTPメソッド(GET, POST, PUT, DELETE)を用いて行います。
- ステートレス: 各リクエストは独立しており、サーバーはクライアントの状態を保持しません。
- キャッシュ可能: HTTPのキャッシュ機能を活用できます。
書き方の例
以下は、Golangを使用したシンプルなRestAPIの例です。
package main
import (
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
var users = []User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
}
func getUsers(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(users)
}
func getUser(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id, _ := strconv.Atoi(params["id"])
for _, user := range users {
if user.ID == id {
json.NewEncoder(w).Encode(user)
return
}
}
http.Error(w, "User not found", http.StatusNotFound)
}
func createUser(w http.ResponseWriter, r *http.Request) {
var newUser User
json.NewDecoder(r.Body).Decode(&newUser)
users = append(users, newUser)
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(newUser)
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/users", getUsers).Methods("GET")
r.HandleFunc("/users/{id}", getUser).Methods("GET")
r.HandleFunc("/users", createUser).Methods("POST")
http.ListenAndServe(":3000", r)
}
GraphQL
特徴
-
単一エンドポイント: 全てのリクエストは単一のエンドポイントを通じて行われます(例:
/graphql
)。 - 柔軟なクエリ: クライアントは必要なデータを正確に指定して取得できます。
- 型システム: スキーマに基づき、データの型が明確に定義されます。
- リアルタイム更新: サブスクリプションを使用してリアルタイムのデータ更新が可能です。
書き方の例
以下は、GolangとGraphQLを使用したシンプルなGraphQL APIの例です。
package main
import (
"github.com/graphql-go/graphql"
"github.com/graphql-go/handler"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
var users = []User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
}
var userType = graphql.NewObject(graphql.ObjectConfig{
Name: "User",
Fields: graphql.Fields{
"id": &graphql.Field{
Type: graphql.Int,
},
"name": &graphql.Field{
Type: graphql.String,
},
},
})
var queryType = graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"users": &graphql.Field{
Type: graphql.NewList(userType),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return users, nil
},
},
"user": &graphql.Field{
Type: userType,
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Type: graphql.Int,
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
id, ok := p.Args["id"].(int)
if ok {
for _, user := range users {
if user.ID == id {
return user, nil
}
}
}
return nil, nil
},
},
},
})
var mutationType = graphql.NewObject(graphql.ObjectConfig{
Name: "Mutation",
Fields: graphql.Fields{
"addUser": &graphql.Field{
Type: userType,
Args: graphql.FieldConfigArgument{
"name": &graphql.ArgumentConfig{
Type: graphql.String,
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
name, _ := p.Args["name"].(string)
newUser := User{ID: len(users) + 1, Name: name}
users = append(users, newUser)
return newUser, nil
},
},
},
})
func main() {
schema, _ := graphql.NewSchema(graphql.SchemaConfig{
Query: queryType,
Mutation: mutationType,
})
h := handler.New(&handler.Config{
Schema: &schema,
Pretty: true,
})
http.Handle("/graphql", h)
http.ListenAndServe(":3000", nil)
}
gRPC
特徴
- プロトコルバッファ: データのシリアライズ形式としてプロトコルバッファ(Protocol Buffers)を使用します。
- 効率的な通信: バイナリ形式での通信により高速で低容量のデータ転送が可能です。
- 双方向ストリーミング: クライアントとサーバー間で双方向のストリーミング通信が可能です。
- 多言語対応: gRPCは様々なプログラミング言語をサポートしています。
書き方の例
以下は、Golangを使用したシンプルなgRPCサーバーとクライアントの例です。
プロトコルバッファ定義 (user.proto)
syntax = "proto3";
package user;
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc CreateUser (CreateUserRequest) returns (User);
}
message User {
int32 id = 1;
string name = 2;
}
message GetUserRequest {
int32 id = 1;
}
message CreateUserRequest {
string name = 1;
}
サーバー実装 (server.go)
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "path/to/your/proto/package"
)
type server struct {
pb.UnimplementedUserServiceServer
users []pb.User
}
func (s *server) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.User, error) {
for _, user := range s.users {
if user.Id == req.Id {
return &user, nil
}
}
return nil, nil
}
func (s *server) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.User, error) {
newUser := pb.User{Id: int32(len(s.users) + 1), Name: req.Name}
s.users = append(s.users, newUser)
return &newUser, nil
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
pb.RegisterUserServiceServer(grpcServer, &server{})
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
クライアント実装 (client.go)
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
pb "path/to/your/proto/package"
)
func main() {
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
client := pb.NewUserServiceClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
// Create a new user
newUser, err := client.CreateUser(ctx, &pb.CreateUserRequest{Name: "Charlie"})
if err != nil {
log.Fatalf("could not create user: %v", err)
}
log.Printf("Created user: %v", newUser)
// Get user
user, err := client.GetUser(ctx, &pb.GetUserRequest{Id: newUser.Id})
if err != nil {
log.Fatalf("could not get user: %v", err)
}