Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

URL anatomy: scheme, host, path, query, fragment

API and Technical Fundamentals cho BA Bài 8/60

Mở đầu — vì sao bài này quan trọng

Mỗi ngày bạn gõ địa chỉ web, click vào link, hay nhìn developer demo một API — và phía sau tất cả những hành động đó là một chuỗi ký tự tưởng chừng vô hại: cái URL. Nhưng với một Business Analyst (BA), URL không chỉ là "đường dẫn để vào trang web". Nó là bản hợp đồng giao tiếp giữa client và server. Khi bạn viết một API spec, khi bạn đọc tài liệu tích hợp của đối tác, khi bạn ngồi họp với dev để chốt endpoint cho tính năng mới — bạn đang làm việc trực tiếp với cấu trúc URL.

Tôi đã chứng kiến không ít BA bị "đứng hình" trong cuộc họp kỹ thuật chỉ vì không phân biệt được đâu là phần path cố định, đâu là query parameter tùy chọn, hay tại sao dev lại nói "cái :443 đó không cần ghi đâu chị". Những khoảnh khắc đó làm giảm uy tín của BA, và tệ hơn, dẫn đến spec mơ hồ khiến dev hiểu sai ý.

Bài này sẽ "mổ xẻ" một URL thành các thành phần riêng biệt: scheme, host, port, path, query, fragment. Khi bạn nắm chắc từng phần, bạn sẽ đọc API spec nhanh hơn, viết yêu cầu chính xác hơn, và quan trọng nhất — bạn nói cùng ngôn ngữ với đội kỹ thuật. Đây là kiến thức nền tảng mà mọi bài sau về phương thức HTTP, phân trang, lọc dữ liệu đều dựa vào.

Khái niệm cốt lõi

Hãy bắt đầu với một URL đầy đủ và "giải phẫu" từng mảnh:

https://api.example.vn:443/v1/orders/123?status=paid&limit=20#section-1
└─┬─┘   └─────┬──────┘└┬┘└────┬─────┘└────────┬─────────┘└───┬───┘
scheme      host     port    path           query        fragment

Mỗi phần có một ký tự phân tách đặc trưng, và hiểu các ký tự này giúp bạn "đọc" URL như đọc một câu văn.

Scheme (giao thức)

https:// là phần đứng đầu, cho biết giao thức dùng để giao tiếp. Phổ biến nhất là httphttps (https = http có mã hóa TLS). Ngoài ra còn có ftp://, ws:// (WebSocket), mailto:, tel:. Với API hiện đại, gần như luôn là https vì lý do bảo mật — dữ liệu được mã hóa trên đường truyền.

Dấu :// là ranh giới giữa scheme và phần còn lại. Một chi tiết nhỏ nhưng quan trọng: httpshttphai endpoint khác nhau. Gọi nhầm http khi server chỉ chấp nhận https sẽ bị redirect hoặc từ chối thẳng.

Host (tên miền hoặc địa chỉ máy chủ)

api.example.vnhost — địa chỉ của máy chủ bạn muốn nói chuyện. Nó có thể là:

  • Một tên miền: api.example.vn, payment.vnpay.vn
  • Một subdomain riêng cho API: chú ý phần api. ở đầu — nhiều công ty tách riêng api.domain.com cho hệ thống API, khác với www.domain.com của website
  • Một địa chỉ IP: 192.168.1.10 (thường gặp trong môi trường nội bộ hoặc test)
  • localhost hoặc 127.0.0.1 khi dev chạy trên máy của họ
Host quyết định request của bạn đi đến đúng máy chủ nào. Một lỗi cực kỳ phổ biến là nhầm host của môi trường production với staging (ví dụ api.example.vn vs staging-api.example.vn).

Port (cổng)

:443port — giống như số phòng trong một tòa nhà. Host đưa bạn đến đúng tòa nhà, port đưa bạn đến đúng cánh cửa dịch vụ.

Điều quan trọng: mỗi scheme có port mặc định. http mặc định là 80, https mặc định là 443. Vì https://api.example.vn:443 dùng đúng port mặc định, nên trong thực tế người ta bỏ luôn :443 cho gọn — và URL vẫn hoạt động y hệt. Đây chính là lý do bạn hiếm khi thấy port trong URL hằng ngày. Port chỉ xuất hiện rõ khi dịch vụ chạy ở cổng "lạ", ví dụ http://localhost:3000 (server dev), :8080, :5432 (database PostgreSQL).

