
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 для своего веб-приложения, вы можете улучшить его производительность, безопасность, надежность, масштабируемость и удобство сопровождения.