-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f3ff0f8
commit 9da3546
Showing
8 changed files
with
135 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import gleam/dynamic.{type DecodeError, type Dynamic} | ||
import gleam/result | ||
|
||
pub type NewUser { | ||
NewUser(name: String, email: String, password: String) | ||
} | ||
|
||
pub type User { | ||
User(id: Int, name: String, email: String, password_hash: String) | ||
} | ||
|
||
// Decodes the JSON blob from the POST to /users | ||
pub fn new_user_decoder(json: Dynamic) -> Result(NewUser, Nil) { | ||
let decoder = | ||
dynamic.decode3( | ||
NewUser, | ||
dynamic.field("name", dynamic.string), | ||
dynamic.field("email", dynamic.string), | ||
dynamic.field("password", dynamic.string), | ||
) | ||
|
||
json | ||
|> decoder() | ||
|> result.nil_error() | ||
} | ||
|
||
// Decodes the return from the db insert | ||
pub fn user_decoder(tuple: Dynamic) -> Result(User, List(DecodeError)) { | ||
let decoder = | ||
dynamic.decode4( | ||
User, | ||
dynamic.element(0, dynamic.int), | ||
dynamic.element(1, dynamic.string), | ||
dynamic.element(2, dynamic.string), | ||
dynamic.element(3, dynamic.string), | ||
) | ||
|
||
decoder(tuple) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import antigone | ||
import app/contexts/user_contexts.{type NewUser, type User, user_decoder} | ||
import gleam/bit_array | ||
import gleam/pgo.{type Connection, Returned} | ||
|
||
pub fn create_user(connection: Connection, user: NewUser) -> Result(User, Nil) { | ||
let sql = | ||
" | ||
INSERT INTO users (name, email, password_hash) | ||
VALUES ($1, $2, $3) | ||
RETURNING id, name, email, password_hash; | ||
" | ||
let password = bit_array.from_string(user.password) | ||
let hashed_password = antigone.hash(antigone.hasher(), password) | ||
|
||
let returned = | ||
pgo.execute( | ||
sql, | ||
connection, | ||
[pgo.text(user.name), pgo.text(user.email), pgo.text(hashed_password)], | ||
user_decoder, | ||
) | ||
|
||
case returned { | ||
Ok(Returned(_, [user, ..])) -> Ok(user) | ||
_ -> Error(Nil) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import app/contexts/web_contexts.{type Context} | ||
import app/services/user_services.{create_user} | ||
import gleam/http.{Post} | ||
import wisp.{type Request, type Response} | ||
|
||
pub fn all(req: Request, ctx: Context) -> Response { | ||
case req.method { | ||
Post -> create_user(req, ctx) | ||
_ -> wisp.method_not_allowed([Post]) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import app/contexts/user_contexts as contexts | ||
import app/contexts/web_contexts.{type Context} | ||
import app/queries/user_queries as queries | ||
import gleam/json | ||
import gleam/result.{try} | ||
import wisp.{type Request, type Response} | ||
|
||
pub fn create_user(req: Request, ctx: Context) -> Response { | ||
use json <- wisp.require_json(req) | ||
|
||
let result = { | ||
// Decode the JSON into a NewUser record. | ||
use new_user <- try(contexts.new_user_decoder(json)) | ||
|
||
// Save the user to the database. | ||
use user <- try(queries.create_user(ctx.db, new_user)) | ||
|
||
// Construct a JSON payload with the id and name of the newly created user. | ||
// TODO: case on the user result, return Ok or Error | ||
Ok( | ||
json.to_string_builder( | ||
json.object([ | ||
#("id", json.int(user.id)), | ||
#("name", json.string(user.name)), | ||
#("email", json.string(user.email)), | ||
#("password_hash", json.string(user.password_hash)), | ||
]), | ||
), | ||
) | ||
} | ||
|
||
case result { | ||
Ok(json) -> wisp.json_response(json, 201) | ||
Error(Nil) -> wisp.unprocessable_entity() | ||
} | ||
} |