I have an app that uses Laravel and Lighthouse on the backend, and Nuxt and Vuex-ORM/graphql-plugin on the frontend. I'm having a difficult time with comparisons because for whatever reason, sometimes data is queried or mutated and IDs seem to be a mixture of either integer or string.
I'm in the midst of an effort to make sure that every single ID is in fact an integer. Whenever I console.log a Trip on the frontend, the ID of that Trip is still a string. When I run the query in graphql-playground, it returns as a string however I think that's more because it's an "ID" scalar type which can be either an int or string. Or something. I don't know, I'm still pretty green with this.
Trip.php:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Trip extends Model
{
protected $fillable = [
'name', 'description', 'user_id'
];
// automatically eager load todos and shopping_list_items
protected $with = [
'items', 'users'
];
// define relationships
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class);
}
}
trip.graphql:
extend type Query @guard(with: ["api"]) {
trip(id: ID! @eq): Trip! @find
trips: [Trip]! @field(resolver: "TripsQuery@find_by_user")
}
extend type Mutation @guard(with: ["api"]) {
updateTrip(id: ID! trip: TripInput! @spread): Trip @update
}
type Trip {
id: ID!
name: String
description: String
created_at: DateTime!
updated_at: DateTime!
user_id: ID
items: [Item]! @hasMany
users: [User]! @hasMany
}
input TripInput {
name: String
description: String
user_id: ID
}
trip.js:
import { Model } from '@vuex-orm/core';
import Item from './item';
import TripUser from './tripUser';
import User from './user';
export default class Trip extends Model {
static entity = 'trips';
static eagerLoad = ['items', 'users'];
static fields () {
return {
id: this.number(0),
name: this.string(''),
description: this.string(''),
user_id: this.number(0),
// relationships
items: this.hasMany(Item, 'trip_id'),
users: this.belongsToMany(User, TripUser, 'trip_id', 'user_id')
};
}
};
planning.vue:
<script>
import currentUser from '~/mixins/currentUser';
import Trip from '~/data/models/trip';
import tripsQuery from '~/apollo/queries/content/trips.gql';
export default {
name: 'Planning',
middleware: 'authenticated',
mixins: [currentUser],
data: () => ({
loading: 1,
}),
computed: {
trips () {
return Trip.query().where('owner_id', this.currentUser.id).all();
}
},
async mounted () {
const { trips } = await this.$store.dispatch('entities/simpleQuery', {
query: tripsQuery,
variables: {},
bypassCache: false
});
console.log(typeof trips[0].id); // <--- returns 'string';
Trip.insert({ data: [...trips] });
this.selectedTrip = trips.length ? trips[0] : null;
this.loading = 0;
},
head () {
return {
title: 'Planning'
};
}
};
</script>
You can see in the console.log of the mounted
function in the Vue file, that the id is still returning as a string instead of an integer. How do I make sure it is always an integer instead?
UPDATE: I think I've narrowed it down to a larger issue as a whole with the @vuex-orm/plugin-graphql library I'm using. I was attempting to revert a bit so that everything used string id's instead, however I discovered that when I dispatch a mutation, for some reason there is code that transforms ids into integers. I'm going to file a bug report with that library, and close this question.
I wanted to chime in here and point out that the ID is being cast as a string by design, not as a bug. You seen read more about it in this SO answer: https://stackoverflow.com/a/47888604/11678503
In short, the ID is a scalar type defined within the GraphQL specification (June 2018 working spec):
While ID's in a database are commonly an auto-incrementing numeric key, this is by no means a standard. Many API's use hashes and UUID's instead, as it depends on the use-case. As such, an ID can always be a string, but it cannot always be a number — hence why casting as a string is a safer bet.
So I hope that clears up why Lighthouse and, by extension, the graphql-php library cast IDs as strings. They're keeping with the spec.
Hope that helps clear things up!