@@ -402,6 +402,236 @@ const user = await apiFetch(
402402
403403---
404404
405+ ## HTTP Methods
406+
407+ what -the -fetch automatically infers HTTP methods based on the presence of a request body . You can optionally use the ` @method ` prefix for explicit control or to specify methods other than GET and POST .
408+
409+ ### Automatic Method Inference
410+
411+ By default , what -the -fetch infers the HTTP method :
412+ - Requests **with a body ** → ` POST `
413+ - Requests **without a body ** → ` GET `
414+
415+ ` ` ` typescript
416+ const api = {
417+ '/users/:id': { /* Uses GET (no body) */ },
418+ '/users': { body: z.object({...}), /* Uses POST (has body) */ }
419+ };
420+ ` ` `
421+
422+ ### Method Prefix Syntax (Optional )
423+
424+ For explicit control or to use other HTTP methods , add the ` @method ` prefix :
425+
426+ ` ` ` typescript
427+ const api = {
428+ '@get/resource': { /* Explicit GET - same as /resource */ },
429+ '/resource': { /* Implicit GET */ },
430+ '@post/resource': { /* Explicit POST */ },
431+ '@put/resource/:id': { /* PUT - prefix required */ },
432+ '@patch/resource/:id': { /* PATCH - prefix required */ },
433+ '@delete/resource/:id': { /* DELETE - prefix required */ }
434+ };
435+ ` ` `
436+
437+ **Note : ** ` /users/:id ` and ` @get/users/:id ` are completely equivalent and both result in a GET request .
438+
439+ ### Supported HTTP Methods
440+
441+ All standard HTTP methods are supported :
442+
443+ - ` @get ` - GET requests (retrieve data )
444+ - ` @post ` - POST requests (create new resources )
445+ - ` @put ` - PUT requests (replace existing resources )
446+ - ` @patch ` - PATCH requests (partially update resources )
447+ - ` @delete ` - DELETE requests (remove resources )
448+ - ` @head ` - HEAD requests (retrieve headers only )
449+ - ` @options ` - OPTIONS requests (check available methods )
450+
451+ ### Complete Example
452+
453+ ` ` ` typescript
454+ import { createFetch } from 'what-the-fetch';
455+ import { z } from 'zod';
456+
457+ const api = {
458+ // GET - Retrieve a user
459+ '@get/users/:id': {
460+ params: z.object({ id: z.number() }),
461+ response: z.object({
462+ id: z.number(),
463+ name: z.string(),
464+ email: z.string()
465+ })
466+ },
467+
468+ // POST - Create a new user
469+ '@post/users': {
470+ body: z.object({
471+ name: z.string(),
472+ email: z.string().email()
473+ }),
474+ response: z.object({
475+ id: z.number(),
476+ name: z.string(),
477+ email: z.string()
478+ })
479+ },
480+
481+ // PUT - Replace entire user
482+ '@put/users/:id': {
483+ params: z.object({ id: z.number() }),
484+ body: z.object({
485+ name: z.string(),
486+ email: z.string().email()
487+ }),
488+ response: z.object({
489+ id: z.number(),
490+ name: z.string(),
491+ email: z.string()
492+ })
493+ },
494+
495+ // PATCH - Partially update user
496+ '@patch/users/:id': {
497+ params: z.object({ id: z.number() }),
498+ body: z.object({
499+ name: z.string().optional(),
500+ email: z.string().email().optional()
501+ }),
502+ response: z.object({
503+ id: z.number(),
504+ name: z.string(),
505+ email: z.string()
506+ })
507+ },
508+
509+ // DELETE - Remove a user
510+ '@delete/users/:id': {
511+ params: z.object({ id: z.number() }),
512+ response: z.object({ success: z.boolean() })
513+ }
514+ } as const;
515+
516+ const apiFetch = createFetch(api, 'https://api.example.com');
517+
518+ // Make requests with explicit methods
519+ const user = await apiFetch('@get/users/:id', { params: { id: 123 } });
520+ // GET https://api.example.com/users/123
521+
522+ const newUser = await apiFetch('@post/users', {
523+ body: { name: 'John Doe', email: '[email protected] ' } 524+ });
525+ // POST https://api.example.com/users
526+
527+ await apiFetch('@put/users/:id', {
528+ params: { id: 123 },
529+ body: { name: 'Jane Doe', email: '[email protected] ' } 530+ });
531+ // PUT https://api.example.com/users/123
532+
533+ await apiFetch('@patch/users/:id', {
534+ params: { id: 123 },
535+ body: { name: 'Jane Smith' }
536+ });
537+ // PATCH https://api.example.com/users/123
538+
539+ await apiFetch('@delete/users/:id', { params: { id: 123 } });
540+ // DELETE https://api.example.com/users/123
541+ ` ` `
542+
543+ ### Equivalence Examples
544+
545+ The following path definitions are equivalent :
546+
547+ ` ` ` typescript
548+ const api = {
549+ // These two are identical - both use GET
550+ '/users/:id': {
551+ params: z.object({ id: z.number() }),
552+ response: z.object({ id: z.number(), name: z.string() })
553+ },
554+ '@get/users/:id': { // Same as above - @get is optional
555+ params: z.object({ id: z.number() }),
556+ response: z.object({ id: z.number(), name: z.string() })
557+ },
558+
559+ // POST is inferred from body
560+ '/users': {
561+ body: z.object({ name: z.string(), email: z.string() }),
562+ response: z.object({ id: z.number(), name: z.string() })
563+ }
564+ };
565+
566+ const apiFetch = createFetch(api, 'https://api.example.com');
567+
568+ // Both calls are equivalent - both use GET
569+ const user1 = await apiFetch('/users/:id', { params: { id: 123 } });
570+ const user2 = await apiFetch('@get/users/:id', { params: { id: 123 } });
571+
572+ // POST (inferred from body)
573+ const newUser = await apiFetch('/users', {
574+ body: { name: 'John', email: '[email protected] ' } 575+ });
576+ ` ` `
577+
578+ **Method inference rules : **
579+ - Request has a ` body ` → ` POST `
580+ - Request has no ` body ` → ` GET `
581+ - Method prefix specified → Uses that method
582+
583+ ### Method Prefix with Path Parameters
584+
585+ The method prefix works seamlessly with path parameters :
586+
587+ ` ` ` typescript
588+ const api = {
589+ '@put/users/:userId/posts/:postId': {
590+ params: z.object({
591+ userId: z.number(),
592+ postId: z.number()
593+ }),
594+ body: z.object({ title: z.string(), content: z.string() }),
595+ response: z.object({ success: z.boolean() })
596+ }
597+ };
598+
599+ const apiFetch = createFetch(api, 'https://api.example.com');
600+
601+ await apiFetch('@put/users/:userId/posts/:postId', {
602+ params: { userId: 123, postId: 456 },
603+ body: { title: 'Updated', content: 'New content' }
604+ });
605+ // PUT https://api.example.com/users/123/posts/456
606+ ` ` `
607+
608+ ### Case Insensitive
609+
610+ Method prefixes are case -insensitive and converted to uppercase :
611+
612+ ` ` ` typescript
613+ const api = {
614+ '@GET/users': { /* ... */ },
615+ '@get/posts': { /* ... */ },
616+ '@GeT/comments': { /* ... */ }
617+ };
618+
619+ // All are treated as GET
620+ ` ` `
621+
622+ ### Best Practices
623+
624+ 1. **Be explicit with methods **: Use method prefixes for clarity , especially for PUT , PATCH , and DELETE operations
625+ 2. **RESTful design **: Follow REST conventions :
626+ - ` @get ` for retrieval
627+ - ` @post ` for creation
628+ - ` @put ` for full replacement
629+ - ` @patch ` for partial updates
630+ - ` @delete ` for removal
631+ 3. **Consistency **: Choose either to always use method prefixes or rely on automatic detection - be consistent across your API schema
632+
633+ ---
634+
405635## Advanced Usage
406636
407637### Shared Request Configuration
0 commit comments