Path (đường dẫn)

/v1/orders/123path — chỉ ra tài nguyên cụ thể mà bạn muốn truy cập trên máy chủ đó. Đây là phần BA cần quan tâm nhất khi thiết kế API, vì path thể hiện cấu trúc tài nguyên.

Đọc kỹ ví dụ này:

  • /v1 — phiên bản API (version)
  • /orders — loại tài nguyên: đơn hàng (số nhiều, theo quy ước REST)
  • /123 — định danh của một đơn hàng cụ thể (ID = 123)
Path được phân tách bằng dấu /, đọc từ trái sang phải như một cây thư mục, từ chung đến riêng. Path là phần bắt buộc và cố định về mặt cấu trúc — nó định danh "cái gì", chứ không phải "lọc thế nào".

Query string (chuỗi truy vấn)

?status=paid&limit=20query string — bắt đầu bằng dấu ?, chứa các cặp key=value nối với nhau bằng dấu &.

Trong ví dụ:

  • status=paid — lọc đơn hàng có trạng thái "đã thanh toán"
  • limit=20 — giới hạn trả về tối đa 20 kết quả
Query thường mang tính tùy chọn và dùng để: lọc (filter), sắp xếp (sort), phân trang (pagination), tìm kiếm (search). Đặc điểm quan trọng: bỏ query đi thì request vẫn hợp lệ, chỉ là trả về dữ liệu mặc định (thường là tất cả, không lọc). Đây là khác biệt cốt lõi giữa path và query mà tôi sẽ nhấn mạnh ở phần lỗi thường gặp.

Fragment (mảnh neo)

#section-1fragment — bắt đầu bằng dấu #. Điểm đặc biệt nhất của fragment: nó chỉ được xử lý ở phía trình duyệt (client), KHÔNG được gửi lên server. Server hoàn toàn không nhìn thấy phần sau dấu #.

