Yax

Yet Another Query Syntax (but X because Elixir)

…for Elixir

……and Ecto

………and Bodyguard

N.B - you’re reading the readme for the very first commit on this project

In no way is this production ready, or even all that good. Even this readme is just some verbal diarrhea, written down.

This package just explores a few ideas:

Yax does that all for you. Yax converts a URL query schema into a properly scoped Ecto query. (Immense amounts of kudos and respect to the folks behind Postgrest for the API, it’s the best in its class I’ve used and heavily inspires the query syntax here. If you need a pure data play, then use Postgrest. If you need integration into an application layer…keep reading.

In The Wild

Let your controllers look like this:

defmodule FooWeb.PostController do 
  plug Yax.Plug, Foo.Posts.Post
  def index(conn, _params), do: json(conn, Yax.all(conn))
  def show(conn, _params) do json(conn, Yax.one(conn))
end

and let your client decide what they need:

https://www.foo.com/api/posts?select=id,title,body,comments(inserted_at),comments.users(avatar,name)

Yax will introspect your Ecto schemas, preload your assocations, scope everything, and give you back just what you asked for. And just what your user is allowed.

Suddenly, your GraphQL Query definitions have turned back into good old Phoenix routes. We can compose them, add them to pipelines. They become part of the Phoenix ecosystem, not an entity on their own. Yet we still retain the consistent schema and reliable response types that GQL offers.

It doesn’t end there. (well, it does right now, but this is definitely something that needs to exist:)

Why do we still need controllers? Phoenix.Router doesn’t ask for them. A controller is just a Plug after all. Why not just whack this in your Router.ex?

What controller?

  get("/posts/:id", Yax.Controller, Foo.Posts.Post)
  get("/posts", Yax.Controller, Foo.Posts.Post)

I mean really we don’t even need that first route. GET /posts?id=1 is the same as GET /posts/1, right? If anything it’s clearer. Well, sort of.

Suddenly it’s all disappeared. You’ve gone from Ecto model -> Context <-> Policy/Scope -> Controller -> Router -> User

Why don’t we just go Ecto model -> Router -> User?

That’s Yax.

/brain dump

Like the idea? Get in touch. We’re using this for Codex, so expect active development.

Installation

If available in Hex, the package can be installed by adding yax to your list of dependencies in mix.exs:

def deps do
  [
    {:yax, "~> 0.1.0"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/yax.