--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
like graphql?
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
The problemI know how to implement a REST API and interrogate that API from Elm but that seams very low level.
I was curious about a language abstraction that would isolate my Elm program from the actual database strategy.How do you approach dealing with the databases? What is your strategy?What options are there?
Do you have any pointers to interesting perspective/approaches?
I've been using absinthe on the server side and I am able to control access permissions quite well for GraphQL hosting, though I am using a custom permission library that ties to our local LDAP server so that code would not be generically useful to release.
But yes, I am a fan of GraphQL. I just expose 'functionality', not raw tables. Many of my GraphQL calls do not map to a database table but rather potentially multiple (or even none in some cases).
On Wednesday, October 19, 2016 at 4:39:00 PM UTC+1, OvermindDL1 wrote:I've been using absinthe on the server side and I am able to control access permissions quite well for GraphQL hosting, though I am using a custom permission library that ties to our local LDAP server so that code would not be generically useful to release.Sounds interesting. Is hooking custom permissions into graphql part of the graphql spec? Or is it some mechanism specific to absinthe that lets you do this?
@desc "An item"
object :item do
field :id, :id
field :name, :string
end
query do
field :item, :item do
arg :id, non_null(:id)
resolve fn %{id: item_id}, _ ->
{:ok, @items[item_id]}
end
end
end
@perm true = user |> can?(select(%Perms.WhateverPerm{id: id}))
Also, is graphql just for fetching data? Or it also allows you to create new data on the server, or make updates to existing data?
But yes, I am a fan of GraphQL. I just expose 'functionality', not raw tables. Many of my GraphQL calls do not map to a database table but rather potentially multiple (or even none in some cases).Yes, I also do not expose raw tables in the API, each entity is typically a small document tree which maps to >1 table. Also depending on what you fetch and what condition you use to filter the query results I would expect hitting >1 table to be quite common.
Absinthe handles all the nasty parts of GraphQL though, the combining of queries, the real-time type documentation generation, etc... etc...
The core idea is to remove the boilerplate of always having to define encoder, decoder and schema. Would love to chat.
I'm sorry to link drop, but I've been doing a bit of work on a library to remove some of the boilerplate when writing client code for a REST API. The library is currently locked in / specific to what is called PostgREST, but I imagine that the patterns could be applied to any REST backend. Check it out: https://github.com/john-kelly/elm-postgrest/
The core idea is to remove the boilerplate of always having to define encoder, decoder and schema. Would love to chat.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hi John,
The project you linked to looks great.
How do you deal with references? (entities referencing other entities)
On Thu, Oct 20, 2016 at 9:19 PM, John Kelly <jdrke...@gmail.com> wrote:
I'm sorry to link drop, but I've been doing a bit of work on a library to remove some of the boilerplate when writing client code for a REST API. The library is currently locked in / specific to what is called PostgREST, but I imagine that the patterns could be applied to any REST backend. Check it out: https://github.com/john-kelly/elm-postgrest/
The core idea is to remove the boilerplate of always having to define encoder, decoder and schema. Would love to chat.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
My issue is in fact related to mutually recursive types, it's just that my types are truly infinite. According to the linked doc about recursive types:"Somewhere in that cycle, you need to define an actual type to end the infinite expansion." Which mine does not.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
I'm coming to the sad realization that an api like this is simply not possible:
```session =resource "sessions"{ id = int "id", speaker_id = int "speaker_id", start_time = string "start_time", end_time = string "end_time", location = string "location", session_type = int "session_type", speaker = hasOne (\_ -> speaker)}speaker =resource "speakers"{ id = int "id", name = string "name", sessions = hasMany (\_ -> session)}
```
Any ideas? I was under the impression that the lambda would fix the recursive type issue, but now i see that elm still has trouble with the type of the record.
I'm sorry to link drop, but I've been doing a bit of work on a library to remove some of the boilerplate when writing client code for a REST API. The library is currently locked in / specific to what is called PostgREST, but I imagine that the patterns could be applied to any REST backend. Check it out: https://github.com/john-kelly/elm-postgrest/The core idea is to remove the boilerplate of always having to define encoder, decoder and schema. Would love to chat.
I'm sorry to link drop, but I've been doing a bit of work on a library to remove some of the boilerplate when writing client code for a REST API. The library is currently locked in / specific to what is called PostgREST, but I imagine that the patterns could be applied to any REST backend. Check it out: https://github.com/john-kelly/elm-postgrest/The core idea is to remove the boilerplate of always having to define encoder, decoder and schema. Would love to chat.
What options are there?
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
What do you do with fields in the json that are missing or null? I can see for example that for an 'int' you just use Decode.int as the decoder, so I guess you will get a Result.Err and fail when the value is missing?
Mostly field names will match record fields, but sometimes they might not, so having an ability to name them differently to the name of the field in the Elm record could be useful.
I'm more interested in how one would solve this in a multilayer system where the actual remote persistence is abstracted from the app.
The actual remote persistence might be implemented with REST, or it might be some kind of websockets thing.
It might involve a SQL database, or maybe a NoSQL database.
It might be something like Datomic.
I'm interested in how would one implement this abstraction, this separation of concerns.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Think about the role that a ORM is playing. What I want to understand is what would a functional equivalent would look like in Elm.
What would sit above graphQL or REST or some other lower level tech?
Another way to look at this would be to take the Json.Decode/Encode as example and imagine that one has the equivalent of a Decoder only that it would be some kind of a descriptor used by some lower level library that does the queries based on that descriptor data.Maybe this descriptor uses something like Datalog.
I cannot provide sample code because I don't have a clear idea how the API could look.
Think about the role that a ORM is playing. What I want to understand is what would a functional equivalent would look like in Elm.
What would sit above graphQL or REST or some other lower level tech?
Another way to look at this would be to take the Json.Decode/Encode as example and imagine that one has the equivalent of a Decoder only that it would be some kind of a descriptor used by some lower level library that does the queries based on that descriptor data.Maybe this descriptor uses something like Datalog.
Another way to think about this is to try to imagine what would it take to reduce the cognitive overload of a beginner that does not really care that much about how the data is retrieved/saved remotely but cares to have the functionality present.
Unless I'm mistaken, that is the goal I have set for elm-postgrest. The equivalent of a `Decoder` in my library is a `Query`.
I am unsure if you are suggesting that a general API could exist which encompasses all backends. I originally tried to create a general API, but quickly came to the conclusion that such a task was quite tricky.
Overall, (once again sorry for the plug) I think that elm-postgrest has made some decent steps in the right direction, and I think a more thorough audit / usage of the code could bring this conversation to another level. (also, for those too lazy to look up PostgREST -- it's basically the same as graphql -- but 0 coding required. some fancy people might say "isomorphic")
I think the model that has the lowest 'cognitive overload' for a beginner is to simply work with the request/response model of HTTP, and to request data when needed, and POST data when you want to update something. Its a pretty obvious abstraction and fits nicely with Elms event handling.
I would say that persistence is not really the concern of the UI. It is nice to experiment with clever technologies that let the UI code build whatever query it needs, or update whatever data it needs but you have to remember that most of the time your UI is not runnning in a trusted environment - in the case of Elm/javascript its running in someones browsers. Therefore it is almost a necessity that you create an API and think carefully about what data can be seen through it, and what data updated by whom. That said, Overmind has provided some clear details of how access rights to data are protected when using graphql. Not sure if PostgREST provides any assistance with access rights?
Coming back to the 'cognitive overload'... I have found that simply setting up and working with the HTTP requests in Elm is a lot of work - you need encoders, decoders, functions to help build the requests, functions to help decode the responses and deal with errors, msgs to pass to update functions to update your model based on responses and so on. There is a lot of boilerplate in simply working with an API, although this has nothing to do with databases and persistence as such.
Why not just freeze dry your entire application state to some key/value store (on every update), then you have a simple way to rehydrate the whole application after a period of inactivity?
Browsers can provide a trusted environment through the use of https. This is what Gmail and Facebook and all other webapps are doing.
Why not just freeze dry your entire application state to some key/value store (on every update), then you have a simple way to rehydrate the whole application after a period of inactivity?This is not an option on large datasets. I gave the example with the Music database in an earlier message specifically to address this.
Pagination is a very real concern that seldom appears in toy examples.
On Tuesday, October 25, 2016 at 8:08:11 AM UTC+1, Peter Damoc wrote:Browsers can provide a trusted environment through the use of https. This is what Gmail and Facebook and all other webapps are doing.What I mean is, there is nothing to stop whoever is running your application from subverting it.
If your 'persistence API' requires the application to behave correctly in order to not store invalid or maliciously altered data, you cannot guarantee that.
I do think that these server side responsibilities are not really within the domain of Elm.
On Tue, Oct 25, 2016 at 11:27 AM, 'Rupert Smith' via Elm Discuss <elm-d...@googlegroups.com> wrote:If your 'persistence API' requires the application to behave correctly in order to not store invalid or maliciously altered data, you cannot guarantee that.This actually sounds more like a challenge to be faced rather that a technical impossibility.
Maybe some kind of declarative access control embedded in a shared schema could solve this.
I do think that these server side responsibilities are not really within the domain of Elm.Look at what happened with Javascript. Once it got useful in the client people wanted it on the server and then we got Node.
We are nowhere near the popularity of javascript and yet, I already see frequent enough questions about using Elm on the server-side.
There are two ways to address this:1. allocating resources to making Elm viable on the server
2. making the server part as small and automatic as possible as to not require much coding.
To me, option 2 is much more attractive.
So to phrase what I previously said a different way, a database is the wrong level of abstraction to be shooting for.
I cannot provide sample code because I don't have a clear idea how the API could look.
Think about the role that a ORM is playing. What I want to understand is what would a functional equivalent would look like in Elm.
As best I can, I try to look at the system as use cases and events.With legacy systems, we are tied to a normalized data model (which is really designed for writing and not reading), so for queries we have to "project" from that normalized data model into another model.
But the place I'd really like to get to is storing the system's events, and creating whatever models are necessary to answer queries and fulfill use cases from those events. AKA Event Sourcing. I am finally getting to do this on a new project. Our existing systems will stay with a normalized data model for the foreseeable future as the cost of change is too high.But I still try to take the principles of using business-specific events (like StudentRegistered or PaymentDeclined) in my business logic, then translate those into database calls when they are sent for persistence. That also allows me to use those events to update secondary models or trigger other logic. The common alternative, just updating state and doing `repository.Save()` makes it harder to hook into specific business happenings.
For example, if a user account must have an email address associated with it, if there is validation on the format of the email address and it cannot be null, then there is not need to write a specific transactional end-point to allow a user to update their email address, you can just let them modify and save the account record and they can still only perform that operation in a way that produces correct data.I take your point though about being able to hook into changes relating to specific events.
There is a danger in focusing on data over use cases. It's not a guarantee that you make this mistake (I have), but you know you've gone too far with it when most workflows are Load/Edit/Save (or Create/Save). And the user is left to know what field to change to have a specific effect in the system. I've seen this termed as data-centric. Seems okay at first but after a few years in production this leads to long user training times, brittle workflows, and high support loads.
On Friday, October 28, 2016 at 6:26:46 PM UTC+1, Kasey Speakman wrote:As best I can, I try to look at the system as use cases and events.With legacy systems, we are tied to a normalized data model (which is really designed for writing and not reading), so for queries we have to "project" from that normalized data model into another model.My understanding of normalization is that its purpose is to avoid duplicating data, and by avoiding duplication reduce the chance of errors in order to help ensure the quality of stored data.
"Explicit is better than implicit."
-- Tim Peters
So here's a concrete example of how we did it wrong in our legacy system. To close a trainee's registration as "No Show", an employee has to create an exam against that registration and grade it as 1%. This is an implicit concept which our employees and our software understand as "No Show". Instead of making it explicit by programming in a No Show button/action/status, we have to program the employees (current and future) to recognize this situation.
However, looking at a fresh system that one might want to design it seams to me like there are 3 possible layers
Layer 3. Business Objects Layer - concerned with validity of state transactionsLayer 2. Data Modeling Layer - concerned with what needs to be persistentLayer 1. Storage Layer - concerned with connections, locations, raw entity storage
Layer 1 would be the implementation of the library I would like to have in Elm. Ideally, something similar to Datomic.
Layer 2 would be implemented by the user using Layer 1 in a declarative way similar to Json.Decode
Layer 3 would be implemented by the user using Layer 2 in a way that is similar to the Elm Architecture (layer 2 Model + some update)What do you think?
Am I misunderstanding what you described?
Are you talking Elm running server side for this?
On Tue, Nov 1, 2016 at 11:30 AM, 'Rupert Smith' via Elm Discuss <elm-d...@googlegroups.com> wrote:Are you talking Elm running server side for this?I haven't thought about that too much.
In theory, there should be some kind of schema common to both the front-end and the back end that would capture authorization requirements but, ideally it would be something that sits mainly in the client.
Ideally it would be something similar to using Horizon.
The server side should be mainly automated.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
It is silly, and I don't know why it was done this way. But that's the world I live in now. It's easy to justify one case at a time, but all tolled it adds up.As far as "layers", you should check out these two posts in order.
It would be awesome to have a more complex but practical example that captures this.
The reservation scenario from the second post looks like an interesting use-case.
I will think more about it.
On Tue, Nov 1, 2016 at 3:33 PM, Kasey Speakman <kjspe...@gmail.com> wrote:Oh, and yes, most of these layers are on the server side if we are talking about an Elm client application. Generally speaking, the client app serves to collect and prepare data to submit use cases. So it reads data from an API and submits data to an API.
...
There is clever stuff we can do with the data-centric approach, in terms of using generic CRUD APIs, or tailoring graphql expressions to fetch or update particular paths in the data model. It is a bit harder to see how clever tricks can be used to cut down the larger amount of work that needs to be done with the service-oriented approach. I think by shifting from doing the clever bit at runtime to doing it at compile time and using code generation techniques, it is doable.
In a new project, we are going for something like this.
On Tue, Nov 1, 2016 at 2:25 AM, Kasey Speakman <kjspe...@gmail.com> wrote:So here's a concrete example of how we did it wrong in our legacy system. To close a trainee's registration as "No Show", an employee has to create an exam against that registration and grade it as 1%. This is an implicit concept which our employees and our software understand as "No Show". Instead of making it explicit by programming in a No Show button/action/status, we have to program the employees (current and future) to recognize this situation.Wow... this is so silly that it almost looks like a joke. Unfortunately, I've seen enough to know that it happens.
On Thursday, October 20, 2016 at 3:55:45 AM UTC-6, Rupert Smith wrote:On Wednesday, October 19, 2016 at 8:23:46 PM UTC+1, OvermindDL1 wrote:Absinthe handles all the nasty parts of GraphQL though, the combining of queries, the real-time type documentation generation, etc... etc...What database do you use? Is it always a SQL database or can Absinthe work with noSQL too?Also, when it combines queries, does it translate that down into an efficient SQL join? Or does it process the joins outside of the database, in the server code?It is storage agnostic, and technically you do not even need a storage, remember that GraphQL calls are basically just RPC, you could have a `fib` GraphQL call that just calculates that.The database I use is PostgreSQL via the Ecto library though. Absinthe is database and all agnostic, however it does have a section at http://absinthe-graphql.org/guides/ecto-best-practices/ talking about the best ways to use it with ecto for optimization purposes, and they do have planned more detailed ecto integration in the future, but for now it is do-it-yourself (which I prefer, means I can use my permission system to only return specific things that they have access to). Absinthe itself does not combine queries, it has no clue what a query is, it just gives the graphql 'function call' setup to you, what the user requested, what they passed in, etc... With proper Ecto work all the joins are in-database. With ecto it is trivial to build up database joins in piecemeal, so it works fantastically with graphql.
--
You received this message because you are subscribed to a topic in the Google Groups "Elm Discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elm-discuss/igxYW0Q3Clw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elm-discuss+unsubscribe@googlegroups.com.