Skip to content

Commit a29df04

Browse files
committed
feat(elixir:gsmlg): Add blog module api.
with: mix phx.gen.json --no-schema --no-context Content Blog blogs slug:string title:string date:date author:string content:text
1 parent fd73a6d commit a29df04

File tree

6 files changed

+207
-3
lines changed

6 files changed

+207
-3
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
defmodule GSMLGWeb.BlogController do
2+
use GSMLGWeb, :controller
3+
4+
alias GSMLG.Content
5+
alias GSMLG.Content.Blog
6+
7+
action_fallback GSMLGWeb.FallbackController
8+
9+
def index(conn, _params) do
10+
blogs = Content.list_blogs()
11+
render(conn, "index.json", blogs: blogs)
12+
end
13+
14+
def create(conn, %{"blog" => blog_params}) do
15+
with {:ok, %Blog{} = blog} <- Content.create_blog(blog_params) do
16+
conn
17+
|> put_status(:created)
18+
|> put_resp_header("location", Routes.blog_path(conn, :show, blog))
19+
|> render("show.json", blog: blog)
20+
end
21+
end
22+
23+
def show(conn, %{"id" => id}) do
24+
blog = Content.get_blog!(id)
25+
render(conn, "show.json", blog: blog)
26+
end
27+
28+
def update(conn, %{"id" => id, "blog" => blog_params}) do
29+
blog = Content.get_blog!(id)
30+
31+
with {:ok, %Blog{} = blog} <- Content.update_blog(blog, blog_params) do
32+
render(conn, "show.json", blog: blog)
33+
end
34+
end
35+
36+
def delete(conn, %{"id" => id}) do
37+
blog = Content.get_blog!(id)
38+
39+
with {:ok, %Blog{}} <- Content.delete_blog(blog) do
40+
send_resp(conn, :no_content, "")
41+
end
42+
end
43+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
defmodule GSMLGWeb.FallbackController do
2+
@moduledoc """
3+
Translates controller action results into valid `Plug.Conn` responses.
4+
5+
See `Phoenix.Controller.action_fallback/1` for more details.
6+
"""
7+
use GSMLGWeb, :controller
8+
9+
# This clause is an example of how to handle resources that cannot be found.
10+
def call(conn, {:error, :not_found}) do
11+
conn
12+
|> put_status(:not_found)
13+
|> put_view(GSMLGWeb.ErrorView)
14+
|> render(:"404")
15+
end
16+
end

elixir/gsmlg_umbrella/apps/gsmlg_web/lib/gsmlg_web/router.ex

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@ defmodule GSMLGWeb.Router do
2929
end
3030

3131
# Other scopes may use custom stacks.
32-
# scope "/api", GSMLGWeb do
33-
# pipe_through :api
34-
# end
32+
scope "/api", GSMLGWeb do
33+
pipe_through :api
34+
35+
resources "/blogs", BlogController, except: [:new, :edit]
36+
37+
end
3538

