crystal_api
crystal_api
Toolset for creating REST Api in Crystal Language.
Roadmap
- [x] Fix DB mapping to allow create database - add types of columns to definition list
- [x] Check and fix JSON mapping
- [x] Update action
- [x] Destroy action
- [x] Clean Postgres adapter
- [x] Rewrite for easier usage as lib
- [x] JSON response header
- [ ] Other DB engines (partially refactored)
- [ ] More predefined/sample controllers
- [ ] Websockets
- [ ] DB inline config (no confi file needed)
Usage
-
Create empty crystal project:
crystal init app crystal_api_sample
-
Add
crystal_api
toshard.yml
. Example:name: crystal_api_sample version: 0.1.0 authors: - Crystal Guy <crystal@crystal.org> dependencies: crystal_api: github: "akwiatkowski/crystal_api" license: MIT
-
Update shards (Crystal libraries):
shards update
-
Create Postgresql connection file in
config/database.yml
using sample fromconfig/database.yml.sample
fromcrystal_api
repository.host: localhost database: crystal user: crystal_user password: crystal_password
-
Set path to Postgresql config file by adding in
src/crystal_api_sample.cr
class CrystalApi::PgAdapter def self.config_path "config/database.yml" end end
-
Create model representing data fetched from Postgresql:
class EventModel < CrystalApi::CrystalModel def initialize(_db_id, _name) @db_id = _db_id as Int32 @name = _name as (String | Nil) end getter :db_id, :name JSON.mapping({ "db_id": Int32, "name": String, }) DB_COLUMNS = { # "id" is default "name" => "varchar(255)", } DB_TABLE = "events" end
Notes:
- nullable columns must use union with
Nil
class - all columns should be defined in constructor
- JSON mapping is used when rendereing JSON
- DB_COLUMNS are used when creating table
- DB_TABLE is table name
- nullable columns must use union with
-
Create service class which performs DB operations.
class EventsService < CrystalApi::CrystalService def initialize(a) @adapter = a @table_name = EventModel::DB_TABLE # create table if not exists create_table(EventModel::DB_COLUMNS) end def self.from_row(rh) return EventModel.new(rh["id"], rh["name"]) end end
Notes:
EventsService.from_row(rh)
instantiates model from Hash-like response from DB adapter
-
Create controller class with defined route paths.
class EventsController < CrystalApi::CrystalApi::Controllers::JsonRestApiController def initialize(s) @service = s @router = { "GET /events" => "index", "GET /events/:id" => "show", "POST /events" => "create", "PUT /events/:id" => "update", "DELETE /events/:id" => "delete", } @resource_name = "event" end end
Notes:
@resource_name
is used inupdate
andcreate
- instead of
CrystalApi::CrystalController
please useCrystalApi::Controllers::JsonRestApiController
-
Create app class
class ApiApp < CrystalApi::App def initialize(a) super(a) @events_service = EventsService.new(@adapter) @events_controller = EventsController.new(@events_service) add_controller(@events_controller) @port = 8002 end end
Notes:
super
is important- service and controller must be initialized here and controller must be added
- default port is 8000
initialize
utilize DB adapter class now
-
You can now run it
a = ApiApp.new( DbAdapter.new ) a.run
Notes:
- you must provide DB adapter instance for
ApiApp
constructor
- you must provide DB adapter instance for
Index
GET http://localhost:8002/events
curl -H "Content-Type: application/json" -X GET http://localhost:8002/events
Show
GET http://localhost:8002/events/:id
curl -H "Content-Type: application/json" -X GET http://localhost:8002/events/1
But first create an Event :)
Create
POST http://localhost:8002/events
curl -H "Content-Type: application/json" -X POST -d '{"event":{"name": "test1"}}' http://localhost:8002/events
Update
PUT http://localhost:8002/events/:id
curl -H "Content-Type: application/json" -X PUT -d '{"event":{"name": "test2"}}' http://localhost:8002/events/1
Delete
DELETE http://localhost:8002/events/:id
curl -H "Content-Type: application/json" -X DELETE http://localhost:8002/events/1
Contributing
- Fork it ( https://github.com/akwiatkowski/crystal_api/fork )
- Create your feature branch (git checkout -b my-new-feature)
- Commit your changes (git commit -am 'Add some feature')
- Push to the branch (git push origin my-new-feature)
- Create a new Pull Request
Contributors
- akwiatkowski Aleksander Kwiatkowski - creator, maintainer