### FetchRequest Class - JavaScript Examples Source: https://context7.com/rails/request.js/llms.txt Demonstrates the usage of the FetchRequest class for making various HTTP requests in JavaScript. Includes examples for POST with JSON, GET with query parameters, file uploads with FormData, and cancelable requests using AbortController. ```javascript import { FetchRequest } from '@rails/request.js' // Basic POST request with JSON body async function createUser() { const request = new FetchRequest('post', '/users', { body: JSON.stringify({ user: { name: 'John Doe', email: 'john@example.com' } }), contentType: 'application/json' }) const response = await request.perform() if (response.ok) { const data = await response.json console.log('User created:', data) return data } else { console.error('Failed with status:', response.statusCode) throw new Error('User creation failed') } } // Request with query parameters and custom headers async function searchUsers() { const request = new FetchRequest('get', '/users', { query: { search: 'John', page: 1, per_page: 20 }, headers: { 'X-Custom-Header': 'custom-value' }, responseKind: 'json' }) const response = await request.perform() const users = await response.json return users } // Upload file with FormData async function uploadAvatar(file) { const formData = new FormData() formData.append('avatar', file) formData.append('user_id', '123') const request = new FetchRequest('post', '/avatars', { body: formData // Content-Type is automatically set for FormData }) const response = await request.perform() return response.ok } // Using signal for request cancellation async function cancelableRequest() { const controller = new AbortController() const request = new FetchRequest('get', '/long-running-task', { signal: controller.signal }) // Cancel after 5 seconds setTimeout(() => controller.abort(), 5000) try { const response = await request.perform() return await response.json } catch (error) { console.log('Request cancelled or failed:', error) } } ``` -------------------------------- ### Perform POST Request and Handle Response (JavaScript) Source: https://github.com/rails/request.js/blob/main/README.md This example shows how to instantiate a FetchRequest for a POST request, send it, and await the response. It highlights a known issue with Turbolinks where the `redirected` property will always be false. ```javascript const request = new FetchRequest('post', 'localhost:3000/my_endpoint', { body: JSON.stringify({ name: 'Request.JS' }) }) const response = await request.perform() response.redirected // => will always be false. ``` -------------------------------- ### Install Rails Request.JS with npm or yarn Source: https://github.com/rails/request.js/blob/main/README.md Instructions for installing the @rails/request.js package using npm or yarn for use with Webpacker or Esbuild. ```shell npm i @rails/request.js ``` ```shell yarn add @rails/request.js ``` -------------------------------- ### Request Options Configuration in JavaScript Source: https://github.com/rails/request.js/blob/main/README.md Illustrates how to pass various options to the request methods, including body, contentType, headers, credentials, query parameters, responseKind, and keepalive. This example focuses on the structure of passing these options. ```javascript post("/my_endpoint", { body: {}, contentType: "application/json", headers: {}, query: {}, responseKind: "html" }) ``` -------------------------------- ### Shorthand HTTP Verb Methods in JavaScript Source: https://github.com/rails/request.js/blob/main/README.md Shows how to use the shorthand functions (get, post, put, patch, destroy) provided by @rails/request.js for making HTTP requests. This example illustrates a POST request and accessing the JSON response body. ```javascript import { get, post, put, patch, destroy } from '@rails/request.js' ... async myMethod () { const response = await post('localhost:3000/my_endpoint', { body: JSON.stringify({ name: 'Request.JS' }) }) if (response.ok) { const body = await response.json ... } } ``` -------------------------------- ### Shorthand HTTP Methods Source: https://context7.com/rails/request.js/llms.txt Provides convenience functions for common HTTP verbs (get, post, put, patch, destroy) with a more concise syntax than directly using the Fetch API. ```APIDOC ## GET /api/users ### Description Fetches a list of users, optionally filtering by active status. ### Method GET ### Endpoint `/api/users` ### Query Parameters - **active** (boolean) - Optional - Filter for active users. ### Request Example ```javascript import { get } from '@rails/request.js'; async function fetchUsers() { const response = await get('/api/users', { query: { active: true }, responseKind: 'json' }); if (response.ok) { return await response.json; } } ``` ### Response #### Success Response (200) - **data** (array) - An array of user objects. #### Response Example ```json { "users": [ { "id": 1, "name": "Alice" }, { "id": 2, "name": "Bob" } ] } ``` ``` ```APIDOC ## POST /posts ### Description Creates a new blog post with the provided title, content, and publication status. ### Method POST ### Endpoint `/posts` ### Request Body - **title** (string) - Required - The title of the post. - **content** (string) - Required - The main content of the post. - **published** (boolean) - Optional - Whether the post should be published immediately. ### Request Example ```javascript import { post } from '@rails/request.js'; async function createPost() { const response = await post('/posts', { body: { title: 'New Post', content: 'Post content here', published: true }, responseKind: 'json' }); if (response.ok) { const newPost = await response.json; console.log('Created post ID:', newPost.id); return newPost; } } ``` ### Response #### Success Response (201) - **id** (integer) - The unique identifier of the newly created post. - **title** (string) - The title of the post. - **content** (string) - The content of the post. - **published** (boolean) - The publication status. #### Response Example ```json { "id": 101, "title": "New Post", "content": "Post content here", "published": true } ``` ``` ```APIDOC ## PUT /users/:userId ### Description Updates an existing user's information with the provided data. ### Method PUT ### Endpoint `/users/:userId` ### Path Parameters - **userId** (integer) - Required - The ID of the user to update. ### Request Body - **updates** (object) - Required - An object containing the fields to update. ### Request Example ```javascript import { put } from '@rails/request.js'; async function updateUser(userId, updates) { const response = await put(`/users/${userId}`, { body: updates, contentType: 'application/json' }); return response.ok; } ``` ### Response #### Success Response (200) - **success** (boolean) - Indicates if the update was successful. #### Response Example ```json { "success": true } ``` ``` ```APIDOC ## PATCH /users/:userId/toggle_status ### Description Partially updates a user's status, typically to toggle between active and inactive. ### Method PATCH ### Endpoint `/users/:userId/toggle_status` ### Path Parameters - **userId** (integer) - Required - The ID of the user whose status to toggle. ### Request Body - **active** (boolean) - Required - The desired status (true for active, false for inactive). ### Request Example ```javascript import { patch } from '@rails/request.js'; async function toggleUserStatus(userId) { const response = await patch(`/users/${userId}/toggle_status`, { body: { active: true }, responseKind: 'json' }); return await response.json; } ``` ### Response #### Success Response (200) - **status** (string) - The new status of the user (e.g., 'active', 'inactive'). #### Response Example ```json { "status": "active" } ``` ``` ```APIDOC ## DELETE /posts/:postId ### Description Deletes a specific blog post. ### Method DELETE ### Endpoint `/posts/:postId` ### Path Parameters - **postId** (integer) - Required - The ID of the post to delete. ### Request Example ```javascript import { destroy } from '@rails/request.js'; async function deletePost(postId) { const response = await destroy(`/posts/${postId}`, { responseKind: 'json' }); if (response.ok) { console.log('Post deleted successfully'); return true; } return false; } ``` ### Response #### Success Response (204) - No content is returned upon successful deletion. #### Response Example (No body content) ``` ```APIDOC ## General Error Handling ### Description Demonstrates a robust pattern for handling various response statuses, including validation errors and network issues. ### Method POST (example) ### Endpoint `/api/endpoint` ### Request Body - **data** (any) - Required - The data to send in the request. ### Request Example ```javascript import { post } from '@rails/request.js'; async function robustRequest() { try { const response = await post('/api/endpoint', { body: { data: 'value' }, responseKind: 'json' }); if (response.ok) { return await response.json; } else if (response.statusCode === 422) { const errors = await response.json; console.error('Validation errors:', errors); return { errors }; } else { throw new Error(`Request failed: ${response.statusCode}`); } } catch (error) { console.error('Network error:', error); throw error; } } ``` ### Response #### Success Response (200) - **data** (any) - The successful response data. #### Error Response (422) - **errors** (object) - An object containing validation errors. #### Network Error - Throws an error object. #### Response Example (Success) ```json { "message": "Operation successful" } ``` #### Response Example (Validation Error) ```json { "field_name": [ "Error message 1", "Error message 2" ] } ``` ``` -------------------------------- ### Implement Progress Bar with Request Hooks (JavaScript) Source: https://github.com/rails/request.js/blob/main/README.md This snippet demonstrates how to wrap a FetchRequest Promise with custom logic to display a progress bar before a request starts and hide it upon completion. It requires @rails/request.js and @hotwired/turbo. ```javascript import { FetchRequest } from "@rails/request.js" import { navigator } from "@hotwired/turbo" function showProgressBar() { navigator.delegate.adapter.progressBar.setValue(0) navigator.delegate.adapter.progressBar.show() } function hideProgressBar() { navigator.delegate.adapter.progressBar.setValue(1) navigator.delegate.adapter.progressBar.hide() } export function withProgress(request) { showProgressBar() return request.then((response) => { hideProgressBar() return response }) } export function get(url, options) { const request = new FetchRequest("get", url, options) return withProgress(request.perform()) } ``` -------------------------------- ### Shorthand HTTP Methods (JavaScript) Source: https://context7.com/rails/request.js/llms.txt Provides convenient functions like get, post, put, patch, and destroy for making HTTP requests with a concise syntax. These functions handle common configurations and response types, simplifying request creation compared to direct Fetch API instantiation. They support options for query parameters, request bodies, content types, and response kinds. ```javascript import { get, post, put, patch, destroy } from '@rails/request.js' // GET request returning JSON async function fetchUsers() { const response = await get('/api/users', { query: { active: true }, responseKind: 'json' }) if (response.ok) { return await response.json } } // POST request with automatic JSON stringification async function createPost() { const response = await post('/posts', { body: { title: 'New Post', content: 'Post content here', published: true }, responseKind: 'json' }) if (response.ok) { const newPost = await response.json console.log('Created post ID:', newPost.id) return newPost } else if (response.unauthenticated) { console.error('Authentication required') // User will be redirected to authenticationURL automatically } } // PUT request to update resource async function updateUser(userId, updates) { const response = await put(`/users/${userId}`, { body: updates, contentType: 'application/json' }) return response.ok } // PATCH request for partial updates async function toggleUserStatus(userId) { const response = await patch(`/users/${userId}/toggle_status`, { body: { active: true }, responseKind: 'json' }) return await response.json } // DELETE request (using destroy to avoid reserved keyword) async function deletePost(postId) { const response = await destroy(`/posts/${postId}`, { responseKind: 'json' }) if (response.ok) { console.log('Post deleted successfully') return true } return false } // Error handling pattern async function robustRequest() { try { const response = await post('/api/endpoint', { body: { data: 'value' }, responseKind: 'json' }) if (response.ok) { return await response.json } else if (response.statusCode === 422) { const errors = await response.json console.error('Validation errors:', errors) return { errors } } else { throw new Error(`Request failed: ${response.statusCode}`) } } catch (error) { console.error('Network error:', error) throw error } } ``` -------------------------------- ### Implement Request Progress Bars with JavaScript Source: https://context7.com/rails/request.js/llms.txt This snippet demonstrates how to wrap HTTP requests with progress bar indicators using pure JavaScript. It utilizes `@rails/request.js` and `@hotwired/turbo` to show and hide a progress bar during request execution. Dependencies include `FetchRequest` from `@rails/request.js` and `navigator` from `@hotwired/turbo`. It provides functions for `get` and `post` requests that automatically manage the progress bar. ```javascript import { FetchRequest } from "@rails/request.js" import { navigator } from "@hotwired/turbo" // Progress bar helper functions function showProgressBar() { const progressBar = navigator.delegate.adapter.progressBar progressBar.setValue(0) progressBar.show() } function hideProgressBar() { const progressBar = navigator.delegate.adapter.progressBar progressBar.setValue(1) progressBar.hide() } // Wrap requests with progress indication export function withProgress(requestPromise) { showProgressBar() return requestPromise .then((response) => { hideProgressBar() return response }) .catch((error) => { hideProgressBar() throw error }) } // Custom HTTP methods with progress bars export function get(url, options) { const request = new FetchRequest("get", url, options) return withProgress(request.perform()) } export function post(url, options) { const request = new FetchRequest("post", url, options) return withProgress(request.perform()) } // Usage in application import { get, post } from './request-with-progress' async function loadData() { // Progress bar shown automatically const response = await get('/api/large-dataset', { responseKind: 'json' }) // Progress bar hidden after response return await response.json } ``` -------------------------------- ### Register Bearer Token Authentication Interceptor Source: https://context7.com/rails/request.js/llms.txt Registers an interceptor to automatically add a Bearer token to outgoing requests. It fetches the token from secure storage and adds it to the 'Authorization' header. Subsequent requests made with 'get' or 'post' from '@rails/request.js' will include this token. ```javascript import { RequestInterceptor, get, post } from '@rails/request.js' // Register interceptor for Bearer token authentication RequestInterceptor.register(async (request) => { // Fetch token from secure storage const token = await getAuthToken() if (token) { request.addHeader('Authorization', `Bearer ${token}`) } }) // All subsequent requests will include the Authorization header async function authenticatedRequest() { // Token is automatically added by interceptor const response = await get('/api/protected-resource', { responseKind: 'json' }) return await response.json() } ``` -------------------------------- ### Basic FetchRequest Usage in JavaScript Source: https://github.com/rails/request.js/blob/main/README.md Demonstrates how to import and use the FetchRequest class to send a POST request to a Rails endpoint. It shows how to instantiate FetchRequest with method, URL, and options, perform the request, and handle the response. ```javascript import { FetchRequest } from '@rails/request.js' .... async myMethod () { const request = new FetchRequest('post', 'localhost:3000/my_endpoint', { body: JSON.stringify({ name: 'Request.JS' }) }) const response = await request.perform() if (response.ok) { const body = await response.text // Do whatever do you want with the response body // You also are able to call `response.html` or `response.json`, be aware that if you call `response.json` and the response contentType isn't `application/json` there will be raised an error. } } ``` -------------------------------- ### Setting up Turbo Integration in JavaScript Source: https://github.com/rails/request.js/blob/main/README.md Provides the necessary JavaScript code to integrate Rails Request.JS with Turbo. It shows how to import and assign the Turbo object to the window, enabling automatic processing of Turbo Stream responses. ```javascript import { Turbo } from "@hotwired/turbo-rails" window.Turbo = Turbo ``` -------------------------------- ### Turbo Stream Integration Source: https://context7.com/rails/request.js/llms.txt This section explains how to integrate with Turbo Streams for real-time page updates, including setting up Turbo, making requests with `responseKind: 'turbo-stream'`, and handling different response scenarios. ```APIDOC ## POST /posts ### Description Creates a new post and expects a Turbo Stream response for updating the UI. ### Method POST ### Endpoint /posts ### Parameters #### Request Body - **post** (object) - Required - Contains the title and content of the new post. ### Request Example ```json { "post": { "title": "New Post", "content": "Content here" } } ``` ### Response #### Success Response (200) - **turbo-stream** - The response will be a Turbo Stream that automatically updates the page. #### Response Example ```html ``` ``` ```APIDOC ## POST /users ### Description Submits form data to create a user. Handles both successful creation and validation errors via Turbo Streams. ### Method POST ### Endpoint /users ### Parameters #### Request Body - **formData** (FormData) - Required - The form data containing user details. ### Response #### Success Response (200) - **turbo-stream** - Indicates successful user creation, likely appending the user to a list. #### Error Response (422) - **turbo-stream** - Indicates validation errors, likely updating the form with error messages. #### Response Example (Success) ```html ``` #### Response Example (Error) ```html ``` ``` ```APIDOC ## GET /notifications/poll ### Description Polls the server for notifications and returns updates via Turbo Streams. ### Method GET ### Endpoint /notifications/poll ### Response #### Success Response (200) - **turbo-stream** - Contains Turbo Stream actions to update notifications on the page. #### Response Example ```html ``` ``` -------------------------------- ### Request Options Configuration Source: https://context7.com/rails/request.js/llms.txt This section details the comprehensive configuration options available for all request methods, including body, headers, query parameters, response kind, and more. ```APIDOC ## POST /api/complex-endpoint ### Description Demonstrates a request with all available configuration options. ### Method POST ### Endpoint /api/complex-endpoint ### Parameters #### Request Body - **user** (object) - Required - User details including name and age. - **metadata** (object) - Required - Additional metadata like source. #### Query Parameters - **include** (string) - Optional - Comma-separated list of related data to include (e.g., 'profile,settings'). - **format** (string) - Optional - Specifies the desired response format (e.g., 'detailed'). #### Headers - **X-Client-Version** (string) - Optional - The client version of the application. - **X-Request-ID** (string) - Optional - A unique identifier for the request. ### Request Example ```json { "user": { "name": "Alice", "age": 30 }, "metadata": { "source": "web" } } ``` ### Response #### Success Response (200) - **json** (object) - The JSON response from the server. #### Response Example ```json { "message": "Success" } ``` ``` ```APIDOC ## POST /photos/bulk-upload ### Description Handles uploading multiple files using FormData, along with album information and privacy settings. ### Method POST ### Endpoint /photos/bulk-upload ### Parameters #### Request Body - **files[]** (file) - Required - An array of files to upload. - **album_name** (string) - Required - The name of the album for the uploaded photos. - **privacy** (string) - Required - The privacy setting for the photos (e.g., 'private'). #### Query Parameters - **redirect_to** (string) - Optional - URL to redirect to after upload completion. ### Request Example ```json // FormData object populated with files and metadata ``` ### Response #### Success Response (200) - **ok** (boolean) - True if the upload was successful, false otherwise. #### Response Example ```json true ``` ``` ```APIDOC ## GET /posts/search ### Description Searches for posts based on provided tags and sorting preferences. ### Method GET ### Endpoint /posts/search ### Parameters #### Query Parameters - **tags[]** (string) - Required - Tags to filter posts by. Can be specified multiple times for multiple tags. - **sort** (string) - Optional - The field to sort the results by (e.g., 'recent'). ### Request Example ```json { "tags": ["javascript", "rails"], "sort": "recent" } ``` ### Response #### Success Response (200) - **json** (object) - The JSON response containing the search results. #### Response Example ```json { "posts": [ { "id": 1, "title": "Example Post" } ] } ``` ``` ```APIDOC ## GET https://api.example.com/data ### Description Fetches data from a cross-origin API endpoint, requiring specific credentials and API key. ### Method GET ### Endpoint https://api.example.com/data ### Parameters #### Headers - **X-API-Key** (string) - Required - Your API key for accessing the external service. #### Query Parameters - None specified in example. ### Request Example ```json { "X-API-Key": "your-api-key" } ``` ### Response #### Success Response (200) - **json** (object) - The JSON response containing the requested data. #### Response Example ```json { "data": "sample data" } ``` ``` -------------------------------- ### Configure Request Options with @rails/request.js Source: https://context7.com/rails/request.js/llms.txt Demonstrates how to configure various options for HTTP requests, such as request bodies, content types, headers, query parameters, response kinds, credentials, and more. Supports FormData for file uploads and URLSearchParams for query strings. ```javascript import { post, get } from '@rails/request.js' // All available options in a single request async function fullOptionsExample() { const response = await post('/api/complex-endpoint', { // Request body (auto-stringified if contentType is JSON) body: { user: { name: 'Alice', age: 30 }, metadata: { source: 'web' } }, // Content-Type header (auto-detected if omitted) contentType: 'application/json', // Additional custom headers headers: { 'X-Client-Version': '1.2.3', 'X-Request-ID': crypto.randomUUID() }, // Query parameters (merged with URL params) query: { include: 'profile,settings', format: 'detailed' }, // Expected response format responseKind: 'json', // 'html' | 'json' | 'turbo-stream' | 'script' // Credentials policy credentials: 'same-origin', // 'include' | 'omit' | 'same-origin' // Abort signal for cancellation signal: new AbortController().signal, // Redirect handling redirect: 'follow', // 'error' | 'manual' | 'follow' // Keep connection alive for subsequent requests keepalive: true }) return await response.json() } // FormData with file upload async function uploadMultipleFiles(files) { const formData = new FormData() files.forEach((file, index) => { formData.append(`files[]`, file) }) formData.append('album_name', 'Vacation Photos') formData.append('privacy', 'private') const response = await post('/photos/bulk-upload', { body: formData, // No contentType needed - automatically set with boundary query: { redirect_to: '/albums/latest' }, keepalive: true // Keep alive for large uploads }) return response.ok } // URLSearchParams for query strings async function searchWithParams() { const params = new URLSearchParams() params.append('tags[]', 'javascript') params.append('tags[]', 'rails') params.append('sort', 'recent') const response = await get('/posts/search', { query: params, responseKind: 'json' }) return await response.json() } // Cross-origin requests with credentials async function crossOriginRequest() { const response = await get('https://api.example.com/data', { credentials: 'include', // Send cookies cross-origin headers: { 'X-API-Key': 'your-api-key' }, responseKind: 'json' }) return await response.json } ``` -------------------------------- ### Registering and Resetting Request Interceptors in JavaScript Source: https://github.com/rails/request.js/blob/main/README.md Demonstrates how to use the RequestInterceptor to modify outgoing requests, such as adding authentication tokens. It shows how to register a custom interceptor function and how to reset it. ```javascript import { RequestInterceptor } from '@rails/request.js' // ... // Set interceptor RequestInterceptor.register(async (request) => { const token = await getSessionToken(window.app) request.addHeader('Authorization', `Bearer ${token}`) }) // Reset interceptor RequestInterceptor.reset() ``` -------------------------------- ### Integrate Turbo Stream Responses with @rails/request.js Source: https://context7.com/rails/request.js/llms.txt Enables automatic processing of Turbo Stream responses for real-time page updates. This integration requires Turbo.js to be loaded and configured globally. ```javascript import { Turbo } from "@hotwired/turbo-rails" import { post, get } from '@rails/request.js' // Set up Turbo global (required for Turbo Stream processing) window.Turbo = Turbo // Create a post with Turbo Stream response async function createPostWithStream() { // Request with turbo-stream response kind const response = await post('/posts', { body: { post: { title: 'New Post', content: 'Content here' } }, responseKind: 'turbo-stream' }) // Turbo Stream is automatically processed if: // 1. Response status is 200 (ok) or 422 (unprocessableEntity) // 2. Content-Type is text/vnd.turbo-stream.html // 3. window.Turbo is available // The stream updates the page automatically console.log('Post created, page updated via Turbo Stream') } // Form submission with Turbo Stream validation errors async function submitFormWithValidation(formData) { const response = await post('/users', { body: formData, responseKind: 'turbo-stream' }) if (response.ok) { // Success stream rendered (e.g., append new user to list) console.log('User created successfully') } else if (response.unprocessableEntity) { // Validation error stream rendered (e.g., update form with errors) console.log('Validation errors displayed via Turbo Stream') } return response } // Polling with Turbo Streams async function pollForUpdates() { const intervalId = setInterval(async () => { const response = await get('/notifications/poll', { responseKind: 'turbo-stream' }) // Each poll can return a Turbo Stream that updates notifications if (response.ok) { console.log('Notifications updated') } }, 30000) // Poll every 30 seconds return intervalId } // Rails controller example for Turbo Stream response: // def create // @post = Post.create(post_params) // // respond_to do |format| // format.turbo_stream { // render turbo_stream: turbo_stream.append('posts', @post) // } // end // end ``` -------------------------------- ### FetchResponse Class Source: https://context7.com/rails/request.js/llms.txt Enhances the native Fetch API response with convenient properties and methods for easier handling of response status, headers, and body parsing. ```APIDOC ## FetchResponse Class Overview ### Description The `FetchResponse` class wraps the native Fetch API response, providing utility methods to check status, access headers, and parse the response body in various formats (JSON, HTML, text). ### Properties - **statusCode** (integer): The HTTP status code of the response. - **ok** (boolean): True if the status code is between 200 and 299. - **unauthenticated** (boolean): True if the status code is 401. - **unprocessableEntity** (boolean): True if the status code is 422. - **contentType** (string): The 'Content-Type' header value. - **headers** (Headers): The native Headers object. ### Methods - **json**: Returns a promise that resolves with the parsed JSON body. Rejects if the content type is not JSON. - **html**: Returns a promise that resolves with the HTML body as a string. - **text**: Returns a promise that resolves with the response body as a string. ### Automatic Handling - **Turbo Stream**: Responses with `text/vnd.turbo-stream.html` are automatically processed. - **JavaScript**: Responses with `application/javascript` are automatically executed. ### Example Usage ```javascript import { post } from '@rails/request.js'; async function handleResponse() { const response = await post('/articles', { body: { title: 'Test Article' } }); console.log('Status code:', response.statusCode); console.log('Is successful:', response.ok); if (response.unauthenticated) { console.log('Login URL:', response.authenticationURL); } const contentType = response.contentType; if (contentType === 'application/json') { const data = await response.json; console.log('JSON data:', data); } else if (contentType.includes('html')) { const html = await response.html; document.getElementById('content').innerHTML = html; } else { const text = await response.text; console.log('Text response:', text); } } ``` ``` ```APIDOC ## Safe JSON Parsing ### Description Demonstrates how to safely parse JSON responses, providing a fallback to text parsing in case of non-JSON content types. ### Method POST ### Endpoint `/api/data` ### Request Body - **query** (string) - Required - The query parameters for the API. ### Request Example ```javascript import { post } from '@rails/request.js'; async function safeJsonParse() { const response = await post('/api/data', { body: { query: 'test' }, responseKind: 'json' }); try { const data = await response.json; return data; } catch (error) { console.error('Expected JSON but got:', response.contentType); const text = await response.text; return { error: 'Invalid response', body: text }; } } ``` ### Response #### Success Response (200) - **data** (object) - The parsed JSON response. #### Error Response (Non-JSON Content Type) - **error** (string) - Indicates an invalid response. - **body** (string) - The raw response body as text. #### Response Example (Success) ```json { "results": [ { "id": 1, "name": "Item 1" } ] } ``` #### Response Example (Error) ```json { "error": "Invalid response", "body": "

