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.
|
**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 :
|
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_)
|
- 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).
|
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
|
#### 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
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.xdrm.io/go/aicra"
|
"git.xdrm.io/go/aicra"
|
||||||
"git.xdrm.io/go/aicra/typecheck/builtin"
|
"git.xdrm.io/go/aicra/datatype"
|
||||||
"git.xdrm.io/go/aicra/api"
|
"git.xdrm.io/go/aicra/datatype/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
// 1. build server
|
// 1. select your datatypes (builtin, custom)
|
||||||
server, err := aicra.New("path/to/your/api/definition.json");
|
var dtypes []datatype.T
|
||||||
if err != nil {
|
dtypes = append(dtypes, builtin.AnyDataType{})
|
||||||
log.Fatalf("Cannot build the aicra server: %v\n", err)
|
dtypes = append(dtypes, builtin.BoolDataType{})
|
||||||
}
|
dtypes = append(dtypes, builtin.UintDataType{})
|
||||||
|
dtypes = append(dtypes, builtin.StringDataType{})
|
||||||
|
|
||||||
// 2. add type checkers
|
// 2. create the server from the configuration file
|
||||||
server.Checkers.Add( builtin.NewAny() );
|
server, err := aicra.New("path/to/your/api/definition.json", dtypes...)
|
||||||
server.Checkers.Add( builtin.NewString() );
|
if err != nil {
|
||||||
server.Checkers.Add( builtin.NewFloat64() );
|
log.Fatalf("cannot built aicra server: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
// 3. bind your implementations
|
// 3. bind your implementations
|
||||||
server.HandleFunc(http.MethodGet, "/path", func(req api.Request, res *api.Response){
|
server.HandleFunc(http.MethodGet, "/path", func(req api.Request, res *api.Response){
|
||||||
|
@ -87,8 +90,14 @@ func main() {
|
||||||
res.SetError(api.ErrorSuccess());
|
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
|
// 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
|
#### 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 input for each method (called *argument*)
|
||||||
- every output for each method
|
- 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 :
|
- input policy :
|
||||||
- type of argument (_i.e. for type checkers_)
|
- type of argument (_i.e. for data types_)
|
||||||
- required/optional
|
- required/optional
|
||||||
- default value
|
|
||||||
- variable renaming
|
- variable renaming
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###### Definition
|
###### 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
|
For each, you will have to create fields described in the table above.
|
||||||
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.
|
|
||||||
|
|
||||||
| field path | description | example |
|
| 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 :
|
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.
|
- **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.
|
- **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.
|
- **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.
|
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 **URI** variable `{id}` from your request route must be named `{id}`.
|
||||||
> - The variable named `somevar` in the **Query** has to be named `GET@somvar` in the configuration.
|
> - the variable `somevar` in the **Query** has to be names `GET@somevar`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
In this example we want 3 arguments :
|
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 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 `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 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 controller with the name `multipart-var`.
|
- 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
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"path": "/article/{id}",
|
||||||
|
"scope": [["author"]],
|
||||||
|
"info": "updates an article",
|
||||||
"in": {
|
"in": {
|
||||||
// arg 1
|
"{id}": { "info": "article id", "type": "int", "name": "article_id" },
|
||||||
"URL#0": {
|
"GET@title": { "info": "new article title", "type": "?string", "name": "title" },
|
||||||
"info": "some integer in the URI",
|
"content": { "info": "new article content", "type": "string" }
|
||||||
"type": "int",
|
|
||||||
"name": "uri-param"
|
|
||||||
},
|
},
|
||||||
// arg 2
|
"out": {
|
||||||
"GET@get-var": {
|
"id": { "info": "updated article id", "type": "uint" },
|
||||||
"info": "some Query OPTIONAL variable",
|
"title": { "info": "updated article title", "type": "string" },
|
||||||
"type": "?int",
|
"content": { "info": "updated article content", "type": "string" }
|
||||||
"name": "get-param"
|
|
||||||
},
|
|
||||||
// arg 3
|
|
||||||
"multipart-var": { /* ... */ }
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ In this example we want 3 arguments :
|
||||||
|
|
||||||
- [x] human-readable json configuration
|
- [x] human-readable json configuration
|
||||||
- [x] nested routes (*i.e. `/user/:id:` and `/user/post/:id:`*)
|
- [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] useful http methods: GET, POST, PUT, DELETE
|
||||||
- [x] manage URL, query and body arguments:
|
- [x] manage URL, query and body arguments:
|
||||||
- [x] multipart/form-data (variables and file uploads)
|
- [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] generic controllers implementation (shared objects)
|
||||||
- [x] response interface
|
- [x] response interface
|
||||||
- [x] log bound resources when building the aicra server
|
- [x] log bound resources when building the aicra server
|
||||||
- [ ] fail on check for unimplemented resources at server boot.
|
- [x] 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 unavailable types in api.json at server boot.
|
||||||
|
|
Loading…
Reference in New Issue