Let's Go Further فیلتر کردن، مرتب‌سازی و صفحه‌بندی › اعتبارسنجی پارامترهای رشته کوئری
قبلی · فهرست مطالب · بعدی
فصل ۹.۲.

اعتبارسنجی پارامترهای رشته کوئری

به لطف تابع کمکی readInt() که در فصل قبل ایجاد کردیم، API ما در حال حاضر باید خطاهای اعتبارسنجی را اگر پارامترهای رشته کوئری page و page_size شامل مقادیر عدد صحیح نباشند، برگرداند. اگر مایلید آن را امتحان کنید:

$ curl "localhost:4000/v1/movies?page=abc&page_size=abc"
{
    "error": {
        "page": "must be an integer value",
        "page_size": "must be an integer value"
    }
}

اما هنوز باید برخی بررسی‌های اضافی انجام دهیم تا مطمئن شویم مقادیر رشته کوئری که توسط کلاینت ارائه شده‌اند، منطقی هستند. به طور خاص، می‌خواهیم بررسی کنیم که:

برای رفع این مشکل، بیایید فایل internal/data/filters.go را باز کرده و یک تابع جدید ValidateFilters() ایجاد کنیم که این بررسی‌ها را روی مقادیر انجام می‌دهد.

ما از همان الگویی که برای تابع ValidateMovie() در ابتدای کار استفاده کردیم، پیروی خواهیم کرد، به این صورت:

فایل: internal/data/filters.go
package data

import (
    "greenlight.alexedwards.net/internal/validator" // New import
)

// Add a SortSafelist field to hold the supported sort values.
type Filters struct {
    Page         int
    PageSize     int
    Sort         string
    SortSafelist []string
}

func ValidateFilters(v *validator.Validator, f Filters) {
    // Check that the page and page_size parameters contain sensible values.
    v.Check(f.Page > 0, "page", "must be greater than zero")
    v.Check(f.Page <= 10_000_000, "page", "must be a maximum of 10 million")
    v.Check(f.PageSize > 0, "page_size", "must be greater than zero")
    v.Check(f.PageSize <= 100, "page_size", "must be a maximum of 100")

    // Check that the sort parameter matches a value in the safelist.
    v.Check(validator.PermittedValue(f.Sort, f.SortSafelist...), "sort", "invalid sort value")
}

سپس باید listMoviesHandler خود را به روز کنیم تا مقادیر پشتیبانی‌شده را در فیلد SortSafelist تنظیم کند و سپس این تابع جدید ValidateFilters() را فراخوانی کنیم.

فایل: cmd/api/movies.go
package main

...

func (app *application) listMoviesHandler(w http.ResponseWriter, r *http.Request) {
    var input struct {
        Title  string
        Genres []string
        data.Filters
    }

    v := validator.New()

    qs := r.URL.Query()

    input.Title = app.readString(qs, "title", "")
    input.Genres = app.readCSV(qs, "genres", []string{})

    input.Filters.Page = app.readInt(qs, "page", 1, v)
    input.Filters.PageSize = app.readInt(qs, "page_size", 20, v)

    input.Filters.Sort = app.readString(qs, "sort", "id")
    // Add the supported sort values for this endpoint to the sort safelist.
    input.Filters.SortSafelist = []string{"id", "title", "year", "runtime", "-id", "-title", "-year", "-runtime"}

    // Execute the validation checks on the Filters struct and send a response 
    // containing the errors if necessary.
    if data.ValidateFilters(v, input.Filters); !v.Valid() {
        app.failedValidationResponse(w, r, v.Errors)
        return
    }

    fmt.Fprintf(w, "%+v\n", input)
}

اگر API را مجدداً راه‌اندازی کنید و درخواستی با پارامترهای نامعتبر page، page_size و sort ارسال کنید، اکنون باید پاسخ خطا حاوی پیام‌های عدم اعتبار مربوطه دریافت کنید. مانند زیر:

$ curl "localhost:4000/v1/movies?page=-1&page_size=-1&sort=foo"
{
    "error": {
        "page": "must be greater than zero",
        "page_size": "must be greater than zero",
        "sort": "invalid sort value"
    }
}

اگر مایلید، می‌توانید آزمایش را بیشتر انجام دهید و مقادیر مختلف رشته کوئری را تا زمانی که مطمئن شوید بررسی‌های اعتبارسنجی همگی به درستی کار می‌کنند، امتحان کنید.