API (интерфейсы прикладного программирования) — это средства, с помощью которых различные компоненты веб-приложения взаимодействуют друг с другом по сети. API необходимы для создания современных масштабируемых, надежных и безопасных веб-приложений.

Но как выбрать правильный дизайн API для своего веб-приложения? Существует множество различных способов разработки и реализации API, каждый из которых имеет свои преимущества и недостатки. В этой статье мы сравним три популярных подхода: TRPC, GRPC и REST API. Мы объясним, что это такое, как они работают и когда их использовать. Мы также поделимся некоторыми реальными примерами и историями из Google и других компаний, которые используют эти подходы.

Что такое ТРПК?

TRPC — это библиотека TypeScript, которая позволяет вам определить схему API в TypeScript и использовать ее для создания клиентского и серверного кода, обеспечивающего безопасность типов. Он использует JSON-RPC в качестве базового протокола и HTTP в качестве транспортного уровня. Он нативен для Интернета и прост в использовании, но поддерживает только TypeScript в качестве языка программирования.

Алекс Йоханссон, веб-разработчик, который был разочарован отсутствием безопасности типов и проверки схемы в традиционных REST API, создал TRPC. Он хотел иметь простой и элегантный способ создания API, использующий всю мощь TypeScript. Его вдохновил GraphQL, но он хотел избежать некоторых его недостатков, таких как избыточная и неполная выборка и сложные инструменты.

TRPC идеально подходит для веб-приложений, использующих TypeScript как во внешнем, так и во внутреннем интерфейсе. Это позволяет вам написать схему API один раз и использовать ее везде. Это также позволяет вам выполнять сквозную проверку типов и проверку ваших данных. Это особенно полезно для быстрого и простого создания прототипов и разработки MVP (минимально жизнеспособных продуктов).

Вот пример использования TRPC для создания простого API блога:

// Define your API schema in TypeScript
import * as trpc from "@trpc/server";
import * as trpcNext from "@trpc/server/adapters/next";

// Define your data types
type Post = {
  id: number;
  title: string;
  content: string;
};

type Comment = {
  id: number;
  postId: number;
  author: string;
  text: string;
};

// Define your API methods
export const appRouter = trpc.router().query("posts", {
  resolve() {
    // Return a list of posts from the database
    return db.posts.findMany();
  },
}).query("postById", {
  input: z.number(),
  resolve({ input }) {
    // Return a single post by id from the database
    return db.posts.findUnique({ where: { id: input } });
  },
}).mutation("createPost", {
  input: z.object({
    title: z.string(),
    content: z.string(),
  }),
  resolve({ input }) {
    // Create a new post in the database
    return db.posts.create({ data: input });
  },
}).mutation("createComment", {
  input: z.object({
    postId: z.number(),
    author: z.string(),
    text: z.string(),
  }),
  resolve({ input }) {
    // Create a new comment in the database
    return db.comments.create({ data: input });
  },
});

// Generate the client and server code for your API
export type AppRouter = typeof appRouter;

export const trpcClient = createTRPCClient<AppRouter>({
  url: "/api/trpc",
});

export default trpcNext.createNextApiHandler({
  router: appRouter,
});

Что такое ГРПК?

GRPC — это инфраструктура, позволяющая определить схему API в protobuf (двоичном формате) и использовать ее для генерации клиентского и серверного кода на различных языках (таких как C++, Java, Go, Python и т. д.). Он использует HTTP/2 в качестве базового протокола и транспортного уровня. Он оптимизирован с точки зрения производительности и масштабируемости, но требует генерации кода и специальной цепочки инструментов.

GRPC был создан Google как преемник его внутренней структуры RPC под названием Stubby. Google требовался способ обработки миллионов запросов в секунду в распределенных системах с малой задержкой и высокой надежностью. GRPC был разработан для удовлетворения этих требований за счет использования двоичной сериализации, двунаправленной потоковой передачи, мультиплексирования, сжатия, балансировки нагрузки, аутентификации и т. д.

