Skip to content

Commit e11984c

Browse files
committed
Initial commit.
0 parents  commit e11984c

File tree

13 files changed

+398
-0
lines changed

13 files changed

+398
-0
lines changed

.formatter.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
4+
]

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github: [codedge-llc]

.github/workflows/ci.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
pull_request:
7+
branches: ["main"]
8+
9+
jobs:
10+
prettier:
11+
name: Prettier
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v3
16+
with:
17+
ref: ${{ github.head_ref }}
18+
- name: Use Node.js 18.x
19+
uses: actions/setup-node@v3
20+
with:
21+
node-version: 18.x
22+
- name: Install Prettier
23+
run: npm install --global prettier
24+
- name: Run Prettier
25+
run: prettier --check --no-error-on-unmatched-pattern "**/*.{json,md,yml,yaml}"
26+
check:
27+
name: Format/Credo
28+
runs-on: ubuntu-latest
29+
steps:
30+
- uses: actions/checkout@v3
31+
- name: Set up Elixir
32+
uses: erlef/setup-beam@v1
33+
with:
34+
elixir-version: "1.18.0"
35+
otp-version: "27.0.1"
36+
- name: Restore dependencies cache
37+
uses: actions/cache@v3
38+
with:
39+
path: deps
40+
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
41+
restore-keys: ${{ runner.os }}-mix-
42+
- name: Install dependencies
43+
run: mix deps.get
44+
- name: Run formatter
45+
run: mix format --check-formatted
46+
- name: Run Credo
47+
run: mix credo
48+
test:
49+
name: Test
50+
runs-on: ubuntu-latest
51+
steps:
52+
- uses: actions/checkout@v3
53+
- name: Set up Elixir
54+
uses: erlef/setup-beam@v1
55+
with:
56+
elixir-version: "1.18.0"
57+
otp-version: "27.0.1"
58+
- name: Restore dependencies cache
59+
uses: actions/cache@v3
60+
with:
61+
path: deps
62+
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
63+
restore-keys: ${{ runner.os }}-mix-
64+
- name: Install dependencies
65+
run: mix deps.get
66+
- name: Run tests
67+
env:
68+
TERM: xterm
69+
run: mix test

.gitignore

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# The directory Mix will write compiled artifacts to.
2+
/_build/
3+
4+
# If you run "mix test --cover", coverage assets end up here.
5+
/cover/
6+
7+
# The directory Mix downloads your dependencies sources to.
8+
/deps/
9+
10+
# Where third-party dependencies like ExDoc output generated docs.
11+
/doc/
12+
13+
# If the VM crashes, it generates a dump, let's ignore it too.
14+
erl_crash.dump
15+
16+
# Also ignore archive artifacts (built via "mix archive.build").
17+
*.ez
18+
19+
# Ignore package tarball (built via "mix hex.build").
20+
jsend-*.tar
21+
22+
# Temporary files, for example, from tests.
23+
/tmp/

.tool-versions

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
elixir 1.18.0-otp-27
2+
erlang 27.2

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## v0.1.0 - 2024-12-26
9+
10+
Initial release.

