Knd_Lepe
I’m working on an email API service, Already got the Ash action to send email working in iex.
My send_email action is a custom action that will perfom some non standard CRUD. Got 2 create actions and the calls to api ask for attributes from wrong create action. As for now just trying to get the Ok atom
My resource
defmodule Eppa.Accounts.Servicios do
use Ash.Resource,
otp_app: :eppa,
domain: Eppa.Accounts,
data_layer: AshPostgres.DataLayer,
extensions: [AshJsonApi.Resource]
json_api do
type "servicios"
end
postgres do
table "servicios"
repo Eppa.Repo
references do
reference :user, index?: true, on_delete: :delete
end
end
actions do
defaults [:read, :destroy]
create :create do
primary? true
accept [:tipo, :creditos_disponibles, :vigencia]
change relate_actor(:created_by, allow_nil?: true)
change relate_actor(:updated_by, allow_nil?: true)
end
update :update do
primary? true
accept [:creditos_disponibles, :vigencia]
change relate_actor(:updated_by, allow_nil?: true)
end
create :send_email do
# Definición de argumentos que se esperan recibir vía JSON
argument :user_email, :ci_string, allow_nil?: false
argument :destinatario, :ci_string, allow_nil?: false
argument :cc, {:array, :ci_string}, default: []
argument :asunto, :string, allow_nil?: false
argument :contenido_html, :ci_string, allow_nil?: false
argument :attachments, {:array, :map}, default: []
argument :plantilla_id, :ci_string, allow_nil?: true
# Testing - "
{:ok, "ok"}
end
end
attributes do
uuid_v7_primary_key :id
attribute :tipo, :atom do
constraints one_of: [:correos, :sms]
allow_nil? false
public? true
end
attribute :creditos_disponibles, :integer do
allow_nil? false
default 0
public? true
end
attribute :vigencia, :datetime do
allow_nil? false
public? true
end
attribute :user_id, :uuid do
end
create_timestamp :inserted_at
update_timestamp :updated_at
end
relationships do
belongs_to :created_by, Eppa.Accounts.User
belongs_to :updated_by, Eppa.Accounts.User
belongs_to :user, Eppa.Accounts.User do
allow_nil? false
end
end
end
My domain
defmodule Eppa.Accounts do
use Ash.Domain, otp_app: :eppa, extensions: [AshJsonApi.Domain]
json_api do
routes do
base_route "/servicios", Eppa.Accounts.Servicios do
post :send_email
end
end
end
resources do
resource Eppa.Accounts.Token
resource Eppa.Accounts.User do
define :create_user, action: :register_with_password
define :update_user, action: :update_user
define :get_users, action: :read
define :get_user_by_id, action: :read, get_by: :id
define :get_user_by_email, action: :read, get_by: :email
define :get_users_with_services, action: :read
end
resource Eppa.Accounts.Servicios do
define :get_servicios, action: :read
define :create_servicio, action: :create
define :send_email, action: :send_email
define :get_servicio_by_id, action: :read, get_by: :id
end
resource Eppa.Accounts.Profile do
define :create_perfil, action: :create
define :update_perfil, action: :update
define :get_profiles, action: :read
define :get_perfil_by_id, action: :read, get_by: :id
end
end
authorization do
# disable using the authorize?: false flag when calling actions
authorize :always
end
end
Router
defmodule EppaWeb.Router do
use EppaWeb, :router
use AshAuthentication.Phoenix.Router
import AshAuthentication.Plug.Helpers
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, html: {EppaWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :load_from_session
end
pipeline :api do
plug :accepts, ["json"]
plug :load_from_bearer
plug :set_actor, :user
end
scope "/api/json" do
pipe_through [:api]
forward "/swaggerui", OpenApiSpex.Plug.SwaggerUI,
path: "/api/json/open_api",
default_model_expand_depth: 4
forward "/", EppaWeb.AshJsonApiRouter
end
scope "/", EppaWeb do
pipe_through :browser
ash_authentication_live_session :authenticated_routes do
live "/dashboard", DashboardLive, :index
live "/users", UserLive.Index, :index
live "/users/new", UserLive.Index, :new
live "/users/:id/edit", UserLive.Index, :edit
live "/users/:id", UserLive.Show, :show
live "/users/:id/show/edit", UserLive.Show, :edit
live "/users/:id/assign_profile", UserLive.Index, :assign_profile
live "/users/:id/servicios", EppaWeb.UserLive.Servicios, :index
live "/profiles", ProfileLive.Index, :index
live "/profiles/new", ProfileLive.Index, :new
live "/profiles/:id/edit", ProfileLive.Index, :edit
live "/profiles/:id", ProfileLive.Show, :show
live "/profiles/:id/show/edit", ProfileLive.Show, :edit
# live "/services", ServiceAssignmentLive.Index, :index
# live "/services/new", ServiceAssignmentLive.Index, :new
live "/services", ServicesLive.Index, :index
live "/services/:id/creditos", ServiceLive.Creditos, :creditos
# in each liveview, add one of the following at the top of the module:
#
# If an authenticated user must be present:
# on_mount {EppaWeb.LiveUserAuth, :live_user_required}
#
# If an authenticated user *may* be present:
# on_mount {EppaWeb.LiveUserAuth, :live_user_optional}
#
# If an authenticated user must *not* be present:
# on_mount {EppaWeb.LiveUserAuth, :live_no_user}
end
end
scope "/", EppaWeb do
pipe_through :browser
# live "/sign-in", SignInLive, :index
get "/", RedirectController, :to_sign_in
# get "/", PageController, :home
auth_routes AuthController, Eppa.Accounts.User, path: "/auth"
sign_out_route AuthController
# Remove these if you'd like to use your own authentication views
sign_in_route register_path: "/register",
reset_path: "/reset",
auth_routes_prefix: "/auth",
on_mount: [{EppaWeb.LiveUserAuth, :live_no_user}],
overrides: [EppaWeb.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default]
# Remove this if you do not want to use the reset password feature
reset_route auth_routes_prefix: "/auth",
overrides: [EppaWeb.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default]
end
# Other scopes may use custom stacks.
# scope "/api", EppaWeb do
# pipe_through :api
# end
# Enable LiveDashboard and Swoosh mailbox preview in development
if Application.compile_env(:eppa, :dev_routes) do
# If you want to use the LiveDashboard in production, you should put
# it behind authentication and allow only admins to access it.
# If your application does not have an admins-only section yet,
# you can use Plug.BasicAuth to set up some basic authentication
# as long as you are also using SSL (which you should anyway).
import Phoenix.LiveDashboard.Router
scope "/dev" do
pipe_through :browser
live_dashboard "/dashboard", metrics: EppaWeb.Telemetry
forward "/mailbox", Plug.Swoosh.MailboxPreview
end
end
end
API CALL
{
"data":{
"type":"servicios",
"attributes": {
"user_email": "knd_rt@hotmail.com",
"destinatario": "blitzlepe@gmail.com" ,
"cc":[
"cande.lepe@agustindeiturbide.com"
],
"asunto":"Prueba desde Insomnia",
"contenido_html":"Su pinche madre, si jalo !!!",
"attachments":[]
}
}
}
Response
{
"errors": [
{
"code": "required",
"id": "c5e78bdc-fc81-421e-a9b9-cf71c85256bb",
"meta": {},
"status": "400",
"title": "Required",
"source": {
"pointer": "/data/attributes/tipo"
},
"detail": "is required"
},
{
"code": "required",
"id": "c6c953b2-0925-4ada-9c8f-fd682c248b99",
"meta": {},
"status": "400",
"title": "Required",
"source": {
"pointer": "/data/attributes/vigencia"
},
"detail": "is required"
}
],
"jsonapi": {
"version": "1.0"
}
}```
Trending in Questions
Hello!
Suppose you are building workflow (order / task / payment) processing system with the following requirements:
Each workflow con...
New
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app?
Looking for hints regarding:
Addi...
New
Hi all, I wanted to ask how the community is dealing with post-release steps.
Today we have Ecto migrations, which make sure that the db...
New
Kia ora,
We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
Hello,
I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










First 7 of 7 Posts
zachdaniel
Looking at this, I think you need to revisit your action basics before working on
AshJsonApi. Actions don’t have “return values” (except for generic actions, but that is inside therunfunction) i.e that{:ok, "ok"}is not the return of the action (it just does nothing in fact, its evaluated at compile time).The arguments also on their own don’t do anything, you need to do something with them like
change set_attribute(:some_attr, arg(:some_arg))(as an example).The reason you are getting errors about those fields being required is because those attributes are themselves required, and your action is not doing anything to set them:
Knd_Lepe
Thanks, I got api working (it receives json payload and persists it to postgres db, really cool!) Now, I want to execute some logic before_action and after_action, but not sure if my approach is correct, should I move this to a generic action??:
Api call
Response
zachdaniel
Nope, that’s fine to do that way
I would suggest consolidating it to a change module, where you can add both hooks in one place.
Knd_Lepe
Ok, looking for another way to do it, it looks I can´t pipe the “after_action”, if I do the response is:
zachdaniel
The function in after_action takes two arguments,
Ash.Changeset.after_action(changeset, fn changeset, result -> end)Knd_Lepe
Cool, you really helped me, thanks!!
Knd_Lepe
In the end I just used after_action, the only “issue” was to update an attribute that was just created but not persisted to db yet.
This did the magic