REST¶
Em muitos casos queremos expor uma API para externos integrarem e nestes casos o formato REST é um padrão universalmente entendido e aceito, com boas ferramentas em todas as plataformas e linguagens. No sdkgen é possível utilizar a annotation @rest
para criar endpoints vinculados a suas funções.
Para criar uma função REST, inicie criando uma função normal do sdkgen, utilize quaisquer argumentos, tipo de retorno e nome que fizer sentido no seu caso de uso. Por exemplo:
fn getPostsByUser(userId: uuid, since: datetime?, until: datetime?): Post[]
Então adicione a annotation @rest
. Ela deve definir obrigatoriamente um método e uma path, podendo incluir detalhamento adicional para os headers e body. Neste caso:
@rest GET /users/{userId}/posts?{since}&{until}
fn getPostsByUser(userId: uuid, since: datetime?, until: datetime?): Post[]
Uma vez que exista ao menos 1 endpoint REST na sua aplicação, um Swagger UI será criado automaticamente com a descrição do endpoint e documentação através de @description
e @arg
. Para entender mais sobre como configurar este comportamento, leia a página sobre um Servidor em Node.js.
Caso queira que sua função esteja disponível exclusivamente como REST utilize @hidden
.
Anatomia do @rest
¶
@rest MÉTODO /caminho/do/recurso/com/{arg1}/e/{arg2}?{argNaQuery1}&{argNaQuery2} [header Nome: {header}] [body {argBody}]
Cada um dos elementos acima serão explicados nas próximas sessões.
Método¶
Os seguintes métodos HTTP são suportados: GET
, POST
, PUT
, DELETE
e PATCH
. Alguns exemplos:
@rest GET /status
fn getStatus(): bool
@rest DELETE /product/{id}
fn deleteProduct(id: uuid)
@rest POST /product [body {newProduct}]
fn createProduct(newProduct: Product): Product
Caminho¶
Logo após o método o segundo elemento obrigatório do @rest
é o caminho (ou "endpoint"). Este caminho deve começar com uma "/" e utilizar caracteres permitidos em uma URL. Neste caminho podem ser incluídos alguns segmentos dinâmicos vinculados aos argumentos da função, como /product/{id}
onde id
é um argumento. O caminho pode incluir múltiplos destes argumentos.
Para um argumento poder ser utilizado dentro de um caminho ele deve ter um dos seguintes tipos: bool
, int
, uint
, bigint
, float
, string
, date
, datetime
, money
, decimal
, cpf
, cnpj
, uuid
, hex
, base64
ou ser um enum. Note que o tipo não pode ser nulável.
Por exemplo:
@rest GET /stores/{storeId}/products/{id}
fn getProduct(storeId: uint, id: uint): Product?
Neste caso uma chamada por GET /stores/3/products/47
será similar a chamar getProduct(3, 47)
.
Argumentos também podem ser recebidos como parte da query. A query é a parte da URL que vem depois do ?
, por exemplo: GET /orders?state=open
. Para estes argumentos especifique confirme o exemplo abaixo:
@rest GET /stores/{storeId}/orders?{state}&{date}
fn getOrders(storeId: uint, state: State?, date: date?): Order[]
Neste caso a ordem dos argumentos não será levada em consideração e os tipos aceitos são os mesmos que podem aparecer no caminho, com a exceção de que eles podem ser nuláveis. Neste caso é comum (mas não obrigatório) que os argumentos sejam de fato nuláveis.
Headers¶
Em uma API REST pode ser necessário receber argumentos através de headers, especialmente em caso de autenticação. Para receber um header escreva conforme o seguinte exemplo:
@rest GET /me [header Authorization: {token}]
fn getCurrentUser(token: base64): User
Os tipos permitidos são os mesmos listados para o caminho, podendo ser opcionais: bool
, int
, uint
, bigint
, float
, string
, date
, datetime
, money
, decimal
, cpf
, cnpj
, uuid
, hex
, base64
ou ser um enum. Múltiplos headers podem ser especificados.
Body¶
Geralmente os métodos POST
, PUT
e PATCH
esperam que um body seja enviado na requisição, embora um body possa ser enviado em qualquer método. No sdkgen você pode encaminhar este body para um dos argumentos da função:
type NewProduct {
name: string
}
type Product {
id: uuid
...NewProduct
}
@rest POST /products [body {newProduct}]
fn createProduct(newProduct: NewProduct): Product
Apenas um argumento pode ser o body da requisição REST.
Se o Content-Type
tiver sido passado como application/json
, então o body será lido conforme as regras de codificação e decodificação padrões do sdkgen. Caso contrário o comportamento é levemente diferente a depender do tipo do argumento:
Tipo | Comportamento |
---|---|
qualquer nulável | O argumento será considerado null caso o body esteja em branco. |
bool |
É esperado que o body seja literalmente true ou false . |
int , uint , bigint ou float |
O body seve conter apenas o número, sem aspas. |
string , date , datetime , money , decimal , cpf , cnpj , uuid , hex ou base64 |
O conteúdo do body será interpretado diretamente. Não deve estar entre aspas. |
xml , bytes ou html |
Similar ao caso acima. O conteúdo do body será passado tal como está. |
json |
Um objeto JSON arbitrário será esperado. |
qualquer enum | O body deverá ser um dos valores possíveis do enum, sem aspas. |
qualquer tipo composto | O body será lido conforme as regras de codificação e decodificação padrões do sdkgen. |
Retorno¶
A sua função pode retornar qualquer um dos tipos suportados pelo sdkgen. No entanto o comportamento exato irá variar a depender do tipo.
Código de Status HTTP¶
Situação | Código de Status |
---|---|
Sucesso, mas com retorno null ou sem retorno e com método GET | 404 Not Found |
Sucesso, mas com retorno null ou sem retorno e outros métodos | 204 No Content |
Sucesso, com qualquer outro tipo de retorno | 200 OK |
Erro lançado dentro da função diferente de Fatal | 400 Bad Request |
Erro Fatal lançado dentro da função | 500 Internal Server Error |
Erro não especificado durante o processamento da requisição | 500 Internal Server Error |
Codificação do corpo da resposta¶
Se a requisição tiver passado o header Accept
como application/json
, então o body será gerado conforme as regras de codificação e decodificação padrões do sdkgen. Caso contrário o comportamento será dependente do tipo de retorno.
Tipo | Comportamento |
---|---|
bool , int , uint , float , string , date , datetime , money , bigint , decimal , cpf , cnpj , uuid , hex ou base64 |
Valor será posto diretamente no body, sem aspas adicionais. O Content-Type será text/plain . |
html |
Valor será posto diretamente no body, sem aspas adicionais. O Content-Type será text/html . |
xml |
Valor será posto diretamente no body, sem aspas adicionais. O Content-Type será text/xml . |
bytes |
Os bytes serão entregues diretamente, ideal para oferecer download de arquivos. O Content-Type será detectado dinamicamente a depender do conteúdo. Caso não seja possível detectar, será application/octet-stream . |
outros tipos | O body será gerado conforme as regras de codificação e decodificação padrões do sdkgen. |