Creating a new resource in an existing phoenix project often involves multiple steps for it to fit nicely into the project. From altering the migration to include foreign keys and NOT_NULL to adding relationships to the ecto schema. I sometimes forgot a step and had to alter the migration after, which can be very anoying. Also I found it hard to remember the commands to create new resouces and often had to look them up.
This guide is highlights generating JSON resources in phoenix but it can be applied to the other options like live views too.
Generation #
Here is an example command to create a new JSON resource in phoenix:
mix phx.gen.json Users User users name:string last_login:utc_datetime account_id:references:accounts
Explenation:
Users-> Plural The context name the new resource should be generated in. Contexts group functionality that belongs close to each other. For example users and logins or addresses. If unsure if an resource fits into an existing group it’s always better to create a new one.User-> Singular The name of the resource.users-> Plural The name of the table that will be generatedaccount_id:references:accounts-> References to other resources. Given in the form of[singular-table-name]_id:references:[plural-table-name]
Output #
* creating lib/app_web/controllers/user_controller.ex
* creating lib/app_web/controllers/user_json.ex
* creating lib/app_web/controllers/changeset_json.ex
* creating test/app_web/controllers/user_controller_test.exs
* creating lib/app_web/controllers/fallback_controller.ex
* creating lib/app/users/user.ex
* creating priv/repo/migrations/20240123151159_create_users.exs
* creating lib/app/users.ex
* injecting lib/app/users.ex
* creating test/app/users_test.exs
* injecting test/app/users_test.exs
* creating test/support/fixtures/users_fixtures.ex
* injecting test/support/fixtures/users_fixtures.ex
Add the resource to your :api scope in lib/app_web/router.ex:
resources "/users", UserController, except: [:new, :edit]
Remember to update your repository by running migrations:
$ mix ecto.migrate
Alter generated code #
- Alter migartion (/app/priv/repo/migrations) to create the correct database objects
- Add
null: falseto not nullable fields (also at references) - Add
defaultwherever possible - Change
:stringto:text. In postgres, there is no performance difference between using a capped VARCHAR(255), which would be:stringor an uncapped TEXT. That’s why I opt for the later. - Alter
references(on_delete)where possible, see the available Options - Verify that columns that need it are indexed. Don’t forget the foreign keys.
- Execute migration with
mix ecto.migrate - Check the database with your favorite DB tool
- Datatypes correct?
- Not null correct? Also at foreign keys?
- Defaults present?
- Indizes present?
- Foreign keys present?
- If you notice an error, first execute
mix ecto.rollback, then edit the migration and reapply it withmix ecto.migrate.
- Add
- Alter schema (/app/lib/app/[context_name])
- Add relationships
- Alter changeset
- Add relationships to cast (i.e. account_id)
- Add resources to
router.exand restrict methods like required
Your new resource is ready to go!