gqlgen-sqlboiler
gqlgen-sqlboiler copied to clipboard
[Question] Supporting external record identifiers as strings that look up non primary key
I'll try to explain myself fully.
In my current code, I do the following when sending data to the client;
Here is the database model
Here is the external model being constructed from the database model
I use the unique UUID as the identifier when referring to it on the end client.
Example uID: '90c1939d-3414-11eb-8ffe-0242ac120005'
So I suppose my question is;
- Am I able to change the schema and resolver to use the UID data as input
- Then use it as the first select argument to look up the record row.
An example of how I do it manually.
Notice the use of ThreadWhere.UID rather than ThreadWhere.ID
Not sure. We construct the id based on the type of the model + the id of the model. e.g.
User_1
or User_2838932983298
this is to support the Node interface and Global Object Identification https://graphql.org/learn/global-object-identification/
So if I understand correctly you use internal id's and external ids?
Yes, mainly for security measures and the aspect of ids unique to the whole database
When making a request, the client sends back the UUID in some valid way instead of a row number
For example
GET api/v1/thread?threadId=90c1939d-3414-11eb-8ffe-0242ac120005
The record is then fetched from the thread table by this unique id, and the model ID, which is the table primary key, is then used by sqlboiler as usual for joins and such.
Ah I see, we choose to encode the model because of the Node resolver so we know which table to fetch based on the id.
I think you could use the override converts for most of these use-cases and convert the graphql id to your internal id https://github.com/web-ridge/gqlgen-sqlboiler#overriding-converts
If you still have the chance I would choose between 1 id a uuid or auto increment id since gqlgen-sqlboiler does handle the unique ID across the schema . If you take security into consideration I don't know if it really would be more secure to not make your internal id's publicly https://en.wikipedia.org/wiki/Security_through_obscurity. I would recommend to put the user_id / tenant_id in your query to secure your data.
I think you will have most of the advantages if you use UUID for your id's everywhere since they are harder to guess than auto increment, so you'll still handle the 'Security through obscurity' and it's harder for users to scrape public data.
This is also interesting to read on this subject: https://softwareengineering.stackexchange.com/a/139453
We force the authentication if configured on all where's so if the user is not the owner of the object it won't do anything
dm.CommentWhere.UserID.EQ(auth.UserIDFromContext(ctx)),
https://github.com/web-ridge/gqlgen-sqlboiler-examples/blob/main/social-network/resolver.go#L71
See here more how to configure the AuthorizationScopes https://github.com/web-ridge/gqlgen-sqlboiler-examples/blob/main/social-network/convert_plugin.go#L66
Aye, I do agree with the question around if it's really practical to obscure the row Ids
In terms of authentication, I'm loading a user context through information provided from access tokens, then passing the user object through the call context, and of course then asserting the user can modify the record in question in the biz logic packages.
As you note, the biggest reason I chose to use external ids is to prevent users from inferring the number of posts, number of users, or other such records. And of course, generally make it slightly harder to attack the api when object identifiers are opaque.