Skip to main content

REST API დიზაინი, რომელიც გადარჩება: ვერსიონირება, auth, შეცდომები და ის, რასაც არავინ ასწავლის

Endpoint-ის გამოშვება ყველას შეუძლია. API-ები, რომლებიც უძლებენ ხუთ წელს კონსიუმერებით, მიგრაციებით და ღამის 3 საათის ინციდენტებით, დაპროექტებულია მოსაწყენი ნაწილების გარშემო: ვერსიონირება, რომელთანაც ცხოვრება შეიძლება, auth, რომელიც დახურულ მდგომარეობაში ვარდება, შეცდომები, რომლებსაც მანქანა პარსავს, და პაგინაცია, რომელიც არ იტყუება.

REST API დიზაინი, რომელიც გადარჩება: ვერსიონირება, auth, შეცდომები და ის, რასაც არავინ ასწავლის

ყველა ტუტორიალი ერთსა და იმავე REST API-ს ასწავლის: ხუთი როუტი, happy path, JSON შედის, JSON გამოდის, ერთ საღამოში მზადაა. მერე API რეალობას ხვდება — მობილური კლიენტი, რომელიც სამი კვირა ვერ განახლდება, პარტნიორის ინტეგრაცია, დაწერილი ბეჭდვითი შეცდომის ზემოთ, რომელსაც ახლა ვეღარ გაასწორებ, security-რევიუ, პაგინაციის ბაგი, რომელმაც არავის ჩამოაჭრა ორჯერ, მაგრამ ყველას ყველაფერი ორჯერ აჩვენა — და აღმოაჩენ, რომ ტუტორიალმა მარტივი 20% დაფარა. დანარჩენ 80%-ზეა ეს პოსტი.

ეს ის გადაწყვეტილებებია, რომელთა დაცვა (ან რომლებზეც ნანვა) წლების production-API-ების განმავლობაში მომიწია — იმ თანმიმდევრობით, რომლითაც ისინი ჩვეულებრივ გვკბენენ. და შემთხვევითი არ არის, რომ ეს ზუსტად ის თემებია, რომლებსაც system design ინტერვიუ სინჯავს, როცა ინტერვიუერი ამბობს: „ახლა კი დააპროექტე ამისთვის API”.

როგორ ვერსიონირებ API-ს, რომლის გატეხვაც არ შეიძლება?

ვერსიონირება პირველი დღიდან, URL-ში, და ყოველ გამოქვეყნებულ ველს მოექეცი როგორც კონტრაქტს, რომელსაც წლების განმავლობაში დაიცავ. იმ მომენტში, როცა ერთი კონსიუმერი, რომელსაც შენ არ აკონტროლებ, შენი API-ს ზემოთ კოდს უშვებს, „მერე გავასუფთავებთ” ფიქცია ხდება: ველის გადარქმევა breaking change-ია, ველის წაშლა breaking change-ია, ტიპის შეცვლა კი ინციდენტია შენი გვარით. /v1/ მისამართში არაგლამურული და ოდნავ არაელეგანტურია — და ეს ის მიდგომაა, რომლის ჩავარდნის რეჟიმებიც მოსაწყენია, რაც API დიზაინში უმაღლესი კომპლიმენტია.

სანამ გადაწყვეტილება-გადაწყვეტილებით წავალთ, აი მთელი პოსტი ერთ ცხრილში — ტუტორიალის პასუხი, პასუხი, რომელიც კონსიუმერების ხუთ წელს უძლებს, და ის, რაც მალსახმობმა რეალურად დაგიჯდება, როცა ანგარიში მოვა:

გადაწყვეტილებატუტორიალის პასუხიპასუხი, რომელიც გადარჩებარა დაგიჯდება მალსახმობი
ვერსიონირებადაამატე და გადაარქვი ველებს თავისუფლად/v1/ პირველი დღიდან; გამოქვეყნების შემდეგ მხოლოდ ადიტიური ცვლილებებიყოველი გადარქმევა ინციდენტია სხვისი აპლიკაციის შიგნით
Auth ნაგულისხმევადდაამატე auth იმ endpoint-ებს, რომლებსაც სჭირდებათDeny by default; საჯარო როუტები ცხადად არის მონიშნულიის ერთი endpoint, რომელიც ვიღაცამ დაავიწყდა და კრაულერმა შენზე ადრე იპოვა
ავტორიზაციავალიდური ტოკენი ნიშნავს, რომ გამომძახებელს უფლება აქვსშეამოწმე მფლობელობა რესურსის ყოველ წაკითხვაზეშენი კლიენტის მონაცემები, სხვა კლიენტისთვის მიწოდებული
შეცდომებიHTTP-სტატუსი პლუს პროზაული შეტყობინებამანქანური კოდი, ადამიანური შეტყობინება, correlation IDინტეგრატორები გამოიცნობენ; მათი ბაგ-რეპორტი შენი ღამის 3 საათის ზარი ხდება
პაგინაცია?page=3გაუმჭვირვალე cursor მნიშვნელობით „გააგრძელე ამ სტრიქონის შემდეგ”ელემენტები დუბლირდება და ქრება ჩაწერების ქვეშ; ღრმა გვერდები სკანავს და გადაყრის
დოკუმენტაციის აუდიტორიაადამიანები, რომლებიც მას გადაათვალიერებენყველაზე პირდაპირი კონსიუმერი, რომელიც ოდესმე გეყოლებააგენტი ჰალუცინირებს პარამეტრს, რომელიც ბუნდოვნად დატოვე

ნამდვილი დისციპლინა URL-სქემაში კი არა, ადიტიური ცვლილებების ჩვევაშია. ახალი შესაძლებლობა? ახალი ოფციური ველი, ახალი endpoint — და არასდროს არსებულის შეცვლილი მნიშვნელობა. გუნდები, რომლებმაც შეითვისეს „გამოქვეყნებული ნიშნავს სამუდამოს”, ველებს უფრო ფრთხილად აპროექტებენ გამოქვეყნებამდე ვე, და სწორედ ეს არის რეალური სარგებელი: ვერსიონირების დისციპლინა ძირითადად forcing function-ია, რომელიც ორჯერ დაფიქრებას გაიძულებს.

როგორ გამოიყურება auth, რომელიც „fails closed”?

ყოველი endpoint ავთენტიფიკაციას მოითხოვს, თუ ის ცხადად და გააზრებულად არ არის მონიშნული საჯაროდ — deny-by-default middleware პატერნი, სადაც როუტის კონფიგურაციის დავიწყება ნიშნავს, რომ ის დახურულია და არა ღია. ინდუსტრიის განმეორებადი API-კატასტროფა გატეხილი კრიპტოგრაფია კი არა, ის endpoint-ია, რომლის დაცვაც ვიღაცამ დაავიწყდა და კრაულერმა იპოვა. Fail-closed დიზაინი ამ შეცდომას სტრუქტურულად შეუძლებელს ხდის: ზარმაცი გზა და უსაფრთხო გზა ერთი და იგივე გზაა.

ავტორიზაცია იმავე პარანოიას იმსახურებს ერთი დონით ღრმად: ავთენტიფიკაცია ამბობს, ვინ ხარ, ავტორიზაცია — რა არის შენი, და მათ შორის შუალედი კლასიკური გატეხვაა. GET /orders/12345 ვალიდური ტოკენით მაინც ვალდებულია შეამოწმოს, რომ შეკვეთა 12345 ამ ტოკენის მომხმარებელს ეკუთვნის — მფლობელობის გამოტოვებული შემოწმების ბაგი (IDOR, უსაფრთხოების ენაზე) კოდ-რევიუზე კვლავ ყველაზე გავრცელებული სერიოზული API-სისუსტეა, და გენერირებული კოდი მას ენთუზიაზმით იმეორებს, რადგან happy-path-ვერსია იდენტურად გამოიყურება.

რატომ იმსახურებს შეცდომების პასუხები დიზაინის დროს?