Not Found

" } ``` ``` -------------------------------- ### Add Request Analytics and Timing with JavaScript Source: https://context7.com/rails/request.js/llms.txt This snippet illustrates how to enhance HTTP requests with analytics tracking, measuring request duration and logging success or failure events. It wraps a request promise and uses the `performance.now()` API to calculate the time taken. Analytics are sent using a hypothetical `analytics.track` function. This functionality can be combined with other request wrappers. ```javascript function withAnalytics(requestPromise, requestInfo) { const startTime = performance.now() return requestPromise .then((response) => { const duration = performance.now() - startTime // Send analytics analytics.track('api_request', { url: requestInfo.url, method: requestInfo.method, status: response.statusCode, duration: duration, success: response.ok }) return response }) .catch((error) => { const duration = performance.now() - startTime analytics.track('api_request_failed', { url: requestInfo.url, method: requestInfo.method, duration: duration, error: error.message }) throw error }) } // Custom request wrapper with multiple hooks export function trackedPost(url, options) { const request = new FetchRequest("post", url, options) const requestPromise = request.perform() // Apply multiple wrappers const withProgressPromise = withProgress(requestPromise) const withAnalyticsPromise = withAnalytics(withProgressPromise, { url: url, method: 'post' }) return withAnalyticsPromise } // Usage async function createResource() { const response = await trackedPost('/resources', { body: { name: 'New Resource' }, responseKind: 'json' }) // Request is tracked and shows progress bar return await response.json } ``` -------------------------------- ### FetchRequest Class - Main request interface Source: https://context7.com/rails/request.js/llms.txt The FetchRequest class provides the core functionality for making HTTP requests with automatic CSRF token handling, custom headers, and Rails-specific response processing. ```APIDOC ## FetchRequest Class - Main request interface ### Description The `FetchRequest` class provides the core functionality for making HTTP requests with automatic CSRF token handling, custom headers, and Rails-specific response processing. ### Method `POST` ### Endpoint `/users` ### Parameters #### Request Body - **user** (object) - Required - User object containing name and email. - **name** (string) - Required - The name of the user. - **email** (string) - Required - The email of the user. ### Request Example ```javascript import { FetchRequest } from '@rails/request.js' const request = new FetchRequest('post', '/users', { body: JSON.stringify({ user: { name: 'John Doe', email: 'john@example.com' } }), contentType: 'application/json' }) const response = await request.perform() ``` ### Response #### Success Response (200) - **data** (object) - The created user object. #### Response Example ```json { "id": 1, "name": "John Doe", "email": "john@example.com" } ``` --- ## GET /users ### Description Fetches a list of users with optional search and pagination parameters. ### Method `GET` ### Endpoint `/users` ### Parameters #### Query Parameters - **search** (string) - Optional - The search term for users. - **page** (integer) - Optional - The page number for pagination. - **per_page** (integer) - Optional - The number of items per page. - **X-Custom-Header** (string) - Optional - A custom header value. ### Request Example ```javascript import { FetchRequest } from '@rails/request.js' const request = new FetchRequest('get', '/users', { query: { search: 'John', page: 1, per_page: 20 }, headers: { 'X-Custom-Header': 'custom-value' }, responseKind: 'json' }) const response = await request.perform() const users = await response.json ``` ### Response #### Success Response (200) - **users** (array) - An array of user objects. #### Response Example ```json [ { "id": 1, "name": "John Doe", "email": "john@example.com" } ] ``` --- ## POST /avatars ### Description Uploads a user avatar. ### Method `POST` ### Endpoint `/avatars` ### Parameters #### Request Body - **avatar** (file) - Required - The avatar file to upload. - **user_id** (string) - Required - The ID of the user whose avatar is being uploaded. ### Request Example ```javascript import { FetchRequest } from '@rails/request.js' const formData = new FormData() formData.append('avatar', file) formData.append('user_id', '123') const request = new FetchRequest('post', '/avatars', { body: formData }) const response = await request.perform() ``` ### Response #### Success Response (200) - **ok** (boolean) - Indicates if the upload was successful. #### Response Example ```json { "ok": true } ``` --- ## GET /long-running-task ### Description Initiates a long-running task with the ability to cancel the request. ### Method `GET` ### Endpoint `/long-running-task` ### Parameters #### Query Parameters - **signal** (AbortSignal) - Required - Used to cancel the request. ### Request Example ```javascript import { FetchRequest } from '@rails/request.js' const controller = new AbortController() const request = new FetchRequest('get', '/long-running-task', { signal: controller.signal }) // Cancel after 5 seconds setTimeout(() => controller.abort(), 5000) try { const response = await request.perform() return await response.json } catch (error) { console.log('Request cancelled or failed:', error) } ``` ### Response #### Success Response (200) - **data** (object) - The result of the long-running task. #### Response Example ```json { "status": "completed", "result": "some data" } ``` ``` -------------------------------- ### Register Interceptor with Conditional Logic and Logging Source: https://context7.com/rails/request.js/llms.txt Demonstrates registering a more complex interceptor that adds headers conditionally based on the request URL and includes a correlation ID. It also logs outgoing requests in a development environment. ```javascript import { RequestInterceptor } from '@rails/request.js' // More complex interceptor with conditional logic RequestInterceptor.register(async (request) => { // Add different headers based on request URL if (request.url.includes('/api/v2/')) { const apiKey = process.env.API_KEY request.addHeader('X-API-Key', apiKey) request.addHeader('X-API-Version', '2.0') } // Add correlation ID for request tracking const correlationId = generateUUID() request.addHeader('X-Correlation-ID', correlationId) // Log outgoing requests in development if (process.env.NODE_ENV === 'development') { console.log(`${request.method} ${request.url}`) } }) ``` -------------------------------- ### Handle JavaScript Responses Automatically with Rails Source: https://context7.com/rails/request.js/llms.txt This snippet shows how to automatically execute JavaScript responses from the server using `@rails/request.js`. When a response has a `Content-Type` of `application/javascript`, it is automatically wrapped in a `