question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Support different API response structures (for pagination)

See original GitHub issue

Frameworks like Laravel often have built in pagination methods, which in turn change the default return data from the API. plugin-axios current $fetch method requires that the model data is in the root of the response array, however Laravel’s pagination method returns something like the following, with the data nested in the response:

{
  current_page: 1,
  data: [
    { ID: 512, FirstName: 'Bob', LastName: 'Smith' },
    { ID: 747, FirstName: 'Ryan', LastName: 'Mack' },
    ...
  ],
  first_page_url: "http://example.test/api/users?page=1",
  from: 1,
  last_page: 215,
  last_page_url: "http://example.test/api/users?page=215",
  next_page_url: "http://example.test/api/users?page=2",
  path: "http://example.test/api/users",
  per_page: 75,
  prev_page_url: null,
  to: 75,
  total: 16113
}

It is necessary that this data is paginated server side, as you can see there is a total of 16113 records, which in reality have many more columns and each have their own relationships.

Would it be possible to cater for this by including some configuration (either globally or within each model, maybe even just as simple as paginated: true would be amazing) where you could specify the expected response structure, or key of the data or something? It would be great if the pagination keys could be stored too, although would not need to be queried in the same way as the data.

At the moment I simply can’t use this as half of my API routes return paginated data, which I’m sure is common. I’ve tested a route without it and it works perfectly so thank you for this, huge huge help with working with a large scale SPA.

Maybe even be as simple as changing this in Fetch.js from:

static onSuccess(commit, model, data) {
  commit('onSuccess')

  model.insertOrUpdate({
    data,
  });
}

To this:

static onSuccess(commit, model, data) {
  commit('onSuccess')

  if (model.paginated) {
    model.insertOrUpdate(data);
  } else {
    model.insertOrUpdate({
      data
    })
  }
}

But I’m unsure of what other side effects this may have or what exactly insertOrUpdate is expecting.

Many thanks in advance.

EDIT: Have since tried the insertOrUpdate part in the promise returned from $fetch, this got the data working great (albeit with an empty default record at index 0) but doesn’t populate any of the pagination values, even after manually specifying the keys in each model’s state.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:9 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
russsiqcommented, Aug 17, 2019
2reactions
russsiqcommented, Apr 1, 2019

I define different status codes in the Laravel controller. This allows more correct processing of query results.

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class ArticleResource extends JsonResource
{
    /**
     * The "data" wrapper that should be applied.
     *
     * @var string
     */
    public static $wrap = null;

    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return parent::toArray($request);
    }
}
use Illuminate\Http\Response;

...

class ArticlesController extends Controller
{

    public function index()
    {
        $articles = Article::with([
                'categories:categories.id,categories.title,categories.slug',
                'user:users.id,users.name',
            ])->withCount([
                'comments',
                'files',
            ])->paginate();

        $collection = ArticleResource::collection($articles);

        return $collection->response()
            ->setStatusCode(Response::HTTP_PARTIAL_CONTENT);
    }

    public function store(ArticleRequest $request)
    {
        ...
            ->setStatusCode(Response::HTTP_CREATED);
    }

    public function show(int $id)
    {
        $article = Article::findOrFail($id);

        // 200 Response::HTTP_OK
        return new ArticleResource($article);
    }

    public function update(ArticleRequest $request, int $id)
    {
        ...
            ->setStatusCode(Response::HTTP_ACCEPTED);
    }
    public function destroy(int $id)
    {
        ...
        return response()->json(null, Response::HTTP_NO_CONTENT);
    }
// store/index.js
...
// Import Vuex plugins.
import VuexORM from '@vuex-orm/core'
import VuexORMAxios from '@vuex-orm/plugin-axios'
import database from './database'
import http from './axios-request-config'

VuexORM.use(VuexORMAxios, {
    http,
    database,
})
...
// store/axios-request-config.js

import store from '@/store'
import router from '@/router'

export default {
    axios: undefined,
...
    onResponse(response) {
        const statuses = {
            201: this.onCreatedResponse,
            202: this.onUpdatedResponse,
            204: this.onDeletedResponse,
            206: this.onPartialContent,
        }

        return response.status in statuses
            ? statuses[response.status](response)
            : response.data
    },
...
    /**
     * On 206 Partial Content
     * @param {object} response
     */
    onPartialContent(response) {
        const {
            data,
            meta
        } = response.data

        store.dispatch('paginator/paginate', meta)

        router.replace({
            query: {
                'page': meta.current_page
            }
        })

        return data
    },
...
}
// views\articles\index.vue
...
    methods: {
        async index(page = 1) {
            // Reset resource list.
            await this.model.deleteAll()

            // Fetch article resource.
            await this.model.$fetch({
                query: {
                    page: parseInt(page, 10)
                }
            })
        },
...
Read more comments on GitHub >

github_iconTop Results From Across the Web

What is API Pagination? Technical topics explained simply
Everything you need to know about API (aka Application Programming Interface) Pagination. This article what it is, various Pagination ...
Read more >
New API Pagination Patterns Using Cursors and Query Filter ...
We are introducing a new pagination approach that will become standard across our APIs using query filter extensions that allow for more ...
Read more >
Import Data Using REST API Pagination - Coupler.io Blog
Learn how you can import large data sets into Google Sheets via APIs using paginated requests, using the example of the Shopify API....
Read more >
API Pagination Patterns for Results Sets - MuleSoft Blog
Another option is limiting the number of records per page at an API level — so that instead of consumers specifying an OFFSET...
Read more >
“Cursor Pagination” Profile - JSON:API
paginated data: an array in a JSON:API response document that holds the results that were extracted from a full list of results being...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found