იმიტომ, რომ შენი შეცდომებიც API-ა — ის, რომელსაც ღამის 3 საათზე დაძაბული ინტეგრატორი მოიხმარს და წყვეტს, ბაგი მისია თუ შენი. გადარჩენისუნარიანი შეცდომის პასუხი სამ რამეს ატარებს: მანქანურად წაკითხვად კოდს (insufficient_funds და არა უბრალოდ HTTP 400), ადამიანურად წაკითხვად შეტყობინებას, რომელიც პრობლემურ ველს ასახელებს, და correlation ID-ს, რომლითაც შენი ლოგები და მისი ბაგ-რეპორტი ერთმანეთს პოულობენ. მხოლოდ HTTP-სტატუსი ზედმეტად უხეშია — 400, რომელიც ხუთ სხვადასხვა რამეს ნიშნავს, ყოველ კონსიუმერს შენი პროზის პარსვას აიძულებს.

პროგნოზირებადობა ფიჩაა. სიურპრიზი — ხარჯი. API-ები, რომლებსაც „ინტეგრაციისთვის სასიამოვნოს” უწოდებენ, იშვიათად არიან მოხერხებულები — ისინი ყველგან ერთსა და იმავეს აკეთებენ.

კონსისტენტურობა სიმდიდრეს სჯობს. ერთი error envelope, იდენტური ფორმა ყოველ endpoint-ზე, ერთხელ დოკუმენტირებული. API-ები, რომლებსაც „ინტეგრაციისთვის სასიამოვნოს” უწოდებენ, იშვიათად აკეთებენ რამე მოხერხებულს — ისინი ყველგან ერთსა და იმავე პროგნოზირებადს აკეთებენ, ამიტომ ინტეგრატორის შეცდომების დამუშავება ერთი ფუნქციაა და არა თითო-თითო ყოველ endpoint-ზე. პროგნოზირებადობა ფიჩაა; სიურპრიზი — ხარჯი, იგივე გაკვეთილი, რომელსაც durability არქიტექტურის დონეზე ასწავლის.

რა სჭირს გვერდის ნომრებით პაგინაციას?

Offset-პაგინაცია (?page=3) კონკურენტული ჩაწერების პირობებში იტყუება: სტრიქონები, ჩამატებული ან წაშლილი მაშინ, როცა კონსიუმერი გვერდებზე მიდის, ელემენტებს ორჯერ აჩენს ან აქრობს, ღრმა offset-ები კი ბაზას სრული scan-and-discard-ით სჯიან. ის ტუტორიალებში იმიტომ ცოცხლობს, რომ ტრივიალურია და სტატიკური მონაცემების დემოებში სწორად გამოიყურება. Cursor-პაგინაცია — გაუმჭვირვალე ტოკენი მნიშვნელობით „გააგრძელე ამ სტრიქონის შემდეგ” — ჩაწერების ქვეშ კორექტული რჩება და სიღრმეზე სწრაფი, „მე-7 გვერდზე გადასვლის” დაკარგვის ფასად, რომელიც რეალური კონსიუმერების უმეტესობას არასდროს სჭირდებოდა.

გადატანადი წესი: პაგინაცია დალაგებაში პოზიციით და არა თავიდან დათვლით, ყოველთვის, როცა მონაცემები მკითხველების ქვეშ იცვლება. ეს პატარა დიზაინ-გადაწყვეტილებაა გრძელი კუდით: cursor-ების მიმაგრება უკვე გამოშვებულ offset-API-ზე ზუსტად ის გამოქვეყნებული კონტრაქტის მიგრაციაა, რომელზეც ვერსიონირების სექცია გვაფრთხილებდა.

იცვლება რამე, როცა კონსიუმერი AI-აგენტია?

პრინციპები გადარჩება; დაშვებები მკაცრდება. აგენტები API-ებს tool definitions-ის მეშვეობით მოიხმარენ, და ყველაფერი ზემოთქმული მანქანისკენ მიმართული ხდება: ბუნდოვანი შეცდომის შეტყობინება, რომელსაც ადამიანი მხრების აჩეჩვით ჩაუვლიდა, აგენტს retry-ციკლში აგზავნის, არაკონსისტენტური envelope მის პარსინგს ტეხავს, ნაკლებდოკუმენტირებული პარამეტრი კი ჰალუცინირდება. API-ების დაპროექტება, რომლებსაც აგენტები საიმედოდ გამოიყენებენ — ზუსტი schema-ები, ამომწურავი შეცდომის კოდები, პატიოსანი აღწერები — იგივე ხელობაა, რაც კარგი REST-დიზაინი, ოღონდ დაუდევრობის დაშვების გარეშე. ეს არის MCP-ის განმარტების თეზისი: ინსტრუმენტების ინტერფეისები API დიზაინის მეორე რაუნდია, ნაკლებად შემწყნარებელი კონსიუმერით.

