Custom payload body for post endpoint

How can create a generic action so that the exposed endpoint would accept the following payload:
{
"event": "event",
"data": {....}
}
{
"event": "event",
"data": {....}
}
I tried the following:
action :create, :struct do
constraints instance_of: __MODULE__
argument :event, :string, allow_nil?: true
argument :data, :map, allow_nil?: true

run fn input, _ ->
dbg(input)
%__MODULE__{event: input.event, data: input.data}
end
end
action :create, :struct do
constraints instance_of: __MODULE__
argument :event, :string, allow_nil?: true
argument :data, :map, allow_nil?: true

run fn input, _ ->
dbg(input)
%__MODULE__{event: input.event, data: input.data}
end
end
but I'm getting this error when I try to submit:
{
"errors": [
{
"code": "invalid_body",
"id": "0fa87573-8d32-48f6-8ec7-754e2db986a2",
"meta": {},
"status": "400",
"title": "InvalidBody",
"source": {
"pointer": "/event"
},
"detail": "Expected only defined properties, got key [\"event\"]."
}
],
"jsonapi": {
"version": "1.0"
}
}
{
"errors": [
{
"code": "invalid_body",
"id": "0fa87573-8d32-48f6-8ec7-754e2db986a2",
"meta": {},
"status": "400",
"title": "InvalidBody",
"source": {
"pointer": "/event"
},
"detail": "Expected only defined properties, got key [\"event\"]."
}
],
"jsonapi": {
"version": "1.0"
}
}
Solution:
But yeah TBH for webhooks I typically just write controllers
Jump to solution
12 Replies
ZachDaniel
ZachDaniel4mo ago
How are you setting up the route? If you are using post ... then it will attempt to make it an idiomatic JSON:API route Use route/3 for fully custom logic and see the generated open api spec/swagger docs for what shape the API expects.
ggarciajr
ggarciajrOP4mo ago
This is how I defined the route in the domain
json_api do
routes do
base_route "/events", MyDomain.Resource do
post :create
end
end
end
json_api do
routes do
base_route "/events", MyDomain.Resource do
post :create
end
end
end
ggarciajr
ggarciajrOP4mo ago
It improved a bit, but it is still wrapping everything in a data object
{
"data": {
"data": {},
"event": "string"
}
}
{
"data": {
"data": {},
"event": "string"
}
}
the only change I made was to replace the post :create block I posted above by route :post, "/path", :create
ZachDaniel
ZachDaniel4mo ago
Hmm...are you sure its not {"result": {....}}? Its actually data.data? oh, nvm result objects default to false. right, its probably because of the way that it serializes it What if you just do
action :create, :map do
argument :event, :string, allow_nil?: true
argument :data, :map, allow_nil?: true

run fn input, _ ->
dbg(input)
%{event: input.event, data: input.data}
end
end
action :create, :map do
argument :event, :string, allow_nil?: true
argument :data, :map, allow_nil?: true

run fn input, _ ->
dbg(input)
%{event: input.event, data: input.data}
end
end
? Its been a bit since I've been in that code, sorry 😄
ggarciajr
ggarciajrOP4mo ago
Nah, I'm still seing the arguments wrapped in the data object
No description
ggarciajr
ggarciajrOP4mo ago
I wonder if it is not easier to just write a regular phoenix controller to call the ash domain in this case. Given it is for a webhook I have no control over
ZachDaniel
ZachDaniel4mo ago
Yep, you definitely can. And also, sorry, I didn't realize you were talking about the arguments, not the output
Solution
ZachDaniel
ZachDaniel4mo ago
But yeah TBH for webhooks I typically just write controllers
ZachDaniel
ZachDaniel4mo ago
AshJsonApi was designed to help build JSON:API compliant APIs i.e for serving public APIs and/or building applications etc.
ggarciajr
ggarciajrOP4mo ago
makes total sense. And thanks for helping me navigating through my newbie questions.
ZachDaniel
ZachDaniel4mo ago
My pleasure 🙇‍♂️

Did you find this page helpful?