3639
# Enables LiveDashboard only for development
3740
#
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
defmodule GSMLGWeb.BlogView do
2+
use GSMLGWeb, :view
3+
alias GSMLGWeb.BlogView
4+
5+
def render("index.json", %{blogs: blogs}) do
6+
%{data: render_many(blogs, BlogView, "blog.json")}
7+
end
8+
9+
def render("show.json", %{blog: blog}) do
10+
%{data: render_one(blog, BlogView, "blog.json")}
11+
end
12+
13+
def render("blog.json", %{blog: blog}) do
14+
%{
15+
id: blog.id,
16+
slug: blog.slug,
17+
title: blog.title,
18+
date: blog.date,
19+
author: blog.author,
20+
content: blog.content
21+
}
22+
end
23+
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
defmodule GSMLGWeb.ChangesetView do
2+
use GSMLGWeb, :view
3+
4+
@doc """
5+
Traverses and translates changeset errors.
6+
7+
See `Ecto.Changeset.traverse_errors/2` and
8+
`GSMLGWeb.ErrorHelpers.translate_error/1` for more details.
9+
"""
10+
def translate_errors(changeset) do
11+
Ecto.Changeset.traverse_errors(changeset, &translate_error/1)
12+
end
13+
14+
def render("error.json", %{changeset: changeset}) do
15+
# When encoded, the changeset returns its errors
16+
# as a JSON object. So we just pass it forward.
17+
%{errors: translate_errors(changeset)}
18+
end
19+
end
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
defmodule GSMLGWeb.BlogControllerTest do
2+
use GSMLGWeb.ConnCase
3+
4+
import GSMLG.ContentFixtures
5+
6+
alias GSMLG.Content.Blog
7+
8+
@create_attrs %{
9+
author: "some author",
10+
content: "some content",
11+
date: ~D[2021-09-26],
12+
slug: "some slug",
13+
title: "some title"
14+
}
15+
@update_attrs %{
16+
author: "some updated author",
17+
content: "some updated content",
18+
date: ~D[2021-09-27],
19+
slug: "some updated slug",
20+
title: "some updated title"
21+
}
22+
@invalid_attrs %{author: nil, content: nil, date: nil, slug: nil, title: nil}
23+
24+
setup %{conn: conn} do
25+
{:ok, conn: put_req_header(conn, "accept", "application/json")}
26+
end
27+
28+
describe "index" do
29+
test "lists all blogs", %{conn: conn} do
30+
conn = get(conn, Routes.blog_path(conn, :index))
31+
assert json_response(conn, 200)["data"] == []
32+
end
33+
end
34+
35+
describe "create blog" do
36+
test "renders blog when data is valid", %{conn: conn} do
37+
conn = post(conn, Routes.blog_path(conn, :create), blog: @create_attrs)
38+
assert %{"id" => id} = json_response(conn, 201)["data"]
39+
40+
conn = get(conn, Routes.blog_path(conn, :show, id))
41+
42+
assert %{
43+
"id" => ^id,
44+
"author" => "some author",
45+
"content" => "some content",
46+
"date" => "2021-09-26",
47+
"slug" => "some slug",
48+
"title" => "some title"
49+
} = json_response(conn, 200)["data"]
50+
end
51+
52+
test "renders errors when data is invalid", %{conn: conn} do
53+
conn = post(conn, Routes.blog_path(conn, :create), blog: @invalid_attrs)
54+
assert json_response(conn, 422)["errors"] != %{}
55+
end
56+
end
57+
58+
describe "update blog" do
59+
setup [:create_blog]
60+
61+
test "renders blog when data is valid", %{conn: conn, blog: %Blog{id: id} = blog} do
62+
conn = put(conn, Routes.blog_path(conn, :update, blog), blog: @update_attrs)
63+
assert %{"id" => ^id} = json_response(conn, 200)["data"]
64+
65+
conn = get(conn, Routes.blog_path(conn, :show, id))
66+
67+
assert %{
68+
"id" => ^id,
69+
"author" => "some updated author",
70+
"content" => "some updated content",
71+
"date" => "2021-09-27",
72+
"slug" => "some updated slug",
73+
"title" => "some updated title"
74+
} = json_response(conn, 200)["data"]
75+
end
76+
77+
test "renders errors when data is invalid", %{conn: conn, blog: blog} do
78+
conn = put(conn, Routes.blog_path(conn, :update, blog), blog: @invalid_attrs)
79+
assert json_response(conn, 422)["errors"] != %{}
80+
end
81+
end
82+
83+
describe "delete blog" do
84+
setup [:create_blog]
85+
86+
test "deletes chosen blog", %{conn: conn, blog: blog} do
87+
conn = delete(conn, Routes.blog_path(conn, :delete, blog))
88+
assert response(conn, 204)
89+
90+
assert_error_sent 404, fn ->
91+
get(conn, Routes.blog_path(conn, :show, blog))
92+
end
93+
end
94+
end
95+
96+
defp create_blog(_) do
97+
blog = blog_fixture()
98+
%{blog: blog}
99+
end
100+
end

0 commit comments

Comments
 (0)