RestKat
¶ ↑
We have all heard the mantra that REST does not require a schema because it is just JSON. However when I found myself writing hundreds of lines of objective C binding code with RestKit I thought that there must be a better way of doing the boring bits.
Now there is RestKat
.
You just have to declare your API in a YAML file using an extension to the kwalify schema validator.
A schema looks like the following
configuration_type: &configuration_type type: map name: XXConfiguration mapping: name: type: str required: yes email: type: str required: yes log_type: &todo_type type: map name: XXTodo mapping: id: type:int required: yes due: type: str name: NSDate desc: type: str name: NSString search_type: &search_type type: map name: XXTodoSearch mapping: desc: type: str required: yes ########################################## # REQUEST TYPES ########################################## # permissions and generated routes. A 's' singleton # modifier can be added to indicate that the resource # does not represent a collection # # s - singleton modifier # # c - POST "/resource" # sc - invalid # # r - GET "/resource/:id" # GET "/resource" # sr - GET "/resource" # # u - adds PUT "/resource/:id" # su - adds PUT "/resource" # # d - adds PUT "/resource/:id" # sd - adds PUT "/resource" # resources: # singletons - name: configuration type: *configuration_type resource: /configuration permissions: sru # collections - name: todo type: *todo_type resource: /todo queries: - name: search type: *search_type permissions: crud
The resources section defines the RESTful resources and thier methods. The type of each resource refers to types defined further up the file. The name of each type must refer to the desired objective C class name for each type.
Resources can be interfaced with through the generated subclasses via this interface.
@interface MSRestSerializableResource : MSRestSerializable #pragma mark methods to be overridden + (Class) classForResource; // The resource path. If this + (NSString *) resourcePath; // Is the resource a singleton or a collection + (bool) isSingleton; // Can the client create resources + (bool) canCreate; // Can the client read resources + (bool) canRead; // Can the client update resources + (bool) canUpdate; // Can the client delete resources + (bool) canDelete; #pragma mark helpers // The router for this class + (RKObjectRouter *) router; // Intialize the routing module. Must // be called from +initialize in a // subclass or the logic will not // work. + (void) initializeRouting; // save the object -(void) saveWithDelegate:(id<RKObjectLoaderDelegate>)delegate; // Find an instance by id + (void) find:(NSNumber *)id withDelegate:(id<RKObjectLoaderDelegate>)delegate; // Load collection + (void) loadCollectionWithDelegate:(id<RKObjectLoaderDelegate>)delegate; // Load collection with query + (void) loadCollectionThroughQuery:(MSRestSerializable *)mappableQueryObject withDelegate:(id<RKObjectLoaderDelegate>)delegate; @end
Standard types of int, float, str are mapped to NSNumber, NSNumber and NSString respectively unless a specialized class is given.
There is a helper for your custom rake task to do the building of the source code for you. For example you could do
require 'rest_kat' namespace :iphone do namespace :api do ApiLocation = File.expand_path "src/AutoGen", __FILE__ SchemaLocation = File.expand_path "api_schema.yml", __FILE__ task :_generate => RestKat::generate_api(ApiLocation, SchemaLocation) desc "Generate iPhone API to #{ApiLocation}" task :generate => :_generate end end
The class heirarchy for the generated classes is
MSRestSerializable ^ | MSRestSerializableResource
All types that are also are resource derive from MSRestSerializableResource and all helper or nested types derive from MSRestSerializable.
Refer to MSRestSerializable.h for more details and the restKit documentation