ამიტომაც ფუნდამენტური კურსების გზა კვლავ რეალური REST-სერვისების აშენებაზე გადის — Node.js და production API-ები თავად ხელობისთვის, backend-არქიტექტურის სართულზე, სადაც წყდება, რა არის სერვისი და რა — handler, TypeScript-ით როგორც ტიპიზაციის დისციპლინით, რომელიც კონტრაქტებს იძულებითს ხდის და არა სასურველს. თითოეულ ამ უნარს ახლა მეორე მომხმარებელი ჰყავს: აგენტი, რომელიც შენს API-ს schema-ს მეშვეობით უძახებს — ზუსტად ისეთივე პირდაპირი, როგორც ტიპჩეკერი, და საგრძნობლად უფრო ძვირი, როცა დაბნეულია.

გადარჩენის ჩეკლისტი

ვერსია URL-ში პირველი დღიდან; გამოქვეყნების შემდეგ — მხოლოდ ადიტიური ცვლილებები. Deny-by-default auth; მფლობელობის შემოწმება რესურსის ყოველ წაკითხვაზე. ერთი error envelope ყველგან: მანქანური კოდი, ადამიანური შეტყობინება, correlation ID. Cursor-ები და არა offset-ები ყველგან, სადაც მონაცემები მოძრაობს. დოკუმენტაცია დაწერე ყველაზე პირდაპირი კონსიუმერისთვის, რომელიც ოდესმე გეყოლება — რადგან წელს ის უკვე გყავს. არაფერი ამათგან გლამურული არ არის. არც ხიდი, რომელიც არ ინგრევა.

გაზიარება
X LinkedIn
შემდეგი ნაბიჯი

დაამყარეთ ეს თემა კურსზე

სტრუქტურირებული გზა თეორიიდან production-კოდამდე — პროექტებითა და code review-ით.

Oleksii Anzhiiak

სტატიის ავტორი

Oleksii Anzhiiak

სოფტვეარ არქიტექტორი, უფროსი .NET ინჟინერი და თანადამფუძნებელი

ოლექსი ანჟიაკი — სოფტვეარ არქიტექტორი, უფროსი .NET ინჟინერი და ToyCRM.com-ისა და ProfectusLab-ის თანადამფუძნებელი. 15+ წლიანი გამოცდილებით, ის სპეციალიზირდება განაწილებულ სისტემებში, cloud ინფრასტრუქტურაში, მაღალი დატვირთვის backend-ში და იდენტობის პლატფორმებში. ქმნის უსაფრთხო ავტენტიფიკაციის სისტემებს, არქიტექტურულ გადაწყვეტებს და თანამედროვე საგანმანათლებლო პროგრამებს, რომლებიც სტუდენტებს კარიერულ წინსვლაში ეხმარება.

LinkedIn

რეკომენდებული საყურებელი

შერჩეული გარე ვიდეოები თემაზე. იხსნება YouTube-ზე.

~1:56:00
გაწაფული Andrej Karpathy

GPT-ის შექმნა ნულიდან

იშვიათი პრაქტიკული ახსნა GPT-ის შიდა არქიტექტურის შესახებ — თეორიიდან რეალურ კოდამდე.

~27:00
საშუალო 3Blue1Brown

Transformer-ები — LLM-ების ტექნოლოგია (Deep Learning, თავი 5)

3Blue1Brown-ის ფირმოვანი ვიზუალური ახსნა transformer-ის არქიტექტურის. საუკეთესო 30-წუთიანი შესავალი ინჟინრებისთვის — ჯერ ინტუიცია, შემდეგ მათემატიკა.

~1:00:00
დამწყები Andrej Karpathy

[1-საათიანი ლექცია] შესავალი Large Language Models-ში

კარპატის ერთსაათიანი ახსნა: როგორ მუშაობს LLM — inference, ტრენინგი, fine-tuning და ჩამოყალიბებადი LLM-OS. ერთიანი მენტალური მოდელი ინჟინრებისთვის, ვინც ახლა შემოდის ამ სფეროში.

დაგვიკავშირდით