HTTP Requests
By Syncfusion®, Inc. · Last updated
HTTP, REST and JSON in plain words, fetch() for GET, POST, PUT, PATCH and DELETE with headers, bodies and query strings, response.ok and status codes, loading, success, empty and error states, refetching, stale responses and AbortController, Axios instances, interceptors and cancellation, a full CRUD screen, API service modules and env-based URLs.
Talking to a Server
- Real apps keep their data on a server: menus, orders, users.
- The browser asks the server for data, and sends new data to it, over HTTP.
- Request = a message from the browser: "give me the dishes".
- Response = the server's answer: a status code and some data.
- JSON = the text format most servers use for data. It looks like JavaScript objects.
Simple lesson: the app sends HTTP requests, and the server answers with JSON.
A Real-World Example
- Meera's menu now lives on a server.
- The page must show "Loading…" first, then the dishes.
- If the server fails, it must show a friendly message, not a blank page.
- What happened: "Loading the menu…" showed first.
- About 300 ms later the dishes arrived, and the list replaced it.
- The Console below the preview shows the request:
[API] GET /dishes → 200.
Real apps call a real server over the internet. In this lab, a pretend REST API at https://api.meeraskitchen.dev answers inside the preview. It has /dishes, /orders, /staff and /reviews, and /error always fails. Add ?delay=1500 to any address to make it slower.
What You Will Learn
- What HTTP methods, REST and status codes mean.
- How to send GET, POST, PUT, PATCH and DELETE with
fetch(). - How to add headers, a body and a query string.
- Why you must check
response.ok. - How to show loading, success, empty and error states.
- How to load again and cancel old requests.
- How to use Axios, its instances and interceptors.
- How to build a full create, read, update and delete screen.
- How to keep API calls in one module and the address in
.env.
HTTP and REST in Plain Words
- REST = a common way to design a server's addresses around things, such as dishes.
- The method says what to do with the thing.
| Method | Meaning | Example |
|---|---|---|
GET | Read | GET /dishes, GET /dishes/2 |
POST | Create | POST /dishes with a new dish |
PUT | Replace all of it | PUT /dishes/2 with the full dish |
PATCH | Change part of it | PATCH /dishes/2 with { price: 95 } |
DELETE | Remove | DELETE /dishes/2 |
Status Codes
- 2xx = success.
200OK,201Created,204No content. - 4xx = the request was wrong.
400Bad request,401Not logged in,403Not allowed,404Not found. - 5xx = the server failed.
500Server error.
Animation: the browser sends POST /dishes with a JSON body to the server. The server answers 201 Created with the new dish and its id
Vue app
Server
POST /dishes 201
Request: method + address + body. Response: status code + JSON.
Every request gets a response with a status code.
Simple lesson: the method says what to do. The status code says how it went.
fetch() for Every Method
fetch(url)sends a GET and returns a Promise of the response.await res.json()reads the JSON body.- For other methods, pass options:
method,headersandbody. - Send JSON with
JSON.stringify(data)and the headerContent-Type: application/json. - Build a query string with
URLSearchParams:?veg=true.
Checking response.ok
fetchonly fails for network problems, such as no internet.- A
404or500is still a "successful" fetch. It does not throw. - So always check
res.ok(true for 2xx) orres.status. - Throw your own error when it is not ok.
Without the res.ok check, a 404 page or an error object goes straight into your list. The page then shows strange values or crashes. Check ok on every request.
Simple lesson: fetch does not throw on 404 or 500. Check res.ok yourself.
Four States of a Request
- Loading: the request is on its way. Show a spinner or "Loading…".
- Success: data arrived. Show it.
- Empty: it worked, but there is nothing. Say so clearly.
- Error: it failed. Explain it kindly and offer "Try again".
- The first box on this page shows all four.
Refetching and Stale Responses
- Data often loads again: a new filter, a new page, a "Refresh" button.
- If the user clicks fast, an old slow request can finish after a newer one.
- The page then shows old data. This is a stale response.
- Fix: cancel the old request with an
AbortControllerbefore starting a new one. - Also cancel in
onUnmounted, as you did in Lifecycle and Template Refs.
- What happened: click "Veg (slow)", then quickly "All (fast)".
- The slow veg request was cancelled, so it could not overwrite the newer list.
Simple lesson: cancel old requests with AbortController, so new data always wins.
Axios
- Axios = a popular library for HTTP requests. Install it with
npm install axios. - It reads JSON for you:
res.data. - It throws on 4xx and 5xx, so you do not forget the check.
axios.create({ baseURL, headers, timeout })makes an instance with shared settings.- Interceptors run on every request or response: add a token, log, handle errors in one place.
- Cancel with the same
AbortController:{ signal: controller.signal }.
Axios in a browser normally sends requests with XMLHttpRequest. In this lab, Axios is set to its built-in fetch adapter, so the pretend API can answer. Your code does not change.
CORS and the Dev Proxy
- CORS = a browser rule. A page from one address may only read answers from another address if that server allows it.
- If it does not, the request fails with a "blocked by CORS policy" error in the browser Console. This is the server's setting, not a bug in your Vue code.
- Fix on the server: it must send
Access-Control-Allow-Originfor your site. - During development, Vite can forward requests for you, so the browser sees one address:
// vite.config.ts
export default defineConfig({
plugins: [vue()],
server: {
proxy: { "/api": "http://localhost:8080" }, // fetch("/api/dishes") → http://localhost:8080/api/dishes
},
});
- The proxy works only in
npm run dev. In production, the server or the host must allow it.
A Full CRUD Screen
- CRUD = Create, Read, Update, Delete. Most admin screens do all four.
- Keep the HTTP calls in a service module, such as
services/dishes.ts. - Components then call
dishService.list(), not raw URLs. - Keep the server address in
.envasVITE_API_URL, read withimport.meta.env. You will learn more in Errors, Security and Deployment.
For bigger apps, wrap the service in a composable or a Pinia store, as in Composables, Directives and Plugins and State Management with Pinia. Then every page shares the same loading and error state.
Simple lesson: keep HTTP calls in a service module, and the server address in .env.
TL;DR
- HTTP = requests and responses between the app and a server.
- REST methods = GET read, POST create, PUT replace, PATCH change, DELETE remove.
- Status codes = 2xx success, 4xx bad request, 5xx server failure.
fetch(url, { method, headers, body })= sends a request.await res.json()reads JSON.res.ok= true for 2xx.fetchdoes not throw on 404 or 500.- Four states = loading, success, empty, error.
AbortController= cancels a request. Stops stale responses.- Axios =
res.data, throws on errors, instances and interceptors. - Service module +
.env= one place for API calls and the server address.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
No res.ok check | fetch throws on 404 | Check res.ok and throw | Error objects end up in your list |
Forgetting JSON.stringify | body: data works | body: JSON.stringify(data) | The server gets [object Object] |
No Content-Type header | The server guesses JSON | Send Content-Type: application/json | The server ignores the body |
| No loading or error state | Requests are instant | Show loading, empty and error | A blank or broken page |
| Not cancelling old requests | Answers arrive in order | Abort the old one | Old data replaces new data |
| URLs scattered in components | Fine for small apps | A service module and .env | Changing the server means editing every file |
Secrets in VITE_ variables | .env is private | Keep secrets on the server | Anyone can read them in the browser |
Check Yourself
Exercises
What to Remember
- GET reads, POST creates, PUT replaces, PATCH changes, DELETE removes.
fetchdoes not throw on 404 or 500. Always checkres.ok.- Show loading, success, empty and error states.
- Cancel old requests with
AbortControllerto avoid stale data. - Keep API calls in a service module, and the server address in
.env.
Next: Authentication and Real-Time Data