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