update readme
This commit is contained in:
parent
d57f60c710
commit
97cf19d7b4
110
README.md
110
README.md
|
@ -10,9 +10,9 @@
|
|||
**Aicra** is a *configuration-driven* **web framework** written in Go that allows you to create a fully featured REST API.
|
||||
|
||||
The whole management is done for you from a configuration file describing your API, you're left with implementing :
|
||||
- controllers
|
||||
- handlers
|
||||
- optionnally middle-wares (_e.g. authentication, csrf_)
|
||||
- and optionnally type checkers to check input parameters
|
||||
- and optionnally your custom type checkers to check input parameters
|
||||
|
||||
|
||||
The aicra server fulfills the `net/http` [Server interface](https://golang.org/pkg/net/http/#Server).
|
||||
|
@ -55,31 +55,34 @@ The library should now be available as `git.xdrm.io/go/aicra` in your imports.
|
|||
|
||||
#### 1) Main executable
|
||||
|
||||
The main executable will declare and run the aicra server, it might look quite like the code below.
|
||||
Your main executable will declare and run the aicra server, it might look quite like the code below.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"git.xdrm.io/go/aicra"
|
||||
"git.xdrm.io/go/aicra/typecheck/builtin"
|
||||
"git.xdrm.io/go/aicra/api"
|
||||
"git.xdrm.io/go/aicra/datatype"
|
||||
"git.xdrm.io/go/aicra/datatype/builtin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// 1. build server
|
||||
server, err := aicra.New("path/to/your/api/definition.json");
|
||||
if err != nil {
|
||||
log.Fatalf("Cannot build the aicra server: %v\n", err)
|
||||
}
|
||||
// 1. select your datatypes (builtin, custom)
|
||||
var dtypes []datatype.T
|
||||
dtypes = append(dtypes, builtin.AnyDataType{})
|
||||
dtypes = append(dtypes, builtin.BoolDataType{})
|
||||
dtypes = append(dtypes, builtin.UintDataType{})
|
||||
dtypes = append(dtypes, builtin.StringDataType{})
|
||||
|
||||
// 2. add type checkers
|
||||
server.Checkers.Add( builtin.NewAny() );
|
||||
server.Checkers.Add( builtin.NewString() );
|
||||
server.Checkers.Add( builtin.NewFloat64() );
|
||||
// 2. create the server from the configuration file
|
||||
server, err := aicra.New("path/to/your/api/definition.json", dtypes...)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot built aicra server: %s\n", err)
|
||||
}
|
||||
|
||||
// 3. bind your implementations
|
||||
server.HandleFunc(http.MethodGet, "/path", func(req api.Request, res *api.Response){
|
||||
|
@ -87,8 +90,14 @@ func main() {
|
|||
res.SetError(api.ErrorSuccess());
|
||||
})
|
||||
|
||||
// 4. extract to http server
|
||||
httpServer, err := server.ToHTTPServer()
|
||||
if err != nil {
|
||||
log.Fatalf("cannot get to http server: %s", err)
|
||||
}
|
||||
|
||||
// 4. launch server
|
||||
log.Fatal( http.ListenAndServe("localhost:8181", server) )
|
||||
log.Fatal( http.ListenAndServe("localhost:8080", server) )
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -96,33 +105,24 @@ func main() {
|
|||
|
||||
#### 2) API Configuration
|
||||
|
||||
The whole project behavior is described inside a json file (_e.g. usually api.json_) file. For a better understanding of the format, take a look at this working [template](https://git.xdrm.io/go/tiny-url-ex/src/master/api.json). This file defines :
|
||||
The whole project behavior is described inside a json file (_e.g. usually api.json_). For a better understanding of the format, take a look at this working [template](https://git.xdrm.io/go/tiny-url-ex/src/master/api.json). This file defines :
|
||||
|
||||
- resource routes and their methods
|
||||
- routes and their methods
|
||||
- every input for each method (called *argument*)
|
||||
- every output for each method
|
||||
- scope permissions (list of permissions needed for clients to use which method)
|
||||
- scope permissions (list of permissions needed by clients)
|
||||
- input policy :
|
||||
- type of argument (_i.e. for type checkers_)
|
||||
- type of argument (_i.e. for data types_)
|
||||
- required/optional
|
||||
- default value
|
||||
- variable renaming
|
||||
|
||||
|
||||
|
||||
###### Definition
|
||||
|
||||
At the root of the json file are available 5 field names :
|
||||
The root of the json file must be an array containing your requests definitions.
|
||||
|
||||
1. `GET` - to define what to do when receiving a request with a GET HTTP method at the root URI
|
||||
2. `POST` - to define what to do when receiving a request with a POST HTTP method at the root URI
|
||||
3. `PUT` - to define what to do when receiving a request with a PUT HTTP method at the root URI
|
||||
4. `DELETE` - to define what to do when receiving a request with a DELETE HTTP method at the root URI
|
||||
5. `/` - to define children URIs ; each will have the same available fields
|
||||
|
||||
|
||||
|
||||
For each method you will have to create fields described in the table above.
|
||||
For each, you will have to create fields described in the table above.
|
||||
|
||||
| field path | description | example |
|
||||
| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
|
@ -138,7 +138,7 @@ For each method you will have to create fields described in the table above.
|
|||
|
||||
Input arguments defines what data from the HTTP request the method needs. Aicra is able to extract 3 types of data :
|
||||
|
||||
- **URI** - Slash-separated strings right after the resource URI. For instance, if your controller is bound to the `/user` URI, you can use the *URI slot* right after to send the user ID ; Now a client can send requests to the URI `/user/:id` where `:id` is a number sent by the client. This kind of input cannot be extracted by name, but rather by index in the URL (_begins at 0_).
|
||||
- **URI** - Curly Braces enclosed strings inside the request path. For instance, if your controller is bound to the `/user/{id}` URI, you can set the input argument `{id}` matching this uri part.
|
||||
- **Query** - data formatted at the end of the URL following the standard [HTTP Query](https://tools.ietf.org/html/rfc3986#section-3.4) syntax.
|
||||
- **URL encoded** - data send inside the body of the request but following the [HTTP Query](https://tools.ietf.org/html/rfc3986#section-3.4) syntax.
|
||||
- **Multipart** - data send inside the body of the request with a dedicated [format](https://tools.ietf.org/html/rfc2388#section-3). This format is not very lightweight but allows you to receive data as well as files.
|
||||
|
@ -150,38 +150,38 @@ Input arguments defines what data from the HTTP request the method needs. Aicra
|
|||
|
||||
The `in` field in each method contains as list of arguments where the key is the argument name, and the value defines how to manage the variable.
|
||||
|
||||
> Variable names must be <u>prefixed</u> when requesting **URI** or **Query** input types.
|
||||
> Variable names from **URI** or **Query** must be named accordingly :
|
||||
>
|
||||
> - The first **URI** data has to be named `URL#0`, the second one `URL#1` and so on...
|
||||
> - The variable named `somevar` in the **Query** has to be named `GET@somvar` in the configuration.
|
||||
|
||||
|
||||
> - the **URI** variable `{id}` from your request route must be named `{id}`.
|
||||
> - the variable `somevar` in the **Query** has to be names `GET@somevar`.
|
||||
|
||||
**Example**
|
||||
|
||||
In this example we want 3 arguments :
|
||||
|
||||
- the 1^st^ one is send at the end of the URI and is a number compliant with the `int` type checker (else the controller will not be run). It is renamed `uri-param`, this new name will be sent to the controller.
|
||||
- the 2^nd^ one is send in the query (_e.g. [http://host/uri?get-var=value](http://host/uri?get-var=value)_). It must be a valid `int` or not given at all (the `?` at the beginning of the type tells that the argument is **optional**) ; it will be named `get-param`.
|
||||
- the 3^rd^ can be send with a **JSON** body, in **multipart** or **URL encoded** it makes no difference and only give clients a choice over the technology to use. If not renamed, the variable will be given to the controller with the name `multipart-var`.
|
||||
- the 1^st^ one is send at the end of the URI and is a number compliant with the `int` type checker. It is renamed `article_id`, this new name will be sent to the handler.
|
||||
- the 2^nd^ one is send in the query (_e.g. [http://host/uri?get-var=value](http://host/uri?get-var=value)_). It must be a valid `string` or not given at all (the `?` at the beginning of the type tells that the argument is **optional**) ; it will be named `title`.
|
||||
- the 3^rd^ can be send with a **JSON** body, in **multipart** or **URL encoded** it makes no difference and only give clients a choice over the technology to use. If not renamed, the variable will be given to the handler with the name `content`.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"method": "PUT",
|
||||
"path": "/article/{id}",
|
||||
"scope": [["author"]],
|
||||
"info": "updates an article",
|
||||
"in": {
|
||||
// arg 1
|
||||
"URL#0": {
|
||||
"info": "some integer in the URI",
|
||||
"type": "int",
|
||||
"name": "uri-param"
|
||||
"{id}": { "info": "article id", "type": "int", "name": "article_id" },
|
||||
"GET@title": { "info": "new article title", "type": "?string", "name": "title" },
|
||||
"content": { "info": "new article content", "type": "string" }
|
||||
},
|
||||
// arg 2
|
||||
"GET@get-var": {
|
||||
"info": "some Query OPTIONAL variable",
|
||||
"type": "?int",
|
||||
"name": "get-param"
|
||||
},
|
||||
// arg 3
|
||||
"multipart-var": { /* ... */ }
|
||||
"out": {
|
||||
"id": { "info": "updated article id", "type": "uint" },
|
||||
"title": { "info": "updated article title", "type": "string" },
|
||||
"content": { "info": "updated article content", "type": "string" }
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
|
@ -190,7 +190,7 @@ In this example we want 3 arguments :
|
|||
|
||||
- [x] human-readable json configuration
|
||||
- [x] nested routes (*i.e. `/user/:id:` and `/user/post/:id:`*)
|
||||
- [ ] nested URL arguments (*i.e. `/user/:id:` and `/user/:id:/post/:id:`*)
|
||||
- [x] nested URL arguments (*i.e. `/user/:id:` and `/user/:id:/post/:id:`*)
|
||||
- [x] useful http methods: GET, POST, PUT, DELETE
|
||||
- [x] manage URL, query and body arguments:
|
||||
- [x] multipart/form-data (variables and file uploads)
|
||||
|
@ -211,5 +211,5 @@ In this example we want 3 arguments :
|
|||
- [x] generic controllers implementation (shared objects)
|
||||
- [x] response interface
|
||||
- [x] log bound resources when building the aicra server
|
||||
- [ ] fail on check for unimplemented resources at server boot.
|
||||
- [ ] fail on check for unavailable types in api.json at server boot.
|
||||
- [x] fail on check for unimplemented resources at server boot.
|
||||
- [x] fail on check for unavailable types in api.json at server boot.
|
||||
|
|
Loading…
Reference in New Issue