edit previous PHP doc (not finished)
This commit is contained in:
parent
fe3034818d
commit
e15772c2f4
|
@ -6,7 +6,7 @@
|
|||
[![Go doc](https://godoc.org/git.xdrm.io/go/aicra?status.svg)](https://godoc.org/git.xdrm.io/go/aicra)
|
||||
|
||||
|
||||
**Aicra** is a self-working framework coded in *Go* that allows anyone to create a fully featured REST API. It features type checking, authentication management through middlewares, file upload, rich argument parsing (*i.e. url slash-separated, urlencoded, form-data, json*), nested routes, project compiler (*i.e. aicra*), etc.
|
||||
**Aicra** is a self-working **REST API engine** coded in *Go* that allows anyone to create a fully featured API. It features type checking, authentication management through middlewares, file upload, rich argument parsing (*i.e. url slash-separated, urlencoded, form-data, json*), nested routes, project compiler (*i.e. aicra*), etc.
|
||||
|
||||
All the REST API management is done for you, you just need to implement :
|
||||
|
||||
|
|
|
@ -0,0 +1,608 @@
|
|||
```yaml
|
||||
module: api
|
||||
version: 1.2
|
||||
```
|
||||
|
||||
For developers
|
||||
====
|
||||
|
||||
[**I.** Overview](#i-overview)
|
||||
|
||||
- [**1** Introduction & features](#1-introduction--features)
|
||||
- [**2** Basic knowledge](#2-basic-knowledge)
|
||||
|
||||
[**II.** Usage](#ii-usage)
|
||||
|
||||
- [**1** REST API](#1-rest-api)
|
||||
- [**2** Internal use (PHP)](#2-internal-use)
|
||||
|
||||
[**III.** Configuration](#iii-configuration)
|
||||
|
||||
- [**1** Configuration format](#1---configuration-format)
|
||||
- [**2** Method definition](#2---methoddefinition)
|
||||
- [**2.1** Method description](#21---methoddescription)
|
||||
- [**2.2** Method permissions](#22---methodpermissions)
|
||||
- [**2.3** Method parameters](#23---methodparameters)
|
||||
- [parameter name](#parametername)
|
||||
- [parameter description](#parameterdescription)
|
||||
- [parameter type](#parameterchecker_type)
|
||||
- [parameter optional vs. required](#parameteris_optional)
|
||||
- [parameter rename](#parameterrename)
|
||||
- [parameter default value](#parameterdefault_value)
|
||||
- [**2.4** Method output format](#24---methodoutput_format)
|
||||
- [**2.5** Method options](#25---methodoptions)
|
||||
|
||||
[**IV.** Implementation](#iv-implementation)
|
||||
|
||||
- [**1** Permissions : AuthSystem](#1---permissions--authsystem)
|
||||
- [**2** Core implementation](#2---core-implementation)
|
||||
- [Classes](#classes)
|
||||
- [Methods](#methods)
|
||||
- [Method arguments](#method-arguments)
|
||||
- [Return statement](#return-statement)
|
||||
- [Before and After scripts](#before-and-after-scripts)
|
||||
- [Example](#example)
|
||||
|
||||
[**V.** Type Checker](#v-type-checker)
|
||||
|
||||
- [**1** Default Types](#1---default-types)
|
||||
- [**2** Complex Types](#2---complex-types)
|
||||
|
||||
[**VI.** Documentation](#vi-documentation)
|
||||
|
||||
- [**1** API accessible documentation](#1---api-accessible-documentation)
|
||||
|
||||
|
||||
For clients
|
||||
====
|
||||
|
||||
[**I.** Simple request](#i-simple-request)
|
||||
|
||||
- [**1** URL](#1---URL)
|
||||
- [**2** variables](#2---variables)
|
||||
|
||||
[**II.** Usage](#ii-usage)
|
||||
|
||||
|
||||
|
||||
|
||||
# **I.** Overview
|
||||
## **1** Introduction & features
|
||||
|
||||
The `api` package (v1.2) allows you to easily create and manage a REST API for your applications.
|
||||
|
||||
The aim of this package is to make your life easier working with APIs and internal delegation. The only things you have to do is to implement your controllers, middle-wares and write 2 configuration files, the package will do the rest.
|
||||
|
||||
Things you **have** to do :
|
||||
- write the project configuration file (cf. [project configuration](#iii-project-configuration))
|
||||
- write the API definition file (cf. [api definition](#iv-api-definition))
|
||||
- implement your middle-wares to manage authentication, csrf, etc (cf. [AuthSystem](#1---middle-wares))
|
||||
- implement your controllers (cf. ???)
|
||||
- implement additional project-specific type checkers (cf. ???)
|
||||
|
||||
Things you **don't have** to do :
|
||||
- check the input variables (cf. [Checker](#v-type-checker))
|
||||
- multiple permission management
|
||||
- optional or required input
|
||||
- Form data type : x-www-urlencoded, multipart, or file upload
|
||||
- URL variables (slash separated at the end of the route, like standard uri)
|
||||
- and a lot more ...
|
||||
|
||||
## **2** Basic knowledge
|
||||
|
||||
The API uses the routes defined in the _api.json_ configuration to export your code (in compiled go or other language). Middle-wares are executed when receiving a new request, then the controllers will be loaded according to the URI.
|
||||
|
||||
<u>Example:</u>
|
||||
* the module `article` contains methods:
|
||||
* `GET` to get article data
|
||||
* `POST` to post a new article
|
||||
* `PUT` to edit an existing article
|
||||
* `DELETE` to delete an exisint article
|
||||
|
||||
*Note that each method must be a valid HTTP METHOD*.
|
||||
|
||||
|
||||
|
||||
|
||||
# **III.** Project Configuration
|
||||
|
||||
|
||||
The documentation consists of a _chain_ of urls each one can contain several HTTP method specifications.
|
||||
Note that each url can be chained apart the method specifications.
|
||||
|
||||
|
||||
|
||||
|
||||
## **1** - configuration format
|
||||
|
||||
The configuration is a set of `uri` paths that can contain up to 4 method types: **POST**, **DELETE**, **PUT**, **GET** or `uri` subpaths.
|
||||
|
||||
For instance the 4 methods directly inside `uri1` will be triggered when the calling URI is `/uri1`, the ones directly inside `uri2` will be triggered when calling `/uri1/uri2` and so on..
|
||||
|
||||
You can also set full paths if you don't need transitional methods, for instance the path `uri5/uri6/uri7` will be triggered by the url `/uri5/uri6/uri7`.
|
||||
|
||||
**Example:** The example file loaded with the default configuration can be found [here](./../../src/config/api/3.0/modules.json).
|
||||
```json
|
||||
{
|
||||
"uri1" : {
|
||||
"GET": method.definition,
|
||||
"POST": method.definition,
|
||||
"PUT": method.definition,
|
||||
"DELETE": method.definition,
|
||||
|
||||
"uri2": {
|
||||
"GET": method.definition,
|
||||
"POST": method.definition,
|
||||
"PUT": method.definition,
|
||||
"DELETE": method.definition,
|
||||
|
||||
"uri3": {}
|
||||
}
|
||||
},
|
||||
|
||||
"uri5/uri6/uri7": {
|
||||
"GET": method.definition,
|
||||
"POST": method.definition,
|
||||
"PUT": method.definition,
|
||||
"DELETE": method.definition
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: It is possible to trigger the *root uri* (`/`), so you can set methods directly at the root of the JSON file.
|
||||
|
||||
## **2** - method.definition
|
||||
```json
|
||||
{
|
||||
"des": method.description,
|
||||
"per": method.permissions,
|
||||
"par": method.parameters,
|
||||
"out": method.output_format,
|
||||
"opt": method.options
|
||||
}
|
||||
```
|
||||
|
||||
## **2.1** - method.description
|
||||
|
||||
The *description* field must be a **string** containing the human-readable description of what the method does.
|
||||
|
||||
## **2.2** - method.permissions
|
||||
|
||||
The *permissions* field must be an array. You can manage **OR** and **AND** permission combinations.
|
||||
|
||||
- **OR** is applied between each **0-depth** array
|
||||
- **AND** is applied between each **1-depth** array
|
||||
|
||||
For instance the following permission `[ ["a","b"], ["c"] ]` means you need the permissions **a** and **b** combined or only the permission **c**.
|
||||
|
||||
## **2.3** - method.parameters
|
||||
|
||||
The *parameters* field must be an object containing each required or optional parameter needed for the implementation.
|
||||
|
||||
```json
|
||||
"parameter.name": {
|
||||
"des": parameter.description,
|
||||
"typ": parameter.checker_type,
|
||||
"opt": parameter.is_optional,
|
||||
"ren": parameter.rename,
|
||||
"def": parameter.default_value,
|
||||
}
|
||||
```
|
||||
|
||||
#### parameter.name
|
||||
|
||||
The *name* field must be a **string** containing variable name that will be asked for the caller.
|
||||
|
||||
Note that you can set any string for **body parameters**, but **GET parameters** must be named `URL#`, where `#` is the index within the URI, beginning with 0.
|
||||
#### parameter.description
|
||||
|
||||
The *description* field must be a **string** containing the human-readable description of what the parameter is or must be.
|
||||
#### parameter.checker_type
|
||||
|
||||
The *checker_type* field must be a **string** corresponding to a `\api\core\Checker` type that will be checked before calling the implementation.
|
||||
|
||||
#### parameter.is_optional
|
||||
|
||||
The *is_optional* field must be a **boolean** set to `true` if the parameter can be ommited. By default, the field is set to `false` so each parameter is required.
|
||||
|
||||
#### parameter.rename
|
||||
|
||||
The *rename* field must be a **string** corresponding to the *variable name* given to the implementation. It is useful for **GET parameters** because they need to be called `URL#`, where `#` is the position in the URI. (cf. [paramter.name](#parametername)))
|
||||
|
||||
If ommited, by default, `parameter.name` will be used.
|
||||
#### parameter.default_value
|
||||
|
||||
The *default_value* field must be of any type according to the *checker_type* field, it will be used only for **optional** parameters when ommited by the caller
|
||||
|
||||
By default, each optional parameter will exist and will be set to `null` to the implementation.
|
||||
|
||||
## **2.4** - method.output_format
|
||||
|
||||
The *output_format* field must have the same format as `method.parameters` but will only be used to generate a documentation or to tell other developers what the method returns if no error occurs.
|
||||
|
||||
## **2.5** - method.options
|
||||
|
||||
The *options* field must be an **object** containing the available options.
|
||||
|
||||
The only option available for now is:
|
||||
|
||||
```json
|
||||
"download": true
|
||||
```
|
||||
|
||||
Your implementation must return 2 fields:
|
||||
- `body` a string containing the file body
|
||||
- `headers` an array containing as an associative array file headers
|
||||
|
||||
If the API is called with HTTP directly, it will not print the **json** response (only on error), but will instead directly return the created file.
|
||||
|
||||
*AJAX:* If called with ajax, you must give the header `HTTP_X_REQUESTED_WITH` set to `XMLHttpRequest`. In that case only, it will return a normal JSON response with the field `link` containing the link to call for downloading the created file. **You must take care of deleting not used files** - there is no such mechanism.
|
||||
|
||||
|
||||
|
||||
# **III.** API Definition
|
||||
|
||||
The documentation consists of a list of URIs each one can contain several HTTP method specifications.
|
||||
|
||||
## **1** - configuration format
|
||||
|
||||
The configuration is a set of `uri` paths that can contain up to 4 method types: **POST**, **DELETE**, **PUT**, **GET** or the `/` field to define sub URIs (recursive).
|
||||
|
||||
For instance the 4 methods directly inside `/`.`uri1` will be triggered when the calling URI is `/uri1`, the ones directly inside `uri2` will be triggered when calling `/uri1/uri2` and so on..
|
||||
|
||||
You can also set full paths if you don't need transitional methods, for instance the path `/`.`uri5`.`/`.`uri6`.`/`.`uri7` will be triggered by the url `/uri5/uri6/uri7`.
|
||||
|
||||
**Example:** The example file loaded with the default configuration can be found [here](./../../src/config/api/3.0/modules.json).
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
"/": {
|
||||
"uri1" : {
|
||||
"GET": method.definition,
|
||||
"POST": method.definition,
|
||||
"PUT": method.definition,
|
||||
"DELETE": method.definition,
|
||||
|
||||
"/": {
|
||||
"uri2": {
|
||||
"GET": method.definition,
|
||||
"POST": method.definition,
|
||||
"PUT": method.definition,
|
||||
"DELETE": method.definition
|
||||
}
|
||||
}
|
||||
},
|
||||
"uri5":
|
||||
"/": {
|
||||
"uri6": {
|
||||
"/": {
|
||||
"uri7": {
|
||||
"GET": method.definition,
|
||||
"POST": method.definition,
|
||||
"PUT": method.definition,
|
||||
"DELETE": method.definition
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: It is possible to trigger the *root uri* (`/`), so you can set methods directly at the root of the JSON file.
|
||||
|
||||
## **2** - method.definition
|
||||
|
||||
```json
|
||||
{
|
||||
"info": method.description,
|
||||
"scope": method.permissions,
|
||||
"in": method.parameters,
|
||||
"out": method.output_format
|
||||
}
|
||||
```
|
||||
|
||||
## **2.1** - method.description
|
||||
|
||||
The *description* field must be a **string** containing the human-readable description of what the method does.
|
||||
|
||||
## **2.2** - method.permissions
|
||||
|
||||
The *permissions* field must be an array. You can manage **OR** and **AND** permission combinations.
|
||||
|
||||
- **OR** is applied between each **0-depth** array
|
||||
- **AND** is applied between each **1-depth** array
|
||||
|
||||
For instance the following permission `[ [a,b], [c] ]` means you need the permissions **a** and **b** combined or only the permission **c**.
|
||||
|
||||
## **2.3** - method.parameters
|
||||
|
||||
The *parameters* field must be an object containing each required or optional parameter needed for the implementation.
|
||||
|
||||
```json
|
||||
"parameter.name": {
|
||||
"info": parameter.description,
|
||||
"type": parameter.checker_type,
|
||||
"name": parameter.rename,
|
||||
"default": parameter.default_value,
|
||||
}
|
||||
```
|
||||
|
||||
#### parameter.name
|
||||
|
||||
The *name* field must be a **string** containing variable name that will be asked for the caller.
|
||||
|
||||
Note that you can set any string for **body parameters**, but you can also catch :
|
||||
|
||||
- **URI** parameters by prefixing your variable name with `URL#` and followed by a number which is the index in the URL (starts with 0). For instance the **first** URI parameter received from `/path/to/controller/some_value` has to be named `URL#0` inside this configuration. It is a good practice to rename these parameters for better access in your code.
|
||||
|
||||
- **GET** parameters by prefixing your variable name with `GET@`. For instance the get parameter **somevar** received from `/host/uri?somevar=some_value` has to be named `GET@somevar` inside this configuration.
|
||||
|
||||
#### parameter.description
|
||||
|
||||
The *description* field must be a **string** containing the human-readable description of what the parameter is or must be.
|
||||
|
||||
#### parameter.checker_type
|
||||
|
||||
The *checker_type* field must be a **string** corresponding to a `\api\core\Checker` type that will be checked before calling the implementation.
|
||||
|
||||
#### parameter.is_optional
|
||||
|
||||
If the parameter is optional and can be ignored by clients, you must prefix _parameter.checker_type_ with a question mark. For instance a number variable will have a type of `number`, if the variable is optional, the type will then be `?number`.
|
||||
|
||||
**Note :** it is recommended to add a default value for optional parameters.
|
||||
|
||||
#### parameter.rename
|
||||
|
||||
The *name* field must be a **string** corresponding to the wanted *variable name* that will be passed to the controller. It is mainly useful for **URI parameters** because their name is not explicit at all.
|
||||
|
||||
If omitted, by default, `parameter.name` will be used.
|
||||
|
||||
#### parameter.default_value
|
||||
|
||||
The *default_value* field must be of compliant to the variable type checker, it will be used only for **optional** parameters when omitted by the client.
|
||||
|
||||
By default, each optional parameter will exist and will be set to `null` to the implementation.
|
||||
|
||||
## **2.4** - method.output_format
|
||||
|
||||
The *output_format* field must have the same format as `method.parameters` but will only be used to generate a documentation or to tell other developers what the method returns if no error occurs. It allows better overview of an API without looking at the code.
|
||||
|
||||
<!-- ## **2.5** - method.options
|
||||
|
||||
The *options* field must be an **object** containing the available options.
|
||||
|
||||
The only option available for now is:
|
||||
|
||||
```json
|
||||
"download": true
|
||||
```
|
||||
|
||||
Your implementation must return 2 fields:
|
||||
|
||||
- `body` a string containing the file body
|
||||
- `headers` an array containing as an associative array file headers
|
||||
|
||||
If the API is called with HTTP directly, it will not print the **json** response (only on error), but will instead directly return the created file.
|
||||
|
||||
*AJAX:* If called with ajax, you must give the header `HTTP_X_REQUESTED_WITH` set to `XMLHttpRequest`. In that case only, it will return a normal JSON response with the field `link` containing the link to call for downloading the created file. **You must take care of deleting not used files** - there is no such mechanism. -->
|
||||
|
||||
|
||||
|
||||
# **IV.** Implementation
|
||||
|
||||
## **1** - middle-wares
|
||||
|
||||
In order to implement your Permission System you have to implement the **interface** `AuthSystem` located in `/build/api/core/AuthSystem`.
|
||||
|
||||
You must register your custom authentification system before each api call.
|
||||
|
||||
For instance, lets suppose your implementation is called `myAuthSystem`.
|
||||
```php
|
||||
\api\core\Request::setAuthSystem(new myAuthSystem);
|
||||
```
|
||||
**Note**: By default the API will try to find `\api\core\AuthSystemDefault`.
|
||||
|
||||
|
||||
## **2** - core implementation
|
||||
|
||||
### classes
|
||||
Each module's implementation is represented as a **file** so as a **class** located in `/build/api/module/`. In order for the autoloader to work, you must name the **file** the same name as the **class**.
|
||||
Also the **namespace** must match, it corresponds to the path (starting at `/api`).
|
||||
|
||||
For instance if you have in your configuration a path called `/uri1/uri2/uri3`, you will create the file `/build/api/module/uri1/uri2/uri3.php`.
|
||||
|
||||
*Specific*: For the root (`/`) path, it will trigger the class `\api\module\root`, so you have to create the file `/build/api/module/root.php`. (cf. [configuration format](#1---configuration-format))
|
||||
|
||||
|
||||
|
||||
### methods
|
||||
Each middle-wares must implement the [driver.Middleware](https://godoc.org/git.xdrm.io/go/aicra/driver#Middleware) interface.
|
||||
|
||||
The `Inspect(http.Request, *[]string)` method gives you the actual http request. And you must edit the string list to add scope elements. After all middle-wares are executed, the final scope is used to check the **method.permission** field to decide whether the controller can be accessed.
|
||||
|
||||
### example
|
||||
|
||||
For instance here, we check if a token is sent inside the **Authorization** HTTP header. The token if valid defines scope permissions.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.xdrm.io/aicra/driver"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// for the API code to export our middle-ware
|
||||
func Export() driver.Middleware { return new(TokenManager) }
|
||||
|
||||
// mockup type to implement the driver.Middleware interface
|
||||
type TokenManager interface{}
|
||||
|
||||
func (tm TokenManager) Inspect(req http.Request, scope *[]string) {
|
||||
token := req.Header.Get("Authorization")
|
||||
if !isTokenValid(token) {
|
||||
return
|
||||
}
|
||||
|
||||
scope = append(scope, getTokenPermissions(token)...)
|
||||
}
|
||||
```
|
||||
|
||||
*Note*: Functions `isTokenValid()` and `getTokenPermissions()` do not exist, it was in order for all to understand the example.
|
||||
|
||||
|
||||
# **V.** Type Checker
|
||||
|
||||
Each type checker checks the parameter values according to the type given in the api definition.
|
||||
|
||||
The default types below are available in the default package.
|
||||
To add a new type, just open the file `/build/api/Checker.php` and add an entry in the `switch` statement.
|
||||
|
||||
## **1** - Default types
|
||||
|
||||
**Warning :** All received values are extracted using JSON format if possible, else values are considered raw strings.
|
||||
|
||||
- `2`, `-3.2` are extracted as floats
|
||||
- `true` and `false` are stored as booleans
|
||||
- `null` is stored as null
|
||||
- `[x, y, z]` is stored as an array containing **x**, **y**, and **z** that can be themselves JSON-decoded if possible.
|
||||
- `{ "a": x }` is stored as a map containing **x** at the key "a", **x** can be itself JSON-decoded if possible.
|
||||
- `"some string"` is stored as a string
|
||||
- `some string` here, the decoding will fail (it is no valid JSON) so it will be stored as a string
|
||||
|
||||
|Type|Example|Description|
|
||||
|---|---|---|
|
||||
|`any`|`[9,"a"]`, `"a"`|Any data (can be simple or complex)|
|
||||
|`id`|`10`, `"23"`|Positive integer number|
|
||||
|`int`|`-10`, `"23"`|Any integer number|
|
||||
|`float`|`-10.2`, `"23.5"`|Any float|
|
||||
|`text`|`"Hello!"`|String that can be of any length (even empty)|
|
||||
|`digest(L)`|`"4612473aa81f93a878..."`|String with a length of `L`, containing only hexadecimal lowercase characters.|
|
||||
|`mail`|`"a.b@c.def"`|Valid email address|
|
||||
|`array`|`[]`, `[1, 3]`|Any array|
|
||||
|`bool`|`true`, `false`|Boolean|
|
||||
|`varchar(a,b)`|`"Hello!"`|String with a length between `a` and `b` (included)|
|
||||
|
||||
## **2** - Complex types
|
||||
|
||||
|Type|Sub-Type|Description|
|
||||
|---|---|---|
|
||||
|`array<a>`|`a`|Array containing only entries matching the type `a`|
|
||||
|`FILE`|_a raw file send in `multipart/form-data`|A raw file sent by `multipart/form-data`|
|
||||
|
||||
> **Note:** It is possible to chain `array` type as many as needed.
|
||||
|
||||
**Ex.:** `array<array<id>>` - Will only match an array containing arrays that only contains `id` entries.
|
||||
|
||||
|
||||
|
||||
# **VI.** Documentation
|
||||
|
||||
With the *all-in-config* method, we can generate a consistent documentation or other documents from the `/config/modules.json` file.
|
||||
|
||||
## **1** - API accessible documentation
|
||||
|
||||
You can request the API for information about the current URI by using the `OPTIONS` HTTP method.
|
||||
|
||||
|
||||
====
|
||||
|
||||
|
||||
# **I.** Simple request
|
||||
## **1** - URL
|
||||
|
||||
### format
|
||||
The `uri` format is as defined: `{base}/{path}/{GET_parameters}`, where
|
||||
- `{base}` is the server's *API* base uri (ex: `https://example.com/api/v1` or `https://api.exampl.com`)
|
||||
- `{path}` is the effective path you want to access (ex: `article/author`)
|
||||
- `{GET_parameters}` is a set of slash-separated values (ex: `val0/val1/val2//val4`)
|
||||
|
||||
*Note:* GET parameters are not used as usual (`?var1=val1&var2=val2...`), instead the position in the URL gives them an implicit name which is `URL#`, where `#` is the index in the uri (beginning with 0).
|
||||
|
||||
### example 1
|
||||
|
||||
If you want to edit an article with the server's REST API, it could be defined as following:
|
||||
|
||||
```yaml
|
||||
http: PUT
|
||||
path: article/{id_article}
|
||||
input:
|
||||
body: new content of the article
|
||||
output:
|
||||
updated: the updated article data
|
||||
```
|
||||
|
||||
Let's take the example where you want to update the article which id is **23** and set its body to "**blabla new content**"
|
||||
|
||||
`HTTP REQUEST`
|
||||
```
|
||||
PUT article/23 HTTP/1.0
|
||||
|
||||
body=blabla+new+content
|
||||
```
|
||||
|
||||
|
||||
`HTTP RESPONSE`
|
||||
```
|
||||
HTTP/1.0 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"error": 0,
|
||||
"ErrorDescription": "all right",
|
||||
|
||||
"updated": {
|
||||
"id_article": 23,
|
||||
"title": "article 23",
|
||||
"body": "blabla new content"
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### example 2
|
||||
|
||||
If you want to get a specific article line, the request could be defined as following
|
||||
|
||||
```yaml
|
||||
http: GET
|
||||
path: article/line/{id_article}/{no_line}
|
||||
input: -
|
||||
output:
|
||||
articles: the list of matching lines
|
||||
```
|
||||
|
||||
Let's take the example where you want to get **all articles** because `id_article` is set to optional, but you only want the first line of each so you have to give only the second parameter set to `1` (first line).
|
||||
|
||||
*Solution:* The position in the `uri` where `id_article` must be, have to be left empty: it will result of 2 slashes (`//`).
|
||||
|
||||
`HTTP REQUEST`
|
||||
```
|
||||
GET article/line//1 HTTP/1.0
|
||||
```
|
||||
|
||||
|
||||
`HTTP RESPONSE`
|
||||
```
|
||||
HTTP/1.0 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"error": 0,
|
||||
"ErrorDescription": "all right",
|
||||
|
||||
"articles": [
|
||||
{
|
||||
"id_article": 23,
|
||||
"line": [ 0: "blabla new content"
|
||||
},{
|
||||
"id_article": 25,
|
||||
"line": [ 0: "some article"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
```
|
Loading…
Reference in New Issue