Welcome to johnbintz.com

PostGraphQL Dev Notes - Part 1

Nov 21, 2017

Warning: some of this stuff will look pretty n00b. I’m not the strongest PostgreSQL user, which is the whole point of diving in deep with PostGraphQL. So far, this “database as app server” approach is working for this simple CRUD app I’m building, and I’ll be writing up more notes like this as I go, both to help solidify it in my mind and to help out other n00bs like myself with this different approach.

Dependent Table Permissions

I have a thing that contain other things (a has_many/belongs_to relationship in Rails) and I want to enforce, in PostgreSQL, ownership of both using the JWT approach in the PostGraphQL when working with the child thing. Within a node-pg-migrate migration file, I did this and it enforced the parent/child relationship of everything. This was probably overkill on the DELETE policy, but eh, it’s more code reuse and less to write for this very basic app:

  var rowLevelCheck = `
    (select true from myschema.parent_table as a
    where user_id = current_setting('jwt.claims.user_id')::integer
    and parent_id = a.id
    and user_id = a.user_id)
  `;

  pgm.sql(`
    create policy insert_child_table on myschema.child_table
    for insert to myapp_user with check (${rowLevelCheck});
  `);

  pgm.sql(`
    create policy update_child_table on myschema.child_table
    for update to myapp_user using (${rowLevelCheck});
  `);

  pgm.sql(`
    create policy delete_child_table on myschema.child_table
    for delete to myapp_user using (${rowLevelCheck});
  `);

Sandstorm Dev Notes - Part 1

Nov 17, 2017

I like Sandstorm so much that I’m finally developing an app for it. It’ll use PostGraphQL to move all of the business logic into PostgreSQL, and React, Redux, and Apollo to handle the UI and data reading/manipulation. I’ll be documenting the weird issues I’ve run into when setting this up, since there aren’t a ton of docs on this particular combo of services.

PostgreSQL

initdb

Due to how grains have random UID/GID assigned to them for security purposes, and because /etc/passwd and /etc/group are not available when running launcher.sh, initdb will fail because it wants to look up the current UID in /etc/passwd for security reasons. You can get around this by using nss_wrapper:

export PGDATA=/var/lib/postgres

echo "postgres:x:$(id -u):$(id -g):PostgreSQL user:/var/lib/postgres:/bin/sh" > /var/passwd
echo "postgres:x:$(id -g):" > /var/group

if [ ! -d $PGDATA ]; then
  LD_PRELOAD=/usr/lib/libnss_wrapper.so NSS_WRAPPER_PASSWD=/var/passwd NSS_WRAPPER_GROUP=/var/group /usr/lib/postgresql/10/bin/initdb
fi

localhost

Since you don’t have /etc. you also don’t have /etc/hosts, which is where the hostname localhost is defined. Use 127.0.0.1 everywhere (your app, PostgreSQL config) instead.

NodeJS

HOME

Some Node modules want your HOME directory:

/usr/lib/node_modules/npm/node_modules/update-notifier/node_modules/xdg-basedir/index.js:5
const home = os.homedir();
                ^

Error: ENOENT: no such file or directory, uv_os_homedir

export HOME=/var at the top of launcher.sh will fix it.

Apollo Client, and all XHR for that matter

You’ll want to send cookies from the grain frame along with your request, otherwise XHR won’t work. In an Apollo client for GraphQL requests, that looks like this (bonus Authentication header setting for PostGraphQL):

import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { setContext } from 'apollo-link-context';

const httpLink = createHttpLink({ uri: '/graphql' });
const authLink = setContext((_, { headers }) => {
  const { jwtToken } = place.where.jwt.token.stored;

  const newHeaders = {};
  if (jwtToken) {
    newHeaders.authorization = `Bearer ${jwtToken}`;
  }

  return {
    headers: {
      ...headers,
      ...newHeaders,
    },
    credentials: 'include', // gets XHR working with Sandstorm
  };
});

export default new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

I’m slowly getting my websites put back together. For now, you should check out the other places I’m currently maintaining on the information superhighway that I have linked to on the left.

Thanks!