GRPC идеально подходит для архитектур микросервисов, которые используют разные языки и платформы на стороне клиента и сервера. Это позволяет вам написать схему API один раз и использовать ее везде. Он также позволяет использовать функции и преимущества HTTP/2, такие как мультиплексирование, потоковая передача и управление потоком. Это особенно полезно для высокопроизводительных приложений с малой задержкой, которым необходимо обрабатывать большие объемы данных.

Вот пример того, как использовать GRPC для создания простого API блога:

// Define your API schema in protobuf
syntax = "proto3";

package blog;

// Define your data types
message Post {
  int32 id = 1;
  string title = 2;
  string content = 3;
}

message Comment {
  int32 id = 1;
  int32 post_id = 2;
  string author = 3;
  string text = 4;
}

// Define your API methods
service BlogService {
  rpc GetPosts (Empty) returns (PostList) {}
  rpc GetPostById (PostId) returns (Post) {}
  rpc CreatePost (Post) returns (Post) {}
  rpc CreateComment (Comment) returns (Comment) {}
}

message Empty {}

message PostId {
  int32 value = 1;
}

message PostList {
  repeated Post posts = 1;
}

Сгенерируйте клиентский и серверный код для вашего API на предпочитаемом вами языке. Например, в Go:

// Import the generated code
import (
    "context"
    "log"

    pb "github.com/myuser/myrepo/blog"
    "google.golang.org/grpc"
)

// Create a grpc client
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
    log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
client := pb.NewBlogServiceClient(conn)

// Call the API methods
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

// Get a list of posts
posts, err := client.GetPosts(ctx, &pb.Empty{})
if err != nil {
    log.Fatalf("could not get posts: %v", err)
}
log.Printf("Posts: %v", posts)

// Get a single post by id
post, err := client.GetPostById(ctx, &pb.PostId{Value: 1})
if err != nil {
    log.Fatalf("could not get post: %v", err)
}
log.Printf("Post: %v", post)

// Create a new post
newPost, err := client.CreatePost(ctx, &pb.Post{Title: "Hello World", Content: "This is my first post"})
if err != nil {
    log.Fatalf("could not create post: %v", err)
}
log.Printf("New Post: %v", newPost)

// Create a new comment
newComment, err := client.CreateComment(ctx, &pb.Comment{PostId: 1, Author: "Alice", Text: "Nice post"})
if err != nil {
    log.Fatalf("could not create comment: %v", err)
}
log.Printf("New Comment: %v", newComment)

Что такое REST API?

REST API — это стиль дизайна API, который следует принципам REST (передача репрезентативного состояния). Он использует HTTP в качестве базового протокола и транспортного уровня, а также любой формат данных (например, JSON, XML и т. д.) в качестве полезной нагрузки. Он основан на концепции ресурсов, которые можно идентифицировать по URL-адресам и управлять ими с помощью методов HTTP (таких как GET, POST, PUT, DELETE и т. д.). Он широко используется и поддерживается многими инструментами и платформами, но не обеспечивает безопасность типов или проверку схемы.

API REST был предложен Роем Филдингом в его докторской диссертации как способ описания архитектуры Интернета. Он определил набор ограничений и свойств, которые делают API RESTful, таких как отсутствие состояния, унифицированный интерфейс, возможность кэширования, многоуровневая система и т. д. Он также представил концепцию HATEOAS (гипермедиа как механизм состояния приложения), что означает, что клиент должен иметь возможность обнаруживать доступные действия и ресурсы из ответов сервера.

REST API идеально подходит для веб-приложений, которые должны быть совместимы с различными клиентами и платформами. Он позволяет вам использовать стандартные функции и соглашения HTTP, такие как заголовки, коды состояния, кэширование и т. д. Он также позволяет вам использовать любой формат данных, который соответствует вашим потребностям и предпочтениям. Это особенно полезно для простых приложений и приложений на основе CRUD, которым не требуется сложная логика или потоковая передача.

Вот пример использования rest API для создания простого API блога:

// Define your API methods using HTTP verbs and URLs

// Get a list of posts
GET /posts

// Get a single post by id
GET /posts/1

