MIT Weblab笔记 - APIs and Promises Introduction
Introduction
Client sends request to server, and server responds with result.
A server binds to a port on a computer. A computer can run multiple servers simultaneously, each server binds to a unique port.
Domain of my own computer: localhost. (http://localhost:3000)
APIs
- API (Application Programming Interface). Interface can be thought of as a contract of service between two applications. This contract defines how the two communicate with each other using requests and responses.
- Frontend makes http requests to the endpoints defined on the backend.
HTTP(S) Methods
- GET: Retrieves data from the server.
- POST: Sends data to the server, often causing a change or creation of new data.
- PUT: Replaces data on the server.
- DELETE: Deletes data on the server.
HTTP Request
- Request Target (URL) + Params: The endpoint and any parameters.
- HTTP Method: The type of action (GET, POST, etc.).
- Headers: Additional metadata for the request.
- Body: The data sent with the request (for POST and PUT).
HTTP Response
- Status Code: Indicates the result of the request.
- 2xx: Success
- 4xx: Client errors
- 5xx: Server errors
- Headers: Metadata about the response.
- Body: The data returned by the server.
Make HTTP Requests
The fetch()
function in JavaScript is used to make network requests.
1 |
|
- url: he URL to which the request is sent.
- absolute url: e.g.
http://example.com/api/data
- relative url: e.g. ‘api/data’ (relative to current page), ‘../api/data’, ‘/api/data’ (relative to root)
- absolute url: e.g.
- options: the option object including properties like method, headers, body, mode
Get Request
1 |
|
- Parameters are passed as part of the URL in the query string for get request
Post Request
1 |
|
- Parameters are included in the request body as key-value pairs. The body can be in various formats (e.g., JSON, XML, form data), but JSON is common.
body
: The actual data sent with the request.JSON.stringify(params)
converts the JavaScript object params into a JSON string.
Define API Endpoints
The following uses Express.js
When the backend receives a request to an API endpoint, it executes the corresponding route handler function to process the request, interact with the database, and send back a response.
1 |
|
- req: The req object represents the HTTP request and contains information about the request that was made by the client. It can be used to access information about the incoming request.
- req.query: Extract the query parameters (for get request) from the query string in the URL
- req.body: Data sent in the body of the request (typically with POST, PUT, or DELETE requests).
- res: The res object represents the HTTP response that an Express application sends when it receives a request.
- res.send(): The parameter can be of different types, such as a string, Buffer, JSON object, array, etc.
- res.status(404).send(‘Page not found’): First set status code and then send.
- res.sendFile(path.join(reactPath, “index.html”)): send a file back
Middleware
Middleware: Run code in between receiving a request and running endpoint code. Middlewares are called in order of definition. Register middleware by calling app.use().
1 |
|
- path (optinoal): Specifies the base path for the middleware function. If omitted, the middleware will be executed for every request to the app.
- A function to execute for the given path.
Using Middleware to route
1 |
|
1 |
|
When http://localhost:3000/api/test
request is sent to the server, the following sequence happens:
- The JSON parsing middleware
express.json()
processes the request. - The request path
/api/test
is checked against theapiRouter
, matches, and then the request is forwarded toapiRouter
. - The router checks its defined routes and finds a match for GET
/test
, and the handler for/test
is executed.
Promises
Async Handling
Get or Post returns a promise. Promises allow for asynchronous processing.
A bad example:
1 |
|
In this example, get('/api/stories')
returns a promise, but setStories(myStories) is called immediately, before the promise has resolved. As a result, the immediately returned promise: myStories, will not contain any data.
Correct way to handle this:
1 |
|
.then()
block waits for the promise to resolve. Once the data is fetched, the parseddata
is then passed tosetStories(data)
. This also returns a promise.- The
.catch()
block handles any errors. Once the promise is rejected, do stuff (call a callback function). Returns a promise. - If the fetch is accepted,
.catch()
will not be executed. If the fetch is rejected, any.then()
will not be executed.
Put Together
Get request example:
1 |
|
The following happens sequentially:
- The
get
function sends a GET request to the backend at the endpoint “/api/comment” with a query parameter parent set to props._id. - The backend’s
router.get("/comment", (req, res) => { ... })
function is triggered by the incoming GET request to “/comment”. - The backend extracts the parent parameter from the query string using
req.query.parent
. - The backend constructs and sends the
filteredComments
array back to the frontend usingres.send(filteredComments)
. - The frontend’s promise, returned by the
get
function, resolves with thefilteredComments
array received from the backend. - The
.then((comments) => { ... })
method is called withcomments
as the argument, which is thefilteredComments
array. - setComments(comments) is called, triggering a re-render of the component with the new comments.
Put request example:
1 |
|
- The parameter of post request can be extracted by
req.body.xxx
in the backend. - The backend sends back the newComment to the client.
.then()
waits for the promise to resolve. The callback function defined in.then()
takes the response as the parameter and makes changes.