LICENSE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Codedge LLC (https://www.codedge.io/)
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Jsend
2+
3+
**TODO: Add description**
4+
5+
## Installation
6+
7+
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
8+
by adding `jsend` to your list of dependencies in `mix.exs`:
9+
10+
```elixir
11+
def deps do
12+
[
13+
{:jsend, "~> 0.1.0"}
14+
]
15+
end
16+
```
17+
18+
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
19+
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
20+
be found at <https://hexdocs.pm/jsend>.
21+

lib/jsend.ex

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
defmodule JSend do
2+
@moduledoc """
3+
JSend API response structure.
4+
5+
Read the specification at [omniti-labs/jsend](https://github.com/omniti-labs/jsend).
6+
"""
7+
8+
@type t :: %__MODULE__{
9+
code: String.t() | integer() | nil,
10+
data: map(),
11+
status: String.t(),
12+
message: String.t() | nil
13+
}
14+
15+
@enforce_keys [:status]
16+
defstruct status: nil, data: %{}, message: nil, code: nil
17+
18+
@success "success"
19+
@fail "fail"
20+
@error "error"
21+
22+
@doc ~S"""
23+
Constructs a success response.
24+
25+
## Examples
26+
27+
iex> JSend.success()
28+
%JSend{status: "success", data: %{}, code: nil, message: nil}
29+
30+
iex> JSend.success(%{id: 1})
31+
%JSend{status: "success", data: %{id: 1}, code: nil, message: nil}
32+
"""
33+
@spec success(map()) :: t()
34+
def success(data \\ %{}) do
35+
new(@success, data)
36+
end
37+
38+
@doc ~S"""
39+
Constructs a failure response.
40+
41+
## Examples
42+
43+
iex> JSend.fail()
44+
%JSend{status: "fail", data: %{}, code: nil, message: nil}
45+
46+
iex> JSend.fail(%{name: "too short"})
47+
%JSend{status: "fail", data: %{name: "too short"}, code: nil, message: nil}
48+
"""
49+
@spec fail(map()) :: t()
50+
def fail(data \\ %{}) do
51+
new(@fail, data)
52+
end
53+
54+
@doc ~S"""
55+
Constructs an error response.
56+
57+
## Examples
58+
59+
iex> JSend.error("Internal server error")
60+
%JSend{status: "error", data: %{}, code: nil, message: "Internal server error"}
61+
62+
iex> JSend.error("Internal server error", 500)
63+
%JSend{status: "error", data: %{}, code: 500, message: "Internal server error"}
64+
65+
iex> JSend.error("Internal server error", 500, %{request: :econnrefused})
66+
%JSend{
67+
status: "error",
68+
data: %{request: :econnrefused},
69+
code: 500,
70+
message: "Internal server error"
71+
}
72+
"""
73+
@spec error(String.t(), String.t() | integer() | nil, map()) :: t()
74+
def error(message, code \\ nil, data \\ %{}) do
75+
%__MODULE__{status: @error, code: code, message: message, data: data}
76+
end
77+
78+
@spec new(String.t(), map()) :: t()
79+
defp new(status, data) do
80+
%__MODULE__{status: status, data: data}
81+
end
82+
end
83+
84+
case Code.ensure_compiled(JSON.Encoder) do
85+
{:module, module} ->
86+
defimpl module, for: JSend do
87+
def encode(struct, encoder) do
88+
map =
89+
Map.from_struct(struct)
90+
|> Enum.reject(fn {_, v} -> v == nil end)
91+
|> Enum.into(%{})
92+
93+
:elixir_json.encode_map(map, encoder)
94+
end
95+
end
96+
97+
{:error, reason} ->
98+
:ok
99+
end
100+
101+
case Code.ensure_compiled(Jason.Encoder) do
102+
{:module, module} ->
103+
defimpl module, for: JSend do
104+
def encode(struct, opts) do
105+
map =
106+
Map.from_struct(struct)
107+
|> Enum.reject(fn {_, v} -> v == nil end)
108+
|> Enum.into(%{})
109+
110+
Jason.Encode.map(map, opts)
111+
end
112+
end
113+
114+
{:error, reason} ->
115+
:ok
116+
end

mix.exs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
defmodule JSend.MixProject do
2+
use Mix.Project
3+
4+
@source_url "https://github.com/codedge-llc/jsend"
5+
@version "0.1.0"
6+
7+
def project do
8+
[
9+
app: :jsend,
10+
deps: deps(),
11+
docs: docs(),
12+
elixir: "~> 1.14",
13+
name: "JSend",
14+
package: package(),
15+
start_permanent: Mix.env() == :prod,
16+
version: @version
17+
]
18+
end
19+
20+
# Run "mix help compile.app" to learn about applications.
21+
def application do
22+
[
23+
extra_applications: [:logger]
24+
]
25+
end
26+
27+
defp deps do
28+
[
29+
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
30+
{:dialyxir, "~> 1.3", only: [:dev], runtime: false},
31+
{:ex_doc, ">= 0.0.0", only: [:dev]},
32+
{:jason, "~> 1.0", optional: true}
33+
]
34+
end
35+
36+
defp docs do
37+
[
38+
extras: [
39+
"CHANGELOG.md",
40+
"LICENSE.md": [title: "License"]
41+
],
42+
formatters: ["html"],
43+
main: "JSend",
44+
skip_undefined_reference_warnings_on: ["CHANGELOG.md"],
45+
source_ref: "v#{@version}",
46+
source_url: @source_url
47+
]
48+
end
49+
50+
defp package do
51+
[
52+
description: "JSend API specification.",
53+
files: ["lib", "mix.exs", "README*", "LICENSE*", "CHANGELOG*"],
54+
licenses: ["MIT"],
55+
links: %{
56+
"Changelog" => "https://hexdocs.pm/jsend/changelog.html",
57+
"GitHub" => "https://github.com/codedge-llc/jsend",
58+
"Sponsor" => "https://github.com/sponsors/codedge-llc"
59+
},
60+
maintainers: ["Henry Popp"]
61+
]
62+
end
63+
end

0 commit comments

Comments
 (0)