AthenaeumAthenaeum
Packages
  • next
  • current
  • v9.x
  • v8.x
  • v7.x
  • v6.x
  • v5.x
  • v4.x
  • v3.x
  • v2.x
  • v1.x
Changelog
GitHub
Packages
  • next
  • current
  • v9.x
  • v8.x
  • v7.x
  • v6.x
  • v5.x
  • v4.x
  • v3.x
  • v2.x
  • v1.x
Changelog
GitHub
  • Version 7.x

    • Release Notes
    • Upgrade Guide
    • New to this...
    • Contribution Guide
    • Security Policy
    • Code of Conduct
    • Origin
  • ACL

    • Introduction
    • How to install
    • Setup
    • Permissions
    • Roles
    • Users
    • Cached Permissions
  • Antivirus

    • Introduction
    • How to install
    • Setup
    • How to use
    • Scanners

      • Introduction
      • ClamAV
      • Null
      • Custom
    • Events
    • PSR
  • Audit

    • Audit
    • How to install
    • Setup
    • Recording
    • Events
  • Auth

    • Introduction
    • How to install
    • Fortify

      • Prerequisites
      • Actions

        • Rehash Password
  • Circuits

    • Circuits
    • How to install
    • Setup
    • Usage
    • Events
  • Collections

    • Collections
    • How to install
    • Summation

      • Summation Collection
      • Items Processor
  • Config

    • Configuration Loader
    • How to install
    • Setup
    • Load Configuration Files
    • Custom File Parsers
  • Console

    • Command and Schedule Registration
    • How to install
    • Setup
    • Commands
    • Schedules
  • Container

    • IoC Service Container
    • How to install
    • Container
    • List Resolver
  • Core

    • Athenaeum Core Application
    • How to install
    • Setup
    • Usage

      • Configuration
      • Service Providers
      • Service Container
      • Events
      • Caching
      • Logging
      • Console
      • Task Scheduling
      • Exception Handling
      • Extending Core Application
      • Testing
  • Database

    • Introduction
    • How to install
    • Models

      • Instantiatable
      • Sluggable
    • Query

      • Criteria (Query Filter)
  • Dto

    • Data Transfer Object (DTO)
    • How to install
    • Create Interface
    • Implement DTO
    • How to use
    • Populate
    • Export
    • Json
    • Serialization
    • Nested DTOs
    • Array DTO
  • ETags

    • Introduction
    • How to install
    • Setup
    • ETags usage

      • How to use
      • Generators

        • Default Generator
        • Custom Generator
      • Eloquent Models
    • Http Request Preconditions

      • Introduction
      • Resource Context
      • Preconditions
      • Actions
      • RFC 9110

        • If-Match
        • If-Unmodified-Since
        • If-None-Match
        • If-Modified-Since
        • If-Range
      • Extensions

        • Introduction
        • Range
      • Range Validator
      • Download Stream
    • Macros
  • Events

    • Register Listeners and Subscribers
    • How to install
    • Setup
    • Listeners
    • Subscribers
  • Filters

    • Search Filter Utilities
    • Prerequisites
    • How to install
    • Setup
    • Processor
    • Filters Builder
    • Predefined Resources

      • Search Processor
      • Sorting Processor
      • Constraints Processor
      • Matching Processor
    • Tip: Create a base builder
  • Flysystem

    • Introduction
    • Database Adapter

      • Introduction
      • How to install
      • Setup
      • Data Deduplication
      • MIME-Type Detection
  • Http

    • Api

      • Http API
      • How to install
      • Setup
      • Resources

        • Introduction
        • Timestamps
        • Self-Link
        • Relations
        • Caching
        • Registrar
      • Requests

        • Introduction
        • List Resources
        • List Deleted
        • Show Resource
        • Create Resource
        • Update Resource
        • Delete Resource
        • List Related
        • Process Multiple Resources
        • Helpers
      • Middleware

        • Introduction
        • Request Must Be Json
        • Capture Fields To Select
        • Remove Response Payload
    • Clients

      • Http Clients
      • How to install
      • Setup
      • Basic Usage
      • Available Methods

        • Fluent Api
        • Protocol Version
        • Base Uri
        • Http Method and Uri
        • Headers
        • Accept & Content-Type
        • Authentication
        • Http Query
        • Payload Format
        • Payload
        • Attachments
        • Cookies
        • Response Expectations
        • Middleware
        • Conditions
        • Criteria
        • Redirects
        • Timeout
        • Debugging
        • Logging
        • Driver Options
        • Driver
      • Http Query Builder

        • Introduction
        • Select
        • Where
        • Dates
        • Include
        • Pagination
        • Sorting
        • Raw Expressions
        • Custom Grammar
    • Cookies

      • Http Cookies
      • How to install
      • Usage
    • Messages

      • Http Messages
      • How to install
      • Serializers
  • Maintenance

    • Modes

      • Maintenance Modes
      • How to install
      • Setup
      • Basic Usage
      • Available Drivers
  • Mime Types

    • MIME-Types
    • How to install
    • Setup
    • Usage
    • Drivers

      • Available Drivers
      • File Info
  • Properties

    • Properties Overload
    • How to install
    • Usage
    • Naming Convention
    • Properties Visibility
  • Redmine

    • Redmine Api Client
    • How to install
    • Setup
    • General Usage

      • Supported Operations
      • Fetch list of resources
      • Find
      • Fetch
      • Create new record
      • Update existing record
      • Delete existing record
      • Relations
    • Available Resources

      • Predefined Resources
      • Attachments
      • Enumerations
      • Issue Relations
      • Users
      • User Groups
      • Roles
      • Project Memberships
      • Versions (Milestones)
      • Issue Categories
      • Trackers
  • Service

    • Service Registrar
    • How to install
    • How to use
  • Streams

    • Streams
    • How to install
    • Setup
    • How to use

      • Introduction
      • Open and Close
      • Raw Resource
      • Seeking
      • Reading
      • Writing
      • Size
      • Truncate
      • Sync
      • Flush
      • Hash
      • MIME-Type
      • Filename
      • Output
      • Locking
      • Transactions
      • Meta
      • Misc
  • Support

    • Introduction
    • How to install
    • Laravel Aware-of Helpers

      • How to use
      • Enforce Via Interface
      • Custom Default
      • Pros and Cons
      • Available Helpers
    • Aware-of Properties

      • Generator
      • Available Aware-of Helpers
    • Live Templates
  • Testing

    • Introduction
    • How to install
    • Test Cases
    • Testing Aware-of Helpers
  • Translation

    • Introduction
    • How to install
    • Exporters

      • Introduction
      • Setup
      • How to use
      • Drivers

        • Introduction
        • Array
        • Lang.js (Array)
        • Lang.js (JSON)
        • Cache
  • Utils

    • Introduction
    • How to install
    • Array
    • Duration
    • Json
    • Math
    • Memory
    • Method Helper
    • Invoker
    • Populatable
    • String
    • Version
  • Validation

    • Introduction
    • How to install
    • Setup
    • Rules

      • Alpha-Dash-Dot
      • Date Format
      • Semantic Version
