لیست کردن دادهها
خب، بیایید ادامه بدهیم و endpoint خودمان GET /v1/movies را طوری تنظیم کنیم که دادههای واقعی را برگرداند.
فعلاً، مقادیر query string ارسالی توسط کلاینت را نادیده میگیریم و تمام رکوردهای فیلم را، مرتب شده بر اساس شناسه فیلم، برمیگردانیم. این یک پایه محکم به ما میدهد تا بتوانیم قابلیتهای تخصصیتر در اطراف فیلتر کردن، مرتبسازی و صفحهبندی را توسعه دهیم.
هدف ما در این فصل این است که endpoint را طوری تنظیم کنیم که یک پاسخ JSON حاوی آرایهای از تمام فیلمها مانند این برگرداند:
{
"movies": [
{
"id": 1,
"title": "Moana",
"year": 2015,
"runtime": "107 mins",
"genres": [
"animation",
"adventure"
],
"version": 1
},
{
"id": 2,
"title": "Black Panther",
"year": 2018,
"runtime": "134 mins",
"genres": [
"sci-fi",
"action",
"adventure"
],
"version": 2
},
... etc.
]
}
بهروزرسانی برنامه
برای بازیابی این دادهها از پایگاه داده PostgreSQL خود، بیایید یک متد جدید GetAll() در مدل پایگاه داده خود ایجاد کنیم که کوئری SQL زیر را اجرا میکند:
SELECT id, created_at, title, year, runtime, genres, version FROM movies ORDER BY id
از آنجایی که انتظار داریم این کوئری SQL چندین رکورد برگرداند، باید آن را با استفاده از متد QueryContext() Go اجرا کنیم. ما قبلاً نحوه عملکرد آن را به طور کامل در Let's Go توضیح دادهایم، پس بیایید مستقیماً به کد بپردازیم:
package data ... // Create a new GetAll() method which returns a slice of movies. Although we're not // using them right now, we've set this up to accept the various filter parameters as // arguments. func (m MovieModel) GetAll(title string, genres []string, filters Filters) ([]*Movie, error) { // Construct the SQL query to retrieve all movie records. query := ` SELECT id, created_at, title, year, runtime, genres, version FROM movies ORDER BY id` // Create a context with a 3-second timeout. ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() // Use QueryContext() to execute the query. This returns a sql.Rows resultset // containing the result. rows, err := m.DB.QueryContext(ctx, query) if err != nil { return nil, err } // Importantly, defer a call to rows.Close() to ensure that the resultset is closed // before GetAll() returns. defer rows.Close() // Initialize an empty slice to hold the movie data. movies := []*Movie{} // Use rows.Next to iterate through the rows in the resultset. for rows.Next() { // Initialize an empty Movie struct to hold the data for an individual movie. var movie Movie // Scan the values from the row into the Movie struct. Again, note that we're // using the pq.Array() adapter on the genres field here. err := rows.Scan( &movie.ID, &movie.CreatedAt, &movie.Title, &movie.Year, &movie.Runtime, pq.Array(&movie.Genres), &movie.Version, ) if err != nil { return nil, err } // Add the Movie struct to the slice. movies = append(movies, &movie) } // After the rows.Next() loop has finished, call rows.Err() to retrieve any error // that was encountered during the iteration. if err = rows.Err(); err != nil { return nil, err } // If everything went OK, then return the slice of movies. return movies, nil }
در مرحله بعد، باید listMoviesHandler را طوری تطبیق دهیم که متد جدید GetAll() را برای بازیابی دادههای فیلم فراخوانی کند و سپس این دادهها را به عنوان پاسخ JSON بنویسد.
اگر همراه ما هستید، لطفاً handler را به صورت زیر بهروزرسانی کنید:
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") input.Filters.SortSafelist = []string{"id", "title", "year", "runtime", "-id", "-title", "-year", "-runtime"} if data.ValidateFilters(v, input.Filters); !v.Valid() { app.failedValidationResponse(w, r, v.Errors) return } // Call the GetAll() method to retrieve the movies, passing in the various filter // parameters. movies, err := app.models.Movies.GetAll(input.Title, input.Genres, input.Filters) if err != nil { app.serverErrorResponse(w, r, err) return } // Send a JSON response containing the movie data. err = app.writeJSON(w, http.StatusOK, envelope{"movies": movies}, nil) if err != nil { app.serverErrorResponse(w, r, err) } }
و حالا باید آماده باشید تا آن را امتحان کنید.
لطفاً API را مجدداً راهاندازی کنید، سپس وقتی درخواست GET /v1/movies میدهید، باید آرایه فیلمهایی که توسط GetAll() برگردانده شده به صورت آرایه JSON نمایش داده شود. مشابه این:
$ curl localhost:4000/v1/movies
{
"movies": [
{
"id": 1,
"title": "Moana",
"year": 2016,
"runtime": "107 mins",
"genres": [
"animation",
"adventure"
],
"version": 1
},
{
"id": 2,
"title": "Black Panther",
"year": 2018,
"runtime": "134 mins",
"genres": [
"sci-fi",
"action",
"adventure"
],
"version": 2
},
{
"id": 4,
"title": "The Breakfast Club",
"year": 1985,
"runtime": "97 mins",
"genres": [
"comedy"
],
"version": 5
}
]
}