Connect a frontend to Conduit
Point a Conduit frontend at the hosted demo API or a compatible local backend and handle its responses.
Connect your frontend to a Conduit API, authenticate protected requests, and verify a complete request against the hosted demo or a local compatible backend. This guide is for frontend developers who need a working API boundary before building screens.
Before you begin
You need a frontend application that can make HTTP requests, a browser origin for that application, and either the hosted API or a local backend that implements the shared Conduit contract. The public base URL is https://api.realworld.show/api; a local backend supplies its own base URL. The hosted service is intended for RealWorld frontend usage and does not require an API key.
Connect the frontend
Set one configuration value for the API root, without a trailing resource path.
const API_BASE_URL = "https://api.realworld.show/api";
// For a compatible local backend, use its address instead, for example:
// const API_BASE_URL = "http://localhost:3000/api";The observable result is a request URL such as https://api.realworld.show/api/articles, not a duplicated /api/api path.
Send JSON with the Content-Type header and add the Authorization header only when your application has a token.
async function request(path, { token, ...options } = {}) {
const headers = {
"Content-Type": "application/json",
...(token ? { Authorization: `Token ${token}` } : {}),
...options.headers,
};
const response = await fetch(`${API_BASE_URL}${path}`, { ...options, headers });
const payload = await response.json();
if (!response.ok) throw new Error(JSON.stringify(payload.errors ?? payload));
return payload;
}The helper returns the decoded response envelope for a successful status and raises an error containing the API's errors object for an unsuccessful status.
Call POST /users or POST /users/login with the required user object, then retain the returned user.token for the session.
const { user } = await request("/users/login", {
method: "POST",
body: JSON.stringify({
user: { email: "reader@example.com", password: "example-password" },
}),
});The successful response is a user envelope containing email, username, token, bio, and image.
Pass the token using the Token scheme when you call a protected operation.
const { user: currentUser } = await request("/user", { token: user.token });The request includes Authorization: Token <jwt>, and a successful response contains the current user in user.
Read the named top-level property instead of treating the response body as the resource itself.
const { articles, articlesCount } = await request("/articles?limit=20&offset=0");
console.log(`Rendering ${articles.length} of ${articlesCount} matching articles`);The frontend now has both the current page and the total matching count. Use response envelopes and resource models for the complete field shapes, pagination for list navigation, and errors for structured failures.
Verify the connection
GET /user. Confirm that the first result is an articles envelope and the second is a user envelope. A protected request without the token should produce an authentication error rather than an application crash.Troubleshooting
If the browser reports a CORS failure before your request reaches the API, configure the backend's OPTIONS response and allowed headers using CORS guidance. If the hosted API returns content you did not create, check whether the request is logged out; the public service intentionally limits visibility. If a response is an error status, preserve and display the structured errors values instead of assuming every failure has a message field.
Next step
For a local frontend and backend running on different origins, configure CORS for separate frontend and backend origins. Then validate the UI against the shared frontend test surface.