// Create a new post
POST /posts
Content-Type: application/json

{
  "title": "Hello World",
  "content": "This is my first post"
}

// Update an existing post by id
PUT /posts/1
Content-Type: application/json

{
  "title": "Hello World",
  "content": "This is my updated post"
}
// Delete an existing post by id 
DELETE /posts/1

// Get a list of comments for a post by id 
GET /posts/1/comments

// Get a single comment by id 
GET /comments/1

// Create a new comment for a post by id 
POST /posts/1/comments 
Content-Type: application/json

{ 
  "author": "Alice",
  "text": "Nice post"
}

// Update an existing comment by id 
PUT /comments/1 
Content-Type: application/json

{ 
  "author": "Alice", 
  "text": "Great post"
}

// Delete an existing comment by id 
DELETE /comments/1

Как выбрать правильный дизайн API для вашего веб-приложения?

На этот вопрос нет однозначного ответа, поскольку разные конструкции API имеют разные компромиссы и подходят для разных сценариев и предпочтений. Тем не менее, вот несколько общих рекомендаций, которые помогут вам принять взвешенное решение:

  • Рассмотрите вариант использования и требования. Какое веб-приложение вы создаете? Каковы основные функции и функции? Насколько сложна логика и данные? Какая производительность и масштабируемость вам нужны? Сколько клиентов и платформ вам нужно поддерживать?
  • Подумайте о своем языке программирования и фреймворке. Какой язык и фреймворк вы используете на фронтенде и бэкенде? Насколько вам с ними хорошо и комфортно? Насколько хорошо они поддерживают дизайн API, который вы хотите использовать? Насколько легко или сложно интегрировать их с другими инструментами и сервисами?
  • Рассмотрите свой процесс разработки и ресурсы. Насколько быстрым и ловким вы хотите быть? Сколько времени и усилий вы хотите потратить на разработку, внедрение, тестирование и поддержку вашего API? Сколько документации и поддержки вам нужно? Какую гибкость и контроль вы хотите иметь над своим API?

Исходя из этих соображений, вы можете выбрать дизайн API, который наилучшим образом соответствует вашим потребностям и предпочтениям. Вот несколько примеров того, как Google и другие компании используют разные дизайны API для своих веб-приложений:

  • Google использует GRPC для многих своих внутренних служб и продуктов, таких как Google Cloud Platform, YouTube, Gmail и т. д. GRPC позволяет Google достигать высокой производительности и масштабируемости в своих распределенных системах с малой задержкой и высокой надежностью. GRPC также позволяет Google использовать различные языки и платформы для своих сервисов, такие как C++, Java, Go, Python и т. д.
  • Google также использует rest API для некоторых своих общедоступных API, таких как Карты Google, Google Диск, Календарь Google и т. д. Rest API позволяет Google предоставлять простой и согласованный интерфейс для своих пользователей и разработчиков. Rest API также позволяет Google использовать стандартные функции и соглашения HTTP, такие как заголовки, коды состояния, кэширование и т. д.
  • Spotify использует TRPC для своего приложения веб-плеера. TRPC позволяет Spotify обеспечивать безопасность типов и проверку схемы для своих данных. TRPC также позволяет Spotify один раз написать свою схему API и использовать ее везде. TRPC особенно полезен для быстрого и простого создания прототипов Spotify и разработки MVP.
  • Netflix использует rest API для своего потокового сервиса. Rest API позволяет Netflix быть совместимым с различными клиентами и платформами, такими как браузеры, мобильные устройства, смарт-телевизоры и т. д. Rest API также позволяет Netflix использовать любой формат данных, который соответствует его потребностям и предпочтениям, например JSON, XML и т. д. rest API особенно полезен для простых приложений Netflix и приложений на основе CRUD, которым не требуется сложная логика или потоковая передача.

Заключение

Дизайн API — важный аспект веб-разработки, который нельзя упускать из виду. Выбрав правильный дизайн API для своего веб-приложения, вы можете улучшить его производительность, безопасность, надежность, масштабируемость и удобство сопровождения.