Fragment dùng để nhảy đến một vị trí cụ thể trong trang (ví dụ một heading có id="section-1"), hoặc trong các Single Page Application để quản lý route phía client. Với API thuần (REST), fragment gần như không bao giờ xuất hiện. Nhưng BA cần biết nó tồn tại, vì đôi khi bạn sẽ gặp nó trong URL callback của OAuth (ví dụ access token đặt sau # để không bị gửi lên server log).

Một số chi tiết bổ sung BA hay gặp

URL encoding: các ký tự đặc biệt trong query phải được "mã hóa". Dấu cách thành %20 hoặc +, dấu & trong giá trị thành %26. Ví dụ tìm kiếm "áo dài" có thể thành ?q=%C3%A1o%20d%C3%A0i. Khi bạn thấy chuỗi %XX lạ mắt, đó chính là URL encoding.

Userinfo: đôi khi (hiếm) bạn thấy https://user:pass@host — phần user:pass@ trước host là thông tin xác thực nhúng trong URL. Cách này không an toàn và ít dùng, nhưng nên nhận diện được.

Tình huống thực tế

Tình huống 1: Tích hợp cổng thanh toán cho sàn TMĐT

Một công ty thương mại điện tử ở TP.HCM tích hợp cổng thanh toán nội địa. Đối tác gửi tài liệu với endpoint:

https://sandbox.payment.vn/v2/transactions/TXN20260627001?merchant_id=SHOP88&signature=a1b2c3

BA tên Lan đọc URL này và phân tích đúng từng phần để đưa vào spec:

  • Scheme https — bắt buộc, đối tác từ chối mọi request http
  • Host sandbox.payment.vnmôi trường test, khi go-live phải đổi thành payment.vn (bỏ sandbox.)
  • Path /v2/transactions/TXN20260627001 — tra cứu một giao dịch cụ thể theo mã TXN20260627001
  • Query merchant_idsignature — định danh người bán và chữ ký bảo mật
Diễn giải: Lan ghi rõ trong spec rằng "khi triển khai production, dev phải thay host từ sandbox.payment.vn sang payment.vn và đảm bảo dùng đúng merchant_id của môi trường thật". Nhờ tách bạch host theo môi trường, đội dev tránh được lỗi kinh điển: deploy lên production nhưng vẫn trỏ vào sandbox, khiến tiền không được trừ thật.

Bài học: Host gắn chặt với khái niệm môi trường (sandbox/staging/production). BA giỏi luôn ghi rõ host cho từng môi trường trong spec, không bao giờ chỉ ghi một URL chung chung.

Tình huống 2: Phân biệt path và query khi viết yêu cầu API danh sách

Một startup giao đồ ăn ở Hà Nội cần API "lấy danh sách đơn hàng của một nhà hàng, lọc theo trạng thái". BA viết yêu cầu đầu tiên như sau:

GET /orders/restaurant/45/status/pending

Dev phản hồi: "Cái này không ổn về mặt thiết kế chị ạ". Sau khi cùng review, họ chốt lại:

GET /restaurants/45/orders?status=pending&page=1&size=20

Diễn giải: restaurants/45 nằm trong path vì nó định danh tài nguyên cha (nhà hàng có ID 45 — đây là dữ liệu cố định, bắt buộc để xác định "đơn hàng của ai"). Còn status=pending thuộc query vì nó là điều kiện lọc tùy chọn — bỏ đi thì trả về tất cả đơn của nhà hàng đó. Tương tự, pagesize là tham số phân trang nên đặt ở query.

Bài học: Quy tắc vàng — cái gì định danh tài nguyên thì vào path; cái gì để lọc, sắp xếp, phân trang thì vào query. Nhầm lẫn hai phần này tạo ra API "xấu", khó mở rộng và khó cache.

Tình huống 3: Bug do quên port trong môi trường nội bộ

Một ngân hàng tại Việt Nam có hệ thống core chạy nội bộ. Dev cung cấp cho đội tích hợp địa chỉ:

http://10.0.5.22:8443/internal-api/v1/accounts/lookup?cif=0123456789

BA mới vào nghề copy URL nhưng vô tình bỏ mất :8443, gửi cho đối tác là http://10.0.5.22/internal-api/.... Kết quả: mọi request đều báo "connection refused".

Diễn giải: Vì scheme là http nhưng port mặc định 80 lại không có dịch vụ nào lắng nghe — dịch vụ thật chạy ở port 8443. Khác với URL public dùng port mặc định (có thể bỏ), URL nội bộ thường dùng port "lạ" và bắt buộc phải ghi đầy đủ.

Bài học: Khi gặp host là địa chỉ IP nội bộ hoặc localhost, hãy đặc biệt cảnh giác với port. Đừng bao giờ tự ý lược bỏ port mà không hỏi dev.

Hướng dẫn từng bước

Khi nhận hoặc viết một URL/endpoint, hãy áp dụng quy trình "đọc URL" sau:

  • Tìm scheme — Nhìn phần trước ://. Là https hay http? Ghi nhớ ràng buộc bảo mật (nhiều API chỉ chấp nhận https).
  • Xác định host — Phần ngay sau :// đến trước dấu / hoặc : đầu tiên. Tự hỏi: đây là production, staging hay sandbox? Có phải subdomain api. riêng không?
  • Kiểm tra port — Có dấu : theo sau là số không? Nếu có, ghi lại. Nếu không, ngầm hiểu là port mặc định (80 cho http, 443 cho https). Với host nội bộ, luôn xác nhận port với dev.
  • Phân tích path — Tách phần sau host theo từng dấu /. Xác định: đâu là version (/v1, /v2), đâu là loại tài nguyên (/orders), đâu là ID cụ thể (/123). Đọc từ chung đến riêng.
  • Đọc query string — Phần sau dấu ?. Tách từng cặp key=value ngăn bởi &. Phân loại mỗi tham số: lọc, sắp xếp, phân trang hay tìm kiếm? Đánh dấu cái nào bắt buộc, cái nào tùy chọn.
  • Để ý fragment — Có dấu # không? Nếu có, nhớ rằng phần này không gửi lên server. Với API thuần thì thường bỏ qua.
  • Soát URL encoding — Có chuỗi %XX không? Giải mã để hiểu giá trị thật, đặc biệt với tham số tìm kiếm tiếng Việt có dấu.
Khi viết spec, hãy lập bảng mô tả từng tham số path và query: tên, vị trí (path/query), bắt buộc hay không, kiểu dữ liệu, ý nghĩa, ví dụ. Bảng này giúp dev và QA hiểu chính xác, tránh hỏi đi hỏi lại.

Lỗi thường gặp & mẹo

Lỗi 1 — Nhầm lẫn path và query. Đây là lỗi số một. Hãy nhớ: path định danh "cái gì" (bắt buộc), query mô tả "lọc/sắp xếp thế nào" (tùy chọn). /orders/123 khác hoàn toàn /orders?id=123 về mặt ngữ nghĩa REST.

Lỗi 2 — Quên version trong path. Nhiều BA viết /orders mà quên /v1. Version giúp API tiến hóa mà không phá vỡ tích hợp cũ. Luôn hỏi dev: "API này có version trong path không?".

Lỗi 3 — Bỏ sót hoặc thêm thừa port. Với URL public dùng port mặc định, đừng cố ghi :443 cho rối. Với URL nội bộ port lạ, đừng bao giờ bỏ port.

Lỗi 4 — Không phân biệt host theo môi trường. Spec chỉ có một URL mà không nói rõ sandbox/staging/production là nguồn gốc của vô số sự cố go-live.

Lỗi 5 — Quên URL encoding. Đặt giá trị có dấu cách, ký tự đặc biệt hay tiếng Việt có dấu vào query mà không mã hóa sẽ làm hỏng request.

Mẹo 1: Phân biệt chữ hoa/thường — host không phân biệt hoa thường (API.Example.VN = api.example.vn), nhưng path thường có phân biệt trên nhiều server. Đừng tự ý đổi hoa thường trong path.

Mẹo 2: Dấu / cuối path (trailing slash) đôi khi gây khác biệt — /orders/orders/ có thể được server xử lý khác nhau. Khi nghi ngờ, hãy hỏi rõ.

Mẹo 3: Khi đọc URL dài, hãy copy vào một editor rồi xuống dòng tại mỗi dấu ?, &, / để nhìn cấu trúc rõ hơn.

Bài tập thực hành

Bài 1 — Giải phẫu URL. Cho URL sau, hãy chỉ ra scheme, host, port, path, query, fragment:

https://api.shopee.vn:443/v3/products/88521/reviews?rating=5&sort=newest&page=2#top

Với mỗi tham số trong query, ghi rõ nó dùng để làm gì (lọc/sắp xếp/phân trang).

Bài 2 — Sửa thiết kế. Một BA viết endpoint lấy danh sách giao dịch của một ví điện tử, lọc theo loại "nạp tiền", phân trang:

GET /transactions/wallet/W789/type/topup/page/3

Hãy viết lại endpoint cho đúng quy ước REST (gợi ý: cái gì định danh tài nguyên thì vào path, cái gì lọc/phân trang thì vào query).

Bài 3 — Phân loại môi trường. Bạn nhận được hai URL từ đối tác:

https://api-uat.partner.com/v1/checkout
https://api.partner.com/v1/checkout
URL nào là môi trường test, URL nào là production? Viết một dòng ghi chú trong spec để dev không nhầm.

Bài 4 — URL encoding. Người dùng tìm kiếm sản phẩm "bút bi & giấy A4". Hãy viết query string đúng cho tham số tìm kiếm q, với các ký tự đặc biệt được mã hóa hợp lý.

Gợi ý đáp án Bài 2: GET /wallets/W789/transactions?type=topup&page=3&size=20.

Tóm tắt

URL không phải chỉ là "địa chỉ web" — với BA, nó là cấu trúc giao tiếp cốt lõi của mọi API. Một URL đầy đủ gồm sáu phần: scheme (giao thức, thường là https), host (máy chủ, gắn với môi trường sandbox/staging/production), port (cổng, có thể bỏ nếu là mặc định 80/443, nhưng bắt buộc với host nội bộ port lạ), path (đường dẫn định danh tài nguyên — cái gì), query (chuỗi truy vấn để lọc, sắp xếp, phân trang — tùy chọn), và fragment (mảnh neo, chỉ xử lý ở client, không gửi lên server).

Quy tắc vàng cần khắc cốt ghi tâm: cái gì định danh tài nguyên thì vào path, cái gì lọc/sắp xếp/phân trang thì vào query. Nắm chắc điều này, bạn sẽ đọc API spec trôi chảy, viết yêu cầu chính xác, phân biệt rõ môi trường, và tránh những lỗi go-live đắt giá. Đây là nền tảng để bạn bước tiếp vào các bài về phương thức HTTP, status code, header và phân trang ở những phần sau của khóa học.