You are viewing documentation for an outdated version. It is no longer supported!

Introduction

  • The Basics
  • How to Evaluate
    • Request
    • Route or Controller Action
    • Responses
  • The Evaluator
  • Exception Handling

The Basics

The design philosophy behind the request preconditions Evaluator is to evaluate an incoming conditional request, e.g. If-Match, against the requested resource.

In general, when a precondition is evaluated either of the following will happen:

  • When it passes (true):
    • Evaluator continues to evaluate another precondition (if requested).
    • Or it returns a changed resource (e.g. a state change or perhaps entirely modified resource).
  • When it fails (false):
    • The request is aborted by throwing an appropriate HttpException, via an Actions component.
    • The resource changed and returned.

All preconditions are evaluated in accordance with RFC 9110's order of precedence. See supported preconditions for additional information.

How to Evaluate

Http Conditional Requests are always specific to the requested resource and the Http Method. It is therefore recommended that you evaluate the requested resource inside your Form Request. The following shows an example request:

Request

use Aedart\Contracts\ETags\HasEtag;
use Aedart\Contracts\ETags\Preconditions\ResourceContext;
use Aedart\ETags\Preconditions\Evaluator;
use Aedart\ETags\Preconditions\Resources\GenericResource;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Http\FormRequest;

class ShowUserRequest extends FormRequest
{
    public ResourceContext $resource;

    protected function prepareForValidation()
    {
        // 1) Find requested resource or fail.
        $model = $this->findOrFailModel();

        // 2) Wrap it inside a Resource Context
        $resource = $this->makeResourceContext($model);

        // 3) Evaluate request's preconditions against resource...
        $this->resource = Evaluator::make($this)
            ->evaluate($resource);
    }

    protected function makeResourceContext(Model & HasEtag $model): ResourceContext
    {
        return new GenericResource(
            data: $model,
            etag: fn () => $model->getStrongEtag(),
            lastModifiedDate: $model->updated_at
        );
    }

    protected function findOrFailModel(): Model & HasEtag
    {
        // ...not shown ...
    }
}

Route or Controller Action

In your controller or route action, you can then return the requested resource with cache headers.

use Illuminate\Support\Facades\Route;

Route::get('/user/{id}', function (ShowUserRequest $request) {
    $resource = $request->resource;
    $payload = $resource
        ->data()
        ->toArray();

    return response()
        ->json($payload)
        ->withCache(
            etag: fn () => $resource->etag(),
            lastModified: $resource->lastModifiedDate(),
            private: true
        );
})->name('users.show');

Responses

Whenever a request without preconditions is received by your application, your application will return the requested resource, along with a few cache headers. For instance:

Request (without precondition)

GET /users/42 HTTP/1.1

Response (with cache headers)

HTTP/1.1 200 OK
Cache-Control: private
Etag: "a81283f2670a78cd4c5a2e56cb0cd4ef5e357eb1"
Last-Modified: Sun, 15 Jan 2023 16:13:23 GMT
Content-Type: application/json

{"id":42,"name":"John Doe","age":31,"updated_at":"2023-01-15T16:13:23.000000Z"}

However, when a request contains a preconditions, e.g. If-None-Match, then it is processed. In the example below, the precondition fails because the etag value matches the resource's etag. Therefore, a 304 Not Modified response is returned.

Request (with precondition)

GET /users/42 HTTP/1.1
If-None-Match: "a81283f2670a78cd4c5a2e56cb0cd4ef5e357eb1"

Response (If-None-Match precondition failed)

HTTP/1.1 304 Not Modified

The controller or route action is never executed. Instead, an exception is thrown and your application converts it into an appropriate response. If the precondition had passed instead, then controller or route action would have been processed (in this example).

The Evaluator

You are free to implement the evaluation logic as you see fit, within your application. The previous shown examples are only meant to demonstrate the general process. The rest is up to you. To instantiate an Evaluator instance, invoke the Evaluator::make() method.

The method accepts 3 arguments:

  • Request $request: the incoming request.
  • string[]|Precondition[] $preconditions = []: (optional) list of preconditions to evaluate.
    • Defaults to RFC 9110 + extension preconditions, when none are given.
  • Actions|null $actions = null: (optional) "abort" or "state change" actions instance.
    • Defaults to a default actions instance, when none is given.
use Aedart\ETags\Preconditions\Evaluator;

// Create evaluator instance (with defaults)
$evaluator = Evaluator::make($request);

// ...Or when you have custom preconditions / actions
$evaluator = Evaluator::make(
    reqeust: $request,
    preconditions: $myPreconditionsArray,
    actions: $myActions
);

Once you have instantiated an evaluator instance, use the evaluate() method to evaluate request's preconditions against the requested resource. The method accepts a ResourceContext instance and will either return the resource (possible changed), or throw a HttpException.

$evaluator->evaluate($resource);

Exception Handling

Whenever the Evaluator throws an exception, your Laravel application's exception handler will process it and create an appropriate response. Please read Laravel's exception handler documentation for additional information.

Edit page
Last Updated: 18/03/2024, 10:45
Contributors: Alin Eugen Deac, alin